/* BUTTON STATUSES
***************************************************************************************************/
var PageControlStatuses = {
	clear: "clear",  
	disabled: "disabled",  
	pressed: "pressed",  
	active: "active",  
	wait: "wait",  
	infocus: "infocus",
	hidden: "hidden"
};
// status = {title, isAppStatuses, blockApp, blockView, additional}
ScriptsManager.registerScript("PageControlStatuses");

/* PAGE CONTROL ELEMENT
***************************************************************************************************/
var PageControlElementAbstract = Class.create(
{
	initialize: function(element, pageControlStatuses, eventParams)
	{
		if( pageControlStatuses == undefined ){
			this.statuses = PageControlStatuses;
		} else {
			this.statuses = pageControlStatuses;
		}
		
		if( eventParams == undefined ){
			this.eventParams = new Object();
		} else {
			this.eventParams = eventParams;
		}
		
	//{ Fields
		this.element = element;	
		this.id = element.id;
		this.status = this.statuses.clear;
		this.styleClass = "";
	//}		
		if(this.clearStatus == undefined)
			throwNotDefinedError('clearStatus');
		if(this.setStatus == undefined)
			throwNotDefinedError('setStatus');
	}, 
		
	/**
	 * Sets events params for the  control element
	 * @param params	Object 	Params for generated events
	**/
	setEventParams: function(params)
	{
		if(typeof(params) != "object"){
			throw "Incorect parameter passed";
		}
		
		this.eventParams = params;
	}
});
ScriptsManager.registerScript("PageControlElementAbstract");


