var SL = SL || {};

/**
 * == Utility ==
 * Utility functions
 * 
 * __All utility functions shall start with an underscrore (`_`).__
**/

/** section: Utility
 * SL
 * The SL Namespace
**/

/** section: Utility
 * SL._fetchEventUrl(event) -> String
 * 
 * Trys to find the URL to use for an Ajax/Json call
**/
SL._fetchEventUrl = function (evt, defaultValue) {
	var el = $(evt.target);
	var url = el.slFetchUrl();
//	if (!url) {
//		// TODO: error handling:
//		// throw exception?
//		// silently print on console, if there is one?
//		// provide user feedback, raising an ooops-dialog?
//		return '';
//	}
	return url || defaultValue;
};

/** section: Utility
 * SL.submitForm(event) -> void
 *     - event (Event): an event of an a href click
 *     - url (String): optional given url where to post the form, default is the event.target.href
 *     - formId (String): optional given form id, it makes sense if you have different postSubmits on one site, default id is hiddenPostSubmitForm 
 * 
 * with this function you can p.e. make a post submit with an a href link without creating a form in your html code, it will be inject in dom
**/
SL.submitForm = function(event, url, formId) {

	event = new Event(event).stop();
	var formId = formId ? formId : 'hiddenPostSubmitForm';
	var url    = url ? url : event.target.href;

	var form = new Element('form', {
		action:  url,
		method:  'post',
		enctype: 'multipart/form-data',
		id:      formId
	});
	
	form.inject(document.body, 'top')
	
	$(formId).submit();

};




/** section: Utility
 * SL.disableEnableForm(form, enable) -> void
 *     - form (String|Element): The Id of an form element, or the form element we want to enable/disable
 *     - enable (Bool): false for disable, and true for enable the form
 *     
 * Enable or disable all input, textarea and select elements of an given form
**/
SL.disableEnableForm = function(form, enable) {
	if($defined($(form))) {
		var formObj = $(form);
	} else if($defined(form)) {
		var formObj = form;
	} else {
		return;
	}
	formObj.getElements('input,select,textarea').each(function(element) {
		element.disabled = enable ? false : true;
	});
};


/** section: Utility
 * SL.disableForm(event, form) -> void
 *     - form (String|Element): The Id of an form element, or the form element we want to disable
 *     - event (Event): A link's click event
 *     
 * Disable all input, textarea and select elements of an given form, see also [SL.disableEnableForm]
**/
SL.disableForm = function(event, form) {
	if(event) { new Event(event).stop(); }
	SL.disableEnableForm(form, false);
}


/** section: Utility
 * SL.enableForm(event, form) -> void
 *     - form (String|Element): The Id of an form element, or the form element we want to enable
 *     - event (Event): A link's click event
 *     
 * Enable all input, textarea and select elements of an given form, see also [SL.disableEnableForm]
**/
SL.enableForm = function(event, form) {
	if(event) { new Event(event).stop(); }
	SL.disableEnableForm(form, true);
}


/** section: Utility
 * SL._fetchStaticBaseHref() -> String
 * 
 * Tries to find the base URL to use for static content
**/
SL._fetchStaticBaseHref = function () {
	if(!SL.Registry.has('sl.impl.staticBaseHref')) {
		SL.Registry.add('sl.impl.staticBaseHref', $('baseHrefStatic').get('href'));
	}
	return SL.Registry.get('sl.impl.staticBaseHref');
}


/**
 * == Base ==
 * The Base Section
 * 
 * Basics for switching or loading content.
**/

/** section: Base
 * SL
 * The SL Namespace
**/


/** section: Base
 * class SL.ElementUpdater < Request.HTML
 * 
 * This class provides an easy to (re-)use and extensible mechanism to Update 
 * an Element by fetching it's new content using an ajax request.
 * By default, a Loading/Spinner layer will cover the area which shall be updated.
**/

/**
 * new SL.ElementUpdater(source, target[, options = {}])
 *     - source (String): The URL to fetch the content from
 *     - target (Element | String): a string of the id for an Element or an Element reference to update
 *     - options (Object): _(Optional)_ A set of options to imfluence the update behavior, use of loading animation etc.
 * 
 * ##### Options
 * Options includes all of [Request](http://mootools.net/docs/core/Request/Request), 
 * and mixins from [Spinner](http://mootools.net/docs/more/Interface/Spinner), plus:
 * - updateMethod (String): `update`|`append`: `update` (replaces the current target content), `append` (append to the current target content)
 * - useSpinner (boolean): use the Spinner class with this request
 * - spinnerOptions (Object): the options object for the Spinner class
 * - spinnerTarget (Element | String): _(Optional, default: document.body)_ a string of the id for an Element or an Element reference to use instead of the deault.
 * 
 * _Note_ that a passed `url` option will be overwritten by the `source` argument!
 *
 * ##### Examples
 *     var updater = new SL.ElementUpdater(this.href, 'target123', {'updateMethod': 'append', 'spinnerTarget': 'wrapper123'});
 *     updater.get(); // as a shortcut, or :
 *     updater.send({"method": "get"}) // or even more data:
 *     updater.send({"method": "post", "data": {"some": "data"}});
 *       
**/
SL.ElementUpdater = new Class({
	
	Extends: Request.HTML,
	
	options: {
		'useSpinner': true,
		'spinnerTarget': null,
		'spinnerOptions': {},
		'updateMethod': 'update',
		'method': 'get'
	},
	
	initialize: function (source, target, options) {
		
		//this.options.spinnerTarget = $(document.body);
		this.setOptions(options);
		
		this.options.url = source;
		this.options[this.options.updateMethod] = target;
		this.options.spinnerTarget = this.options.spinnerTarget || target;
		
		this.parent(this.options);
		
	}
});


