//  Open Social Ajax wrapper, version 0.1
//  (c) 2007 Chris Chabot
//
//  This class is freely distributable under the terms of an MIT-style license.
//  For details, see the project's website:
//  http://www.chabotc.com/generic/third-step-into-the-open-social-world/

// Open Social containers do not allow direct ajax calls (since they are cross site)
// also the hosting social site preferes to proxy / cache (for performance and security reasons)
// So our normal Ajax.Request is pretty useless. This makes a new Ajax.Request which
// uses the _IG_FetchContent call and makes it look like our old Ajax.Request
// All this to make us feel more at home and snuggly in our social container :-)

// Include this script AFTER including prototype.js


Ajax.Request.prototype = {
	initialize: function(url, options) {
		// we unfortunaly only support a very limited amount of options:
		// 	method (get anyhow otherwise _method=post will be send as get param)
		// 	evalJS : contrary to prototype, we default to false since we cant use http headers to detect js
		// 	onComplete/Success : recieves a faked transport, which has a transport.responseText (and never JSON or XML)
		// 	onError : a faked 2 second timeout, since IG_FetchContent doesnt do errors it seems ... duh ...
		// we also fake post by doing a GET and adding the postBody to the get URL, and adding &_method=post to it
		// all pretty ugly hacks, but the best i can make of it in our limited IG container posibilities
		this.options = {
			method:   'get',
			evalJS:   false,
			evalJSON: false
		};
		Object.extend(this.options, options || {});
		// One of the things i dislike about _IG_FetchContent is that it doesn't deliver error's
		// it just never calls the onComplete.. So we'll fake an onError with a timeout, this is very dirty
		// though since if a webserver takes 2 seconds, it will be considered an error
		// and onComplete could be triggered AFTER onError, warning though, never been tested really well
		if (this.options.onError) {
			var onError    = this.options.onError.bind(this);
			this.errorTimer = window.setTimeout(function() {
				return onError;
			}, 2000);
		} else {
			this.errorTimer = false;
		}

		this.transport      = false;
		this.options.method = this.options.method.toLowerCase();
		if (Object.isString(this.options.parameters)) {
			this.options.parameters = this.options.parameters.toQueryParams();
		}
		this.request(url);
	},

	request: function(url) {
		this.url    = url;
		this.method = this.options.method;
		var params  = Object.clone(this.options.parameters);
		// method HAS to be get, only method supported by _IG_FetchContent
		if (this.method != 'get') {
			params['_method'] = this.method;
			this.method = 'get';
		}
		this.parameters = params;
		// always rewrite params to the GET, since there is no post ...
		if (params = Object.toQueryString(params)) {
			this.url += (this.url.include('?') ? '&' : '?') + params;
		}
		// fake a post by parsing content in the get string (size limited though)
		if (params['_method'] == 'post' && this.options.postBody) {
			this.url += (this.url.include('?') ? '&' : '?') + this.options.postBody;
		}
		if (this.options.onCreate) {
			this.options.onCreate();
		}
		// Invoke the actual iGadget ajax call
		_IG_FetchContent(url, this.onComplete.bindAsEventListener(this));
	},

	onComplete: function(response) {
		this.transport = { responseText : response, responseJSON : null };
		if (this.options.evalJS || this.options.evalJS == 'force') {
			this.evalResponse();
		}
		if (this.options.evalJSON) {
			this.transport.responseJSON = this.transport.responseText.evalJSON(true);
		}
		if (this.options.onComplete) this.options.onComplete(this.transport);
		if (this.options.onSuccess)  this.options.onSuccess(this.transport);
	},
	
	evalResponse: function() {
		try {
			return eval((this.transport.responseText || '').unfilterJSON());
		} catch (e) {
			//this.dispatchException(e);
		}
	}
}

Ajax.Updater = Class.create(Ajax.Request, {
	initialize: function($super, container, url, options) {
		this.container = {
			success: (container.success || container),
			failure: (container.failure || (container.success ? null : container))
		};
		options = options || {};
		var onComplete = options.onComplete;
		options.onComplete = (function(response, param) {
			this.updateContent(response.responseText);
			if (Object.isFunction(onComplete)) onComplete(response, param);
		}).bind(this);
		$super(url, options);
	},

	updateContent: function(responseText) {
		var receiver = this.container[this.success() ? 'success' : 'failure'],
		options      = this.options;
		if (!options.evalScripts) {
			responseText = responseText.stripScripts();
		}
		if (receiver = $(receiver)) {
			if (options.insertion) {
				if (Object.isString(options.insertion)) {
					var insertion = { }; insertion[options.insertion] = responseText;
					receiver.insert(insertion);
				} else {
					options.insertion(receiver, responseText);
				}
			} else {
				receiver.update(responseText);
			}
		}
		if (this.success()) {
			if (this.onComplete) this.onComplete.bind(this).defer();
		}
	},
	
	success: function() {
		return (this.transport);
	}
});
