/**
 * Font size UI controller
 * 
 * This module is UI controller for font size
 * control. It is initialized using font size control
 * container ID and array of font-size options.
 * 
 * Use of static method
 * (Zfse_Fontsize) Zfse_Fontsize.init(containerId, options);
 * is recommended.
 * 
 * Supported options are:
 * array sizes 			Array of available font sizes, or empty
 * 						if dynamic font size control 
 * float defaultSize	Default font size
 * string unit			CSS font size unit
 * float delta			Delta for dynamic control (0.1 = decrease/increase by 0.1)
 * int lowerLimit		Lower font size limit (e.g. 0.7)
 * int upperLimit		Upper font size limit (e.g. 2.0)
 */
Zfse_Fontsize = function(containerId, options){
	
	this.containerId = containerId,
	this.options = options,
	this._container = null,
	this._sizes = {},
	this._dynamic = false,
	this._size = null,
	
	this._construct = function(){
		this._container = document.getElementById(this.containerId);
		this._sizes = this.options.sizes;
		this._dynamic = (this.options.sizes.length == 0);
		
		var ctrls = this._getControls();
		var ctrl;
		
		/**
		 * Check whether cookies are enabled
		 */
		if(!this._cookiesEnabled())
			return;
		
		/**
		 * Initialize all font size control elements
		 */
		for(var i = 0; i<ctrls.length; i++){
			ctrl = ctrls[i];
			$(ctrl).find('a').attr('href', 'javascript:void(0);');
			
			this._testControl(i);
			
			/**
			 * Set dynamic sizes
			 */
			if(this._dynamic && i == 0){
				this._sizes[i] = Math.round((this.getSize() - this.options.delta)*100)/100;
			}
			if(this._dynamic && i == 1){
				this._sizes[i] = Math.round((this.getSize() + this.options.delta)*100)/100;
			}
		}
		
		/**
		 * Initialize reset element
		 */
		var reset = this._getReset();
		if(reset){
			$(reset).find('a').attr('href', 'javascript:void(0);');
			$(reset).click(
				(function(obj){
					return function(){obj._onReset();};
				})(this)
			);
		}
		this.setSize(this.getSize());
	},
	
	/**
	 * Returns current font size
	 * 
	 * @return int
	 */
	this.getSize = function(){
		if(this._size == null){
			var s = this._readCookie('zfse_fontSize');
			var u = this._readCookie('zfse_fontSizeUnit');
			
			if(s != null && s != 'NaN' && (u == null || u == this.options.unit)){
				return Math.round(parseFloat(s)*100)/100;
			}
			else{
				return this.options.defaultSize;
			}
		}
		else{
			return this._size;
		}
	},
	
	/**
	 * Sets font size
	 * 
	 * @param {int} size
	 * @return {boolean} True on success, false otherwise
	 */
	this.setSize = function(size){
		var l, c;
		
		if(this.options.lowerLimit != null && size < this.options.lowerLimit){
			return false;
		}
		else if(this.options.upperLimit != null && size > this.options.upperLimit){
			return false;
		}
		
		if(this.options.container){
			$(this.options.container).css('fontSize', size + this.options.unit);
		}
		else{
			l = document.body.childNodes.length;
			
			/**
			 * Apply font size for all div elements that
			 * are direct descendants of body element
			 */
			for(var i=0; i<l; i++){
				c = document.body.childNodes[i];
				
				if(c.nodeType == Node.ELEMENT_NODE && c.nodeName == 'DIV'){
					c.style.fontSize = size + this.options.unit;
				}
			}
		}
		
		/**
		 * Store new size in a cookie
		 */
		this._eraseCookie('zfse_fontSize');
		this._createCookie('zfse_fontSize', size, null);
		
		/**
		 * Remember this size
		 */
		this._size = size;
		
		/**
		 * Update the sizes for dynamic controls
		 */
		if(this._dynamic){
			
			this._sizes[0] = Math.round((size-this.options.delta)*100)/100;
			this._sizes[1] = Math.round((size+this.options.delta)*100)/100;

			this._testControl(0);
			this._testControl(1);
		}
		else{
			this._testControls();
		}
		
		return true;
	},
	
	/**
	 * Resets font size to the default size
	 */
	this.reset = function(){
		this.setSize(this.options.defaultSize);
	},	
	
	/**
	 * Runs internal tests for control by control number
	 * 
	 * Internal tests check, whether the control should
	 * be enabled or disabled.
	 */
	this._testControl = function(controlNum){
		var s = this._sizes[controlNum];
		
		if(this._dynamic){
			if(this.options.upperLimit != null && s > this.options.upperLimit){
				this._disableControl(controlNum);
			}
			else if(this.options.lowerLimit != null && s < this.options.lowerLimit){
				this._disableControl(controlNum);
			}
			else{
				this._enableControl(controlNum);
			}
		}
		else{
			this._enableControl(controlNum);
			
			if(this.getSize() == this._sizes[controlNum]){
				this._selectControl(controlNum);
			}
			else{
				this._unSelectControl(controlNum);
			}
		}
	},
	
	/**
	 * Run tests on all controls
	 */
	this._testControls = function(){
		var ctrls = this._getControls();
		
		for(var i = 0; i<ctrls.length; i++){
			this._testControl(i);
		}
	},
	
	/**
	 * Enable control
	 * 
	 * @param {int} controlNum
	 */
	this._enableControl = function(controlNum){
		var ctrls = this._getControls();
		var ctrl = ctrls[controlNum];
		
		$(ctrl).removeClass('zfse_fontSizeDisabled');
		$(ctrl).find('*').removeClass('zfse_fontSizeDisabled');
		
		ctrl.onclick = (function(obj, i){
			return function(){obj._onSetSize(i);};
		})(this, controlNum);
	},
	
	/**
	 * Disable control
	 * 
	 * @param {int} controlNum
	 */	
	this._disableControl = function(controlNum){
		var ctrls = this._getControls();
		var ctrl = ctrls[controlNum];
		
		$(ctrl).addClass('zfse_fontSizeDisabled');
		$(ctrl).find('*').addClass('zfse_fontSizeDisabled');
		
		ctrl.onclick = null;
	},
	
	/**
	 * select control
	 * 
	 * @param {int} controlNum
	 */
	this._selectControl = function(controlNum){
		var ctrls = this._getControls();
		var ctrl = ctrls[controlNum];
		
		$(ctrl).addClass('zfse_fontSizeSelected');
		$(ctrl).find('*').addClass('zfse_fontSizeSelected');
	},
	
	/**
	 * unSelect control
	 * 
	 * @param {int} controlNum
	 */	
	this._unSelectControl = function(controlNum){
		var ctrls = this._getControls();
		var ctrl = ctrls[controlNum];
		
		$(ctrl).removeClass('zfse_fontSizeSelected');
		$(ctrl).find('*').removeClass('zfse_fontSizeSelected');
	},	
	
	/**
	 * Returns array of control elements
	 * 
	 * @return {Array}
	 */
	this._getControls = function(){
		if(this._dynamic){
			var order = ['smaller', 'default', 'larger'], k, c, controls = new Array();
			
			for(var i = 0; i<order.length; i++){
				k = order[i];
				c = $(this._container).find('.zfse_fontSize_'+k).get(0);
				
				if(c){
					controls[controls.length] = c;
				}
			}
			
			return controls;
		}
		else{
			return $(this._container).find('.zfse_fontSizeControl').get();
		}
	},
	
	/**
	 * Returns reset element or null if not found
	 * 
	 * @return {Object}
	 */
	this._getReset = function(){
		return $(this._container).find('.zfse_fontSizeReset').get(0);
	},
	
	/**
	 * Triggered when user toggles reset control
	 */
	this._onReset = function(){
		this.reset();
	},
	
	/**
	 * Triggered when user toggles size control
	 */	
	this._onSetSize = function(ctrlNum){
		var s = this._sizes[ctrlNum];
		this.setSize(s);
	},
	
	/**
	 * Creates a cookie
	 * 
	 * @param {String} name
	 * @param {String} value
	 * @param {int} days
	 */
	this._createCookie = function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path="+this.options.cookiePath;
	},

	/**
	 * Reads value of a cookie
	 * 
	 * @param {String} name
	 * @return {String}
	 */
	this._readCookie = function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	},

	/**
	 * Erases cookie
	 * 
	 * @param {String} name
	 */
	this._eraseCookie = function(name) {
		this._createCookie(name,"",-1);
	},
	
	/**
	 * Cheks whether the cookies are enabled
	 * 
	 * @return {boolean}
	 */
	this._cookiesEnabled = function(){
		var t = 'zfse_fontSizeTest';
		
		this._eraseCookie(t);
		var c = this._createCookie(t, t, 1);
		var v = this._readCookie(t);
		if(v) this._eraseCookie(t);
		
		return v == t;
	},
	
	this._construct();
};

/**
 * Collection of font size controls
 */
Zfse_Fontsize._controls = new Object();

/**
 * Static initializer for font size module
 * 
 * @param {String} containerId
 * @param {Object} options
 */
Zfse_Fontsize.init = function(containerId, options){
	var ctrl = new Zfse_Fontsize(containerId, options);
	Zfse_Fontsize._controls[containerId] = ctrl;
	
	return ctrl;
};

/**
 * Returns font size control by id
 * 
 * @param {String} containerId
 * @return {Object}
 */
Zfse_Fontsize.getControlById = function(containerId){
	return Zfse_Fontsize._controls[containerId]; 
};