//SL.Tracker.trackEvent('update', {'srcUrl': source, 'target': target});
//SL.Tracker.trackEvent('openOverlay', {'srcUrl': source});
//SL.Tracker.trackEvent('closeOverlay', {'srcUrl': source});
/*
SL.Tracker = new Class({
	
	Implements: [Options],
	
	trackEvent: function(type, options) {
		
	}

});
*/

/** section: Base
 * class SL.ElementViewSwapper() 
 * 
 * Load another "view" for a given Element. Like an edit-view for a given textblock.
 * The main objective is to _not_ throw the original content away, but provide
 * a mechanism to update it, after the new view has done it's suff.
 * 
 * The term `target` is used for the actual element which shall be "replaced"
 * by a second, new element
 * 
**/

/**
 * new SL.ElementViewSwapper(source, target[, options = {}])
 *     - source (String): The URL to fetch the new views content from
 *     - target (String | Element): a string of the id for an Element or an Element reference to load the new view for.
 *     - options (Object): _(Optional)_ 
 * 
 * ##### Options
 * - inject (Srting): _(Optional, default: 'after')_ Where to inject the new View (see: [Element.inject](http://mootools.net/docs/core/Element/Element#Element:inject))
 * - prefix (String): _(Optional, default: 'view-')_ The ID-Prefix for the container, the fetched content will be load in
 * - updater (Object): _(Optional, default: {})_ Options passed to [[SL.ElementUpdater]]
**/
SL.ElementViewSwapper = (function (){
	// define some constants for storing values into Elements
	var IS_SWAPPED = 'SL.ElementViewSwapper.isSwapped';
	var IS_FETCHED = 'SL.ElementViewSwapper.isFetched';
	var NEW_TARGET = 'SL.ElementViewSwapper.newTarget';
	var SWAPPER    = 'SL.ElementViewSwapper.viewSwapper';
	
	var ElementViewSwapper = new Class({

		Implements: [Options, Events],
		
		options: {
			'inject': 'after',
			'prefix': 'view-',
			'updater': {}
		},
		
		sourceUrl: null,
		
		oldElement: null,
		
		newElement: null,

		initialize: function (source, target, options) {
			
			this.setOptions(options);
			this.sourceUrl = source;
			this.oldElement = $(target);
			
			this.bounds = {
				'onFetchSuccess': this.onFetchSuccess.bind(this),
				'onFetchRequest': this.onFetchRequest.bind(this)
			};
			
			this.oldElement.store(SWAPPER, this);
			
			this.newElement = this.injectTarget();
		},
		
		getTargetId: function () {
			
			return (this.options.prefix + this.oldElement.get('id'));
		},
		
		injectTarget: function () {
			
			var el = $(this.oldElement.retrieve(NEW_TARGET));
			if (el) {
				return el;
			} 
			
			el = new Element('div', {
				'id': this.getTargetId(),
				'styles': {
					'visibility': 'hidden'
				}
			});
			
			el.inject(this.oldElement, this.options.inject);
			this.oldElement.store(NEW_TARGET, this.getTargetId());
			
			return el;
		},

		/**
		 * SL.ElementViewSwapper#load(refetch = false) 
		 *     - refetch (boolean): whether to force the refetch of the remote content
		 * 
		 * 
		**/
		load: function (refetch) {
			
			if (false === this.oldElement.retrieve(IS_SWAPPED, false))
			{
				if (true === refetch || false === this.oldElement.retrieve(IS_FETCHED, false)) {
					
					var options = $extend({
						'onRequest': this.bounds.onFetchRequest,
						'onSuccess': this.bounds.onFetchSuccess,
						'updateMethod': 'update'
					}, this.options.updater);
					
					var updater = new SL.ElementUpdater(this.sourceUrl, this.newElement, options);
					updater.get();
				
				} else {
					this.show();
				}
			}
		},
		
		/**
		 * SL.ElementViewSwapper#dismiss(clean = false) 
		 *     - clean whether to throw the fetched content away
		**/
		dismiss: function (clean) {
			this.oldElement.show();
			this.oldElement.store(IS_SWAPPED, false);
			
			if (clean) {
				this.newElement.nix();
			} else {
				this.newElement.hide();
			}
		},
		
		show: function () {
			
			this.oldElement.hide();
			this.oldElement.store(IS_SWAPPED, true);
			this.newElement.show();
		},

		
		onFetchSuccess: function (responseText, responseXML) {
			
			this.oldElement.store(IS_FETCHED, true);
			this.newElement.setStyle('visibility', 'visible');
			this.show();
		},
		
		onFetchRequest: function () {
			
		}

	});
	
	/** section Base
	 * SL.ElementViewSwapper.getInstance(target[, source, options = {}])
	 *     - target (String | Element): The element to get an Swapper for
	 *     - source (String): _(Optional, when retrieving an existing Swapper)_ The URL to fetch the new content from
	 *     - options (Object): _(Optional)_ 
	 * 
	 * Factory for [[SL.ElementViewSwapper]]
	 * retrieves an existing, or creates a new instance of SL.ElementViewSwapper for a given target
	**/
	ElementViewSwapper.getInstance = function (target, source, options) {
		
		var inst = $(target).retrieve(SWAPPER);
		if (inst) {
			return inst;
		}
		return new SL.ElementViewSwapper(source, target, options);
	};
	
	return ElementViewSwapper;
})();


