/**
 *
 * Ajax Controller
 * Created ON 07/10/2010
 *
 * @package mootools-extends
 * @version 0.2
 * @author �ngel Luis Quesada Nieto http://alquesada.com
 * @author Jose Villalobos Cort�s http://josevillalobos.es
 * @author Victor Ant�n Sanchez
 * @author Sim�n Mart�n Contreras http://ondasaudibles.es
 * @copyright Copyright (c) 2010 �ngel Luis Quesada Nieto. (http://alquesada.com)
 * @license http://www.gnu.org/licenses/lgpl.html GNU LESSER GENERAL PUBLIC LICENSE
 * @todo change check Page via DOM by check through the array
 *
 * LICENSE
 * This source file is subject to the GNU LESSER GENERAL PUBLIC LICENSE that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/lgpl.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to angel.quesada@kubide.es so we can send you a copy immediately.
 *
 */

var ajaxizable = new Class({

	Implements: [Options, Events],


	options: {

		watcher :
		{
			hostname : location.hostname,
			pathname : "",
			actualHash : false,
			tempHash : false,
			start : true,
			periodical : 1000,
			update : "",
			baseCheck : "",
			obviate :
			{
				'class' : "noAjax",
				rel : "noAjax"
			},
			onRequest : function(){},
			onComplete : function(){},
			onCancel : function(){},
			onSuccess : function(){},
			onFailure : function(){},
			onException : function(){}
		},
		rQueue :
		{
			use : true,
			obj : null,
			base : "req_"
		},

		request :
		{
			ajaxFile : '/index.ajax.php?ajax=',
			method : "post",
			evalScripts : true,
//			evalResponse : true //no se la diferenc�a con evalScripts pero el anterior funciona.
			noCache : true,
			update: null,
			append: null,
			onRequest : function(){},
			onComplete : function(){},
			onCancel : function(){},
			onSuccess : function(){},
			onFailure : function(){},
			onException : function(){},
			replace : false, // remplazar el hash con el goto
			addAjaxNav : false, //a�adir navegaci�n por AJAX
			url : null, // la nueva url para hacer el goto
			waiter:
			{
				use : true, // true si quieres que haga "espera" en la llamada
				baseHref : "/assets/", // (string) url prefix for the img src (see below); defaults to 'http://www.cnet.com/html/rb/assets/global/waiter/'
				img :
				{
					styles :
					{
						width:"auto",
						height:"auto"
					}
				}, // (object or false) options for the image (see below); if set to false no image will be injected.
				containerPosition : {}, // (object) options passed to Element:setPosition for the container of the message; relativeTo is set to the target above automatically (but can be overwritten).
				containerProps : {}, // (object) attributes for the container div that contains the (optional) message and the image
				msg : false, // (mixed, optional) message placed above the spinner image (as in "Please wait..."). Can be a string or an element.
				msgProps : {}, // (object) attributes for the container of the (optional) message
				layer : {}, //(object) options for the overlay layer (see below)
				fxOptions : {}, // (object) options passed to the effects used to transition the overlay and the image opacity
				useIframeShim : true, // (boolean) true: an IframeShim will be used underneath the modal layer; false: no shim is used; defaults to true
				iframeShimOptions : {}, // (object) options passed to IframeShim
				delay : 1000 // 1second
			},
			toSend :
			{
				url : "",
				type : "",
				method : null,
				debug : false

			},
			sticky:
			{


			},

			form:
			{

			}
		}
	},


	initialize: function(options)
	{
		// set options
		this.setOptions(options);
		if (this.options.rQueue.use)
			this.options.rQueue.obj = new Request.Queue();
		if (this.options.watcher.start)
		{
			this.watcherInitialize(this.options.watcher.baseChek);
			this.watcher.periodical(this.options.watcher.periodical, this);
		}
	},

/* NavController Zone*/

	/* The init of the watcher */
	watcherInitialize: function()
	{
		this.watcherAddAjaxNav();
//		this.options.watcher.onSuccess();
	},

	/* The watcher's options */
	watcherOptions: function()
	{
		var options = {
			method: "get",
			onRequest : this.options.watcher.onRequest,
			onComplete : this.options.watcher.onComplete,
			onCancel : this.options.watcher.onCancel,
			onSuccess : this.options.watcher.onSuccess,
			onFailure : this.options.watcher.onFailure,
			onException : this.options.watcher.onException,
			replace : true,
			toSend :
			{
				type : "navigation"
			}
		};
		return options;
	},

	/* Set all innerlinks as AJAX */
	watcherAddAjaxNav: function(root)
	{

		root = $chk(root) ?
			($type(root) == "element" ? root : document.id(root) )
			: document;

		var match = 'http://'+this.options.watcher.hostname+this.options.watcher.pathname;

		root.getElements('a').each(function(el)
		{
			//Pasa el test y no lo obviamos
			if ( el.href.test(match)
				&& !this.watcherObviate(el) )
			{
				el.removeEvents('click');
				el.addEvent('click', function(event)
				{
					event.preventDefault();
					this.gotoUpdate(el.href, this.options.watcher.update, this.watcherOptions());
				}.bind(this));
			}
		}.bind(this));
	},

	/* Check if the inline link must be obviate */
	watcherObviate: function(el)
	{
		for(key in this.options.watcher.obviate)
			if (el.get(key) && el.get(key).test(this.options.watcher.obviate[key]) )
				return true;

		return false;
	},

	/* watcher that control the ajaxNavigation */
	watcher: function()
	{
		switch(true)
		{
/*		case (location.pathname != this.options.watcher.pathname):
			// We aren't in the correct base URL
			var href = location.href;
			var match = 'http://'+this.options.watcher.hostname+this.options.watcher.pathname;

//			alert(location.pathname + " * " + this.options.watcher.pathname+ "-> "+href.replace(match,match+"#"));
			this.options.watcher.tempHash = href.replace(match,"");
			alert (this.options.watcher.tempHash);
//			location.href = href.replace(match,match+"#"); // por compatibilidad con IE
			break;
*/
		case (location.hash == "#/user/logout/"):
			/* especial internal case (hardcoded, this must be a extensible function) */
			location.hash = '#';
			break;
		case (location.hash != this.options.watcher.actualHash ):

			if (location.hash == this.options.watcher.tempHash)
				return true;

			this.options.watcher.tempHash = location.hash;
			var url = location.hash.replace("#","");
			this.gotoUpdate(url, this.options.watcher.update, this.watcherOptions());
			break;
		}
	},



/* AjaxComunication Zone*/
	_goto: function(options)
	{

		var element = options.element ? options.element :
			(options.update ? options.update : options.append);

		if (options.waiter.use){
			document.getElements('.waitingDiv').destroy();
			var waiterExample = new Waiter(element, options.waiter);
		}

		if (!$chk(options.url) && this.options.watcher.actualHash)
			options.url = options.toSend.url = rawurlencode(this.options.watcher.actualHash.replace("#", ""));

		if (!$type(options.validate))
			options.validate =  true;
		
		var url = (options.ajaxFile ?
				options.ajaxFile:
				options.url)
				+ JSON.encode(options.toSend) ;
		
		var reqOpts =
		{
			url: url,
			method: options.method,
			evalScripts: options.evalScripts,
			noCache : options.noCache,
			onRequest : function()
			{
				if (options.waiter.use)
					waiterExample.start();

				options.onRequest(options);
			},
			onComplete : function(responseTree, responseElements, responseHTML, responseJavaScript)
			{
				options.onComplete(options);
			},
			onCancel : function()
			{
				options.onCancel(options);
				if (options.waiter.use)
					waiterExample.stop.delay(options.waiter.delay, waiterExample);

			},
			onSuccess : function(responseTree, responseElements, responseHTML, responseJavaScript)
			{
				if (options.replace && options.url)
				{
					var href = location.href;
					var match = 'http://'+this.options.watcher.hostname+this.options.watcher.pathname;
				 	location.hash = '#'+options.url.replace(match,''); // a�adimos el hash solo, ya venga toda la URL o solo el hash
				 	this.options.watcher.tempHash = this.options.watcher.actualHash = location.hash;
				}

				if (options.addAjaxNav)
				{
					$console("AddAjax al element "+element);
					this.watcherAddAjaxNav(element);
				}
				options.onSuccess(options, responseTree, responseElements, responseHTML, responseJavaScript);
				
				if (options.waiter.use)
					waiterExample.stop.delay(options.waiter.delay, waiterExample);

			}.bind(this),
			onFailure : function()
			{
				options.onFailure(options);
//				alert ("Algo salio mal, prueba de nuevo");

				if (options.waiter.use)
					waiterExample.stop.delay(options.waiter.delay, waiterExample);
			},
			onException : function(xhr)
			{
				options.onException(options, xhr);
				if (options.waiter.use)
					waiterExample.stop.delay(options.waiter.delay, waiterExample);
			}
		};

		var send = false;
		switch (options.toSend.type){
			case "formUpdate" :
				var mergedOpts = $merge(this.options.form, options);
				
				mergedOpts.onSuccess = function(){};
				mergedOpts.requestOptions = $merge (reqOpts, mergedOpts.requestOptions);
				$console('cargamos el metodo fUpdate de ' + mergedOpts.form + " " +mergedOpts.element);

				if (mergedOpts.validate){
					new Form.Validator.Tips(mergedOpts.form, {
					    pointyTipOptions: {
					        point: 12
					    },
					    onFormValidate: function(passed, myform, event) {
					        if (passed){
					        	var req = new Form.Request(mergedOpts.form, mergedOpts.element, mergedOpts);
					        	req.send();
					        }
					        event.preventDefault();
					    }
					});
				}
				else{
					
					alert (mergedOpts.onSuccess);
					var req = new Form.Request(mergedOpts.form, mergedOpts.element, mergedOpts);
				}
				
				break;
			case "formAppend" :
				var mergeOpts = $merge(this.options.form, options);
				//mergeOpts.onSuccess = function(){};
				mergeOpts.requestOptions = $merge (reqOpts, mergeOpts.requestOptions);
				$console('cargamos el metodo fAppend de ' + mergeOpts.form);
				var req = new Form.Request.Append(mergeOpts.form, mergeOpts.element, mergeOpts);
				break;
			default:
//				$console('ejecutamos el metodo Request.HTML');
				send = true;
				if ($chk(options.update))
				{
					if ($type(options.update) === "string")
						reqOpts.update = document.id(options.update);
					else
						reqOpts.update = options.update;
				}
					
				if ($chk(options.append))
					reqOpts.append = options.append;

				var req = new Request.HTML(reqOpts);
		};


		if (this.options.rQueue.use && req)
		{
			var name = options.name ? options.queueName : this.options.rQueue.base+$time();
			this.options.rQueue.obj.addRequest(name, req);
		}

		try{ 
			if (send && req)
				req.send();
		} catch(e){
			$console('fallo el AJAX ' + e);
		}		
	},


	gotoUpdate: function(url, element, options) {

//		url = rawurlencode(url);
		var toSend =
		{
			url : rawurlencode(url),
			type : "update"
		}

		if (!$chk(options))
			options = {};

		options.toSend = $merge(toSend, options.toSend);
		
		var mergedOpts = $merge(this.options.request, options);
		mergedOpts.update = element;
		mergedOpts.url = url;
		this._goto(mergedOpts);
	},

	gotoAppend: function(url, element, options) {
		
		var toSend =
		{
			url : rawurlencode(url),
			type : "append"
		}

		if (!$chk(options))
			options = {};

		options.toSend = $merge(toSend, options.toSend);

		var mergedOpts = $merge(this.options.request, options);
		mergedOpts.append = element;
		mergedOpts.url = url;

		this._goto(mergedOpts);
	},

	formUpdate: function(form, element, options)
	{
		var toSend =
		{
			type : "formUpdate",
			url : rawurlencode(form.get("action"))
		};

		if (!$chk(options))
			options = {};

		options.toSend = $merge(toSend, options.toSend);

		var mergedOpts = $merge(this.options.request, options);
		mergedOpts.element = element;
		mergedOpts.form = form;
		mergedOpts.url = form.get("action");
		this._goto(mergedOpts);
	},

	formAppend: function(form, element, options)
	{
		var toSend =
		{
			type : "formAppend"
		}

		if (!$chk(options))
			options = {};

		options.toSend = $merge(toSend, options.toSend);

		var mergedOpts = $merge(this.options.request, options);
		mergedOpts.element = element;
		mergedOpts.form = form;

		this._goto(mergedOpts);
	},


	getScript: function(src, func,  options)
	{
		var baseOpts = {id : "script_"+src, onload:function(){} };
		if (!$chk(options))
			options = {};
		var mergedOpts = $merge(baseOpts, options);
		
		if ($type(func) == "function")
			mergedOpts.onload = func;
//		if (document.id(mergedOpts.id) && !mergedOpts.force)
//		{	//Si existe el script, ejecutamos la funcion y listo
			$console("el script "+src+" esta ya, ejecutamos la funcion");
			mergedOpts.onload();
			return true;
//		}
//
//		var myScript = new Asset.javascript(src, mergedOpts);
	},

	getStyles: function(src, options) {
		var baseOpts = {
			id : "style_"+src,
			rel : "stylesheet",
			href : src
		}
		var mergedOpts = $merge(baseOpts, options);
		if (document.id(mergedOpts.id) && !mergedOpts.force)
			return false;

		var myCSS = new Asset.css(src, options);
	},

/*
	getScript: function(src, func,  options) {
		var baseOpts = {id : "script_"+src, src : src};
		if (!$chk(options))
			options = {};

		var mergedOpts = $merge(baseOpts, options);
		if (document.id(mergedOpts.id) && !mergedOpts.force)
		{	//Si existe el script, ejecutamos la funcion y listo
			if ($type(func) == "function")
				func();
			return true;
		}

		var element = new Element('script', mergedOpts);

		//Si existe funci�n nos traemos el c�digo primero para ejecutarla bien
		if ($type(func) == "function")
		{
			var onSuccess = function()
			{
				func();
				if (!document.id(mergedOpts.id) || mergedOpts.force)
					document.head.adopt(element);
			}
			var reqOpts =
			{
				onSuccess : onSuccess,
				addAjaxNav : false,
				replace : false,
				waiter :
				{
					use : false,
				},
				toSend :
				{
					type : "script",
				}
			}
			this.gotoUpdate(src, null, reqOpts);
		}else
			document.head.adopt(element);
	},

	getStyles: function(src, options) {
		var baseOpts = {
			id : "style_"+src,
			rel : "stylesheet",
			href : src
		getStickyPoint}
		var mergedOpts = $merge(baseOpts, options);
		if (document.id(mergedOpts.id) && !mergedOpts.force)
			return false;

		var element = new Element('link', mergedOpts);
		document.head.adopt(element);
	},
*/

	getStickyPoint: function(url, options)
	{
		if (!$chk(options))
			options = {};

		var aux = options.onSuccess;

		//Hacemos el request
		options.onSuccess = function(options, responseTree, responseElements, responseHTML, responseJavaScript)
		{

			var body = options.sticky.body ? options.sticky.body : responseHTML;
			var sticky = new StickyWin.PointyTip(options.sticky.caption, body, options.sticky);

			if (options.addAjaxNav)
			{
				$console("AddAjax al sticky "+sticky);
				this.watcherAddAjaxNav(sticky);
			}
			

			if ($type (aux) == "function")
				aux(options, responseTree, responseElements, responseHTML, responseJavaScript);
		}.bind(this);

		var stickyOpts =
		{
			replace : false,
			addAjaxNav : false,
			toSend :
			{
				url : url,
				type : "sticky"
			}
		}

		var mergedOpts = $merge(this.options.request, stickyOpts, options);
		mergedOpts.url = url;

		this._goto(mergedOpts);
	}
});