/* PAGE CONTROL ELEMENT
***************************************************************************************************/
var PageControlElement = Class.create(PageControlElementAbstract, 
{
	initialize: function($super, element)
	{
		$super(element);
		this.infocus = 0;
		this._observe();
		
		this.setStatus(this._defaultStatus);
	},	

	clearStatus: function()
	{
		this.element.removeClassName(this.styleClass);
		this.status = this.statuses.clear;
		if(this.infocus){
			this.styleClass = this.statuses.infocus;
			this.element.addClassName(this.styleClass);
		} else {
			this.styleClass = "";
		}
		this.element.fire("Control:statusCleared");
	},
	
	setStatus: function(status)
	{
		if(this.status != this.statuses.clear && this.status == status){
			return;
		}
		switch(status){
			case this.statuses.clear:
				this.clearStatus();
				break;
			case this.statuses.disabled:				
				this.element.removeClassName(this.styleClass);
				this.styleClass = status;
				this.element.addClassName(status);
				this.status = status;
				this.element.fire("Control:setDisabled");
				break;
			case this.statuses.pressed:
				this.element.removeClassName(this.styleClass);
				this.styleClass = status;
				this.element.addClassName(status);
				this.element.fire("Control:setPressed");				
				break;
			case this.statuses.hidden:
				this.element.removeClassName(this.styleClass);
				this.element.addClassName(status);
				this.status = status;
				this.styleClass = status;
				this.element.fire("Control:setHidden");				
				break;
			case this.statuses.active:
				this.element.removeClassName(this.styleClass);
				if(this.infocus){
					this.styleClass = status + this.statuses.infocus;					
				} else {
					this.styleClass = status;
				}
				this.element.addClassName(this.styleClass);
				this.status = status;
				this.element.fire("Control:setActive");				
				break;
			case this.statuses.wait:
				this.element.removeClassName(this.styleClass);
				if(this.infocus){
					this.styleClass = status + this.statuses.infocus;					
				} else {
					this.styleClass = status;
				}
				this.element.addClassName(this.styleClass);
				this.status = status;
				this.element.fire("Control:setWait");			
				break;	
			default:
				throw "Unknown status type";
		}
	},
	
	_defaultStatus: PageControlStatuses.clear,
//{ Delegates
	//{ Common actions
	_onFocusDelegate: function(event)
	{
		Event.stop(event);
		if( this.status == this.statuses.clear ||
			this.status == this.statuses.active ||
			this.status == this.statuses.wait )
		{
			this.infocus = 1;
			this.setStatus(this.status);
			this.element.fire("Control:focus", this.eventParams);
		} else {
			Event.stop(event);
		}		
	},
	
	_onBlurDelegate: function(event)
	{
		Event.stop(event);
		if( this.status == this.statuses.clear ||
			this.status == this.statuses.active ||
			this.status == this.statuses.wait )
		{
			this.infocus = 0;
			this.setStatus(this.status);
			this.element.fire("Control:blur", this.eventParams);			
		} else {
			Event.stop(event);
		}		
	},
	
	_onClickDelegate: function(event)
	{		
		if( this.status == this.statuses.disabled ||
			this.status == this.statuses.hidden || 
			this.status == this.statuses.wait || 
			this.status == this.statuses.active )		
		{
			Event.stop(event);
		} else {
			this.element.fire("Control:click", this.eventParams);
		}		
	},	
	//}
	//{ Mouse actions
	_onMouseOverDelegate: function(event)
	{
		Event.stop(event);
		if(	this.status == this.statuses.clear ||
			this.status == this.statuses.active ||
			this.status == this.statuses.infocus )
		{
			this.element.fire("Control:mouseover", this.eventParams);
		} else {
			Event.stop(event);
		}
	},

	_onMouseDownDelegate: function(event)
	{
		Event.stop(event);
		if(	this.status == this.statuses.clear ||
			this.status == this.statuses.infocus )		
		{
			this.setStatus(this.statuses.pressed);
			this.element.fire("Control:mousedown", this.eventParams);			
		} else {
			Event.stop(event);
		}
	},
		
	_onMouseUpDelegate: function(event)
	{
		Event.stop(event);
		if(	this.status == this.statuses.hidden ){
			Event.stop(event);
		} else {
			this.setStatus(this.status);
			this.element.fire("Control:mouseup", this.eventParams);
		}
	},
		
	_onDbClickDelegate: function(event)
	{
		Event.stop(event);
		if( this.status == this.statuses.clear ||
			this.status == this.statuses.infocus )		
		{
			this.element.fire("Control:dbclick", this.eventParams);			
		} else {
			Event.stop(event);
		}
	},
	
	_onMouseOutDelegate: function(event)
	{
		Event.stop(event);
		if(	this.status == this.statuses.clear ||
			this.status == this.statuses.active ||
			this.status == this.statuses.infocus )
		{
			this.element.fire("Control:mouseout", this.eventParams);
		} else {
			Event.stop(event);
		}
	},
	//}
	//{ Keyboard actions
	_onKeyDownDelegate: function(event)
	{
		Event.stop(event);
		var params = this.eventParams;
		params.charCode = event.charCode;
		params.keyCode = event.keyCode;
		if(	this.status == this.statuses.clear ||
			this.status == this.statuses.infocus )		
		{
			this.setStatus(this.statuses.pressed);
			this.element.fire("Control:keydown", params);
		} else {
			Event.stop(event);
		}
	},
	
	_onKeyPressDelegate: function(event)
	{
		Event.stop(event);
		var params = this.eventParams;
		params.charCode = event.charCode;
		params.keyCode = event.keyCode;
		this.element.fire("Control:keypress", params);
	},
	
	_onKeyUpDelegate: function(event)
	{
		Event.stop(event);
		var params = this.eventParams;
		params.charCode = event.charCode;
		params.keyCode = event.keyCode;
		if(	this.status == this.statuses.clear ||
			this.status == this.statuses.infocus )		
		{
			Event.stop(event);
		} else {
			this.setStatus(this.status);
			this.element.fire("Control:keyup", params);
		}
	},
	//}	
//}
//{ Observing		
	_observe: function()
	{
	//{ Common events
		Event.observe(this.element, 'focus', this._onFocusDelegate.bind(this));
		Event.observe(this.element, 'blur', this._onBlurDelegate.bind(this));
		Event.observe(this.element, 'click', this._onClickDelegate.bind(this));
	//}
	//{ Mouse events
		Event.observe(this.element, 'mouseover', this._onMouseOverDelegate.bind(this));
		Event.observe(this.element, 'mousedown', this._onMouseDownDelegate.bind(this));
		Event.observe(this.element, 'mouseup', this._onMouseUpDelegate.bind(this));
		Event.observe(this.element, 'dbclick', this._onDbClickDelegate.bind(this));
		Event.observe(this.element, 'mouseout', this._onMouseOutDelegate.bind(this));
	//}
	//{Keyboard events
		Event.observe(this.element, 'keypress', this._onKeyPressDelegate.bind(this));
		Event.observe(this.element, 'keydown', this._onKeyDownDelegate.bind(this));
		Event.observe(this.element, 'keyup', this._onKeyUpDelegate.bind(this));
	//}
	}
//}
});
ScriptsManager.registerScript("PageControlElement");

/* JS BUTTON
**************************************************************************************************/
var JsButton = Class.create(PageControlElement, 
{
	_defaultStatus: PageControlStatuses.wait
});
ScriptsManager.registerScript("JsButton");

/* <A> JS BUTTON
**************************************************************************************************/
var AJsButton = Class.create(JsButton, 
{		
	_onClickDelegate: function(event)
	{
		Event.stop(event);
		if( !(this.status == this.statuses.disabled ||
			this.status == this.statuses.wait || 
			this.status == this.statuses.hidden || 
			this.status == this.statuses.active) )		
		{
			this.element.fire("Control:click", this.eventParams);			
		}
	}
});
ScriptsManager.registerScript("AJsButton");

/* PAGE CONTROL TYPE
***************************************************************************************************/
var PageControlType = Class.create({
	initialize: function(cssClassName, appClassName)
	{	
		if(cssClassName != undefined){
			this.cssClassName = cssClassName;
		}
		if(appClassName != undefined){
			this.appClassName = appClassName;
		}
		
		var throwNotDefinedError = function(caption){
			throw '"' + caption + '" : is not defined';
		};

		if(this.cssClassName == undefined)
			throwNotDefinedError('cssClassName');
		if(this.appClassName == undefined)
			throwNotDefinedError('appClassName');
	}
});
ScriptsManager.registerScript("PageControlType");
/* EXAMPLE FOR CREATING NEW TYPE

var someType = new (Class.create(PageControlType, {cssClassName: "some class name", appClassName: "some control class name"}));
*/

/* CONTROLS MANAGER
***************************************************************************************************/
var PageControlsManager = Class.create(
{
	initialize: function(page)
	{
		this.types = $H({
			button: new (Class.create(PageControlType, {cssClassName: "a.button", appClassName: "JsButton"})),
			linkButton: new (Class.create(PageControlType, {cssClassName: "a.linkbutton", appClassName: "PageControlElement"}))});
		this.controls = new Hash();
		this.notRegisteredElements = new Hash();
	},

	
	/**
	 * Registers new page conntrols by PageControlType and creates objects for it
	 * @param pageControlsType	PageControlType	Type for registering if parametr is undefined registers elemements for default controls types
	 * @return  Array 	Array of PageControlElement
	**/
	registerElements: function(pageControlType)
	{
		if(pageControlType == undefined){			
			var controls = new Array();
			this.types.each(function(type){
				controls.concat(this.createControls(eval(type.value.appClassName), $$(type.value.cssClassName)));
			}.bind(this));			
			return controls;
		} else {	
			if(pageControlType.appClassName == undefined || pageControlType.cssClassName == undefined){
				throw "Param`s value is not PageControlType object";
			}
			return this.createControls(eval(pageControlType.appClassName), $$(pageControlType.cssClassName));
		}
	},

	/**
	 * Sets status for the control
	 * @param control 	Element id or  array of elements ids or control object or  array of controls object
	 * @param status		Control status
	**/
	setStatus: function(control, status)
	{
		var control;
		var setControlStatus = function(control){
			if(Object.isString(control)){
				control = this.controls.get(control);
				if(control == undefined){
					throw "Control is undefined";
				}
				control.setStatus(status);
			} else if(Object.isElement(control)){
				control = this.controls.get(control.id);
				if(control == undefined){
					throw "Control is undefined" + Object.inspect(control); 
				}
				control.setStatus(status);
			} else {
				control.setStatus(status);
			}
		}.bind(this); 
		
		if(Object.isArray(control)){		
			for(var i=0; i<control.length; i++){
				setControlStatus(control[i]);
			}
		} else {
			setControlStatus(control);
		}
	},
	
	/**
	 * Gets control by identifier
	 * @param ident		Element OR element id OR array of the elements OR array of elements ids
	 * @return PageControlElement object OR array of PageControlElement objects
	**/
	getControls: function(ident)
	{
		var getControl = function(ident){
			var control;
			if(Object.isString(ident)){
				control = this.controls.get(ident);
				if(control == undefined){
					throw "Control is undefined" + ident;
				}				
			} else if(Object.isElement(ident)){
				control = this.controls.get(ident.id);
				if(control == undefined){
					throw "Control is undefined" + ident;
				}				
			}
			return control;
		}.bind(this); 
		
		if(Object.isArray(ident)){		
			var controls = new Array();
			for(var i=0; i<ident.length; i++){
				controls.push(getControl(ident[i]));
			}
			return controls;
		} else {
			return getControl(ident);
		}
	},
	
	/**
	* Sets visual status for the element
	* @param ident 	string 			Element css identifier
	* @param status	PageControlStatus	Sattus wich will be visualized
	**/
	setVisualStatusForElements: function(ident, status)
	{
		var elements = $$(ident);
		for(var i=0; i<elements.length; i++){
			this.notRegisteredElements.set(elements[i].id, status);
			elements[i].addClassName(status);
		}
	},
	
	
	/**
	 * Destroys page controls
	 * @param controls 	PageControlElement objects
	**/
	destroyControls: function(controls)
	{
		var destroyControl = function(control){
			var id = control.element.id;
			this.controls.unset(id);
		}.bind(this);
		
		if(Object.isArray(controls)){
			for(var i=0; i<controls.length; i++){
				destroyControl(controls[i]);
			}			
		} else {
			destroyControl(controls);
		}
		
	// Run garbarge collector on IE
		if (window.CollectGarbage){
			window.CollectGarbage();
		}
	},
	
	/**
	 * Creates controls objects
	 * @param classObject 	Class object of the page control
	 * @param elements 		Elements to create
	 * @return Array 	Array of PageControlElement
	**/	
	createControls: function(classObject, elements)
	{
	//add rewrite rule
		var controls = new Array();
		var control, curStatus;
		var createControl = function(classObject, element){
			control = this.controls.get(element.id);
			if(control == undefined){
				control = new classObject(element);			
				this.controls.set(element.id, control);
				curStatus = this.notRegisteredElements.get(element.id);
				if(curStatus != undefined){
					element.removeClassName(curStatus);
				}
			}
			controls.push(control);
		}.bind(this);
		
		if(Object.isArray(elements)){
			for(var i=0; i<elements.length; i++){
				createControl(classObject, elements[i]);
			}
		} else {
			createControl(classObject, elements);
		}		
		
		return controls;
	}
});

var pageControlsManager = new PageControlsManager(document.body);
ScriptsManager.registerScript("PageControlsManager");