/*var relPagination = new Class({
    Extends: Pagination,

	_getContent: function(i) {
		domElement = document.id(this.options.hash+i)
		domElement.set("html", "Content -> "+i);
	}

});*/


function rawurlencode( str ) {
    // URL-encodes string
    //
    // version: 901.1411
    // discuss at: http://phpjs.org/functions/rawurlencode
    // +   original by: Brett Zamir
    // *     example 1: rawurlencode('Kevin van Zonneveld!');
    // *     returns 1: 'Kevin van Zonneveld%21'
    // *     example 2: rawurlencode('http://kevin.vanzonneveld.net/');
    // *     returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
    // *     example 3: rawurlencode('http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a');
    // *     returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
	if (!$chk(str) || $empty(str))
		return "";
$console("continuamos con "+str);
    var histogram = {}, tmp_arr = [];
    var ret = str.toString();

    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };

    // The histogram is identical to the one in urldecode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A'; 
    histogram['~']   = '%7E';
    histogram['!']   = '%21';

//    histogram['=']   = '--';
    
    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
    ret = encodeURIComponent(ret);

    // Restore spaces, converted by encodeURIComponent which is not rawurlencode compatible
    ret = replacer('%20', ' ', ret); // Custom replace. No regexing

    for (var search in histogram) {
        replace = histogram[search];
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
    alert (ret);
    return ret;
}

