//*************************************************************************************************
/*!
	\file		Solera.js
	\brief		Main decfinitions
	\par    	Project:
					Solera 0.01
	\par		Copyright:
					PATANEGRA Soft<br>
					Sevilla (SPAIN)<br>
					<a href="http://www.patanegra.com">http://www.patanegra.com</a>	<br>
					Aug 2003
*/
//*************************************************************************************************

//*************************************************************************************************
/*!
	\brief		Function: meta key definitions container (call only once at initiazation)
	\internal
	\date		Sep 2007 - AGS
*/
//*************************************************************************************************
function SlKey()
{
	// Special chars
	SlKey.ESCAPE      = 27;
	SlKey.SPACE       = 32;
	SlKey.TAB         = 9;
	SlKey.ENTER       = 13;

	// Others
	SlKey.PRINTSCREEN = 44;
	SlKey.NUMLOCK     = 144;
	SlKey.SCROLLLOCK  = 145;
	SlKey.CAPSLOCK    = 20;
	SlKey.PAUSE       = 19;

	// Edit keys
	SlKey.INSERT      = 45;
	SlKey.BAKSPACE    = 8;
	SlKey.DELETE      = 46;
	SlKey.UP          = 38;
	SlKey.DOWN        = 40;
	SlKey.LEFT        = 37;
	SlKey.RIGHT       = 39;
	SlKey.HOME        = 36;
	SlKey.END         = 35;
	SlKey.PAGEUP      = 33;
	SlKey.PAGEDOWN    = 34;

	// Function keys
	SlKey.F1          = 112;
	SlKey.F2          = 113;
	SlKey.F3          = 114;
	SlKey.F4          = 115;
	SlKey.F5          = 116;
	SlKey.F6          = 117;
	SlKey.F7          = 118;
	SlKey.F8          = 119;
	SlKey.F9          = 120;
	SlKey.F10         = 121;
	SlKey.F11         = 122;
	SlKey.F12         = 123;
}

//*************************************************************************************************
/*!
	\brief		Function: meta mouse button definitions container (call only once at initiazation)
	\internal
	\date		Sep 2007 - AGS
*/
//*************************************************************************************************
function SlButton()
{
	// CrossBrowsing: distinct numeration for mouse buttons
	if(SlSys._ie)
	{
		SlButton.LEFT   = 1;
		SlButton.MIDDLE = 4;
		SlButton.RIGHT  = 2;
	}
	else
	{
		SlButton.LEFT   = 0;
		SlButton.MIDDLE = 1;
		SlButton.RIGHT  = 2;
	}

	//*************************************************************************************************
	/*!
		\brief	  	Convert a button code in string
		\param		button Button code
		\return 	A string containing the button code
		\internal
		\date		Sep 2007 - AGS
	*/
	//*************************************************************************************************
	SlButton.toString = function(button)
	{
		switch(button)
		{
			case SlButton.LEFT  : return 'LEFT'   ;
			case SlButton.MIDDLE: return 'MIDDLE' ;
			case SlButton.RIGHT : return 'RIGHT'  ;
			default             : return 'Unknown';
		}
	};
}

//*************************************************************************************************
/*!
	\brief		Class: Clean system services (without solera dependencies) for solera objects
	\internal
	\date			Aug 2005 - AGS
*/
//*************************************************************************************************
function SlSys()
{
	// Get document head
	SlSys._head = document.getElementsByTagName('head')[0];

	// Get document body: Useful for SlSys._body.clientWidth/clientHeight (for physical use screen.width/height)
	SlSys._body = document.getElementsByTagName('body')[0];

	// Get document protocol (including //)
	SlSys._proto = document.location.protocol + '//';

	// CrossBrowsing: detect browsers
	SlSys._ua     = navigator.userAgent.toLowerCase();
	SlSys._safari = SlSys._ua.indexOf("safari") > -1;
	SlSys._opera  = SlSys._ua.indexOf("opera") > -1;
	SlSys._ns     = !SlSys._opera && !SlSys._safari && (navigator.appName == "Netscape");
	SlSys._ie     = !SlSys._opera && (navigator.appName == "Microsoft Internet Explorer");
	SlSys._gecko  = SlSys._ua.indexOf('gecko') > -1;

	// Timeout (milliseconds). Default
	SlSys._timeout = 50;

	// Timeout (milliseconds). Destroy delay (should be > ajax timeout)
	SlSys._destroytimeout = 60000;

	// Debug messages?
	SlSys._debugmsg = 0; // 0 none, 1 launch, 2 processing

	// Load meta keys
	SlKey();

	// Load meta buttons
	SlButton();
}

//! "Clean" system services initialization
SlSys();

//*************************************************************************************************
/*!
	\brief		Method: Configure inheritance for a class
	\param		motherclass A direct reference to the mother class
	\return		The own object
	\internal
	\date			Oct 2003 - Douglas Crockford
	\date			Dec 2003 - AGS
*/
//*************************************************************************************************
Function.prototype.inherits = function(motherclass)
{
	// Sets new prototype object
   this.prototype = new motherclass;

	// Get name of the class
	var __classname = this.toString();
	__classname = __classname.substr(0, __classname.indexOf('(')).split(' ')[1];

	//! Method: Returns Solera class name
	this.getClassName = this.prototype.getClassName = function()
	{
		return __classname;
	}

	//! Method: Returns if the object/class descends from a Solera class name
	this.descendsFrom = this.prototype.descendsFrom = function(cn)
	{
		return __classname == cn || (motherclass.descendsFrom ? motherclass.descendsFrom(cn) : cn == 'Function');
   	}

   return this;
}

//! Set inheritance
SlBase.inherits(Function);

//*************************************************************************************************
/*!
	\brief		Class: Solera base class
	\param		id Object identifier (null for automatic)
	\par			Comment:
						- All vars leading _ (single underscore) will be considered as public, readable, non writable<br>
						- All vars leading __ (double underscore)  will be considered as private, non readable, non writable<br>
						- All the rest of vars will be considered as public, readable, writable
						- All methods will be considered public, readable, writable, executable<br>
	\internal
	\date			Sep 2003 - AGS
*/
//*************************************************************************************************
function SlBase(id)
{
	// Automatic id generation: classname + counter
	if(id == null)
	{
		// Obtain object classname
		var s = this.getClassName();

		// Check for class counter array
		if(SlBase.__counters == null)
			SlBase.__counters = new Object;

		// Check for class counter value
		if(SlBase.__counters[s] == null)
			SlBase.__counters[s] = 0;

		// Default id for objects
		id = s + SlBase.__counters[s]++;
	}

	// Attributes
	this._id     = id;  	   	  //!< Id
	this._status = new Object; //!< Object status

	// Check for objects array
	if(SlBase.__all == null)
		SlBase.__all = new Object;

	// Check id duplicates
	if(SlBase.__all[id] != null)
		throw 'context=[SlBase()] class=[' + this.getClassName() + '] what=[Identifier \"' + id + '\" already declared]';

	// Index solera object
	SlBase.__all[id] = this;
}

//*************************************************************************************************
/*!
	\brief		Method: Default message processing
	\param		msg   Message sent
	\return		An useful value of any type
	\internal
	\date		Jun 2005 - AGS
*/
//*************************************************************************************************
SlBase.prototype.msgDefault = function(msg)
{
	if(SlSys._debugmsg >= 2)
	{
		var debugstr = 'SlBase: ' + msg.getClassName().toUpperCase() + ' --> ' + this._id;
		SlDebug(debugstr);
    }

	// Return value
    var ret = true;

	switch(msg.getClassName())
	{
		// Just eval string
		case 'SlMsgEvalBase':
		case 'SlMsgEval':
			return eval('{' + msg._expr + '}');
			break;

		// Just call function with all arguments packed in array
		case 'SlMsgFunctionBase':
		case 'SlMsgFunction':
			// Pseudo-realistic call to the function with its parameters
			switch(msg._argv.length)
			{
				case 0:
					return msg._func();
				case 1:
					return msg._func(msg._argv[0]);
				case 2:
					return msg._func(msg._argv[0], msg._argv[1]);
				case 3:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2]);
				case 4:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3]);
				case 5:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4]);
				case 6:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4], msg._argv[5]);
				case 7:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4], msg._argv[5], msg._argv[6]);
				case 8:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4], msg._argv[5], msg._argv[6], msg._argv[7]);
				case 9:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4], msg._argv[5], msg._argv[6], msg._argv[7], msg._argv[8]);
				case 10:
					return msg._func(msg._argv[0], msg._argv[1], msg._argv[2], msg._argv[3], msg._argv[4], msg._argv[5], msg._argv[6], msg._argv[7], msg._argv[8], msg._argv[9]);
				default:
					var funname = msg._func.toString();
					funname = funname.substr(0, funname.indexOf('(')).split(' ')[1];
					var exstring = 'context=[SlBase.prototype.msgDefault()] what=[Too many params in SlMsgFunction \"' + funname + '()\"] class=[\"' + this.getClassName() + '\"] id=[\"' + this._id + '\"]';
					throw exstring;
			}
			break;

		// No action at this level
		case 'SlMsgSend':
			break;

		// No action at this level
		case 'SlMsgRecv':
			break;

		case 'SlMsgRequest':
			// Send SlMsgSend to the object, abort operation if it returns false
			if(!this.msgDefault(new SlMsgSend()))
				return false;

			// Asynchronous launcher to send a SlMsgRecv
			var msync = new SlMsgFunctionBase(
				function()
				{
					if(!this._destobj.getStatus('async'))
						this._destobj.msgDefault(new SlMsgRecv());
				});

			// Destination for sync message
			msync._destobj = this;

			// Execute SlMsgRequest action
			msg.launch(this, this.getStatus('async'), msync);
			break;

		// Unknown message class
		default:
			if(SlSys._debugmsg >= 2)
				SlDebug('Rejected ' + msg.getClassName().toUpperCase());

			// Ignore layer non captured events, otherwise generate error
			if(!this.descendsFrom('SlLayer'))
				throw 'context=[SlBase.msgDefault()] class=[' + this.getClassName() + '] what=[Cant\'t process message of type \"' + msg.getClassName() + '\"]';
	}

	return ret;
}

//*************************************************************************************************
/*!
	\brief		Method: Destroy object
	\internal
	\date		Dec 2003 - AGS
*/
//*************************************************************************************************
SlBase.prototype.destroy = function()
{
	// At this level, just unregister object
	SlBase.__all[this._id] = null;
}

//*************************************************************************************************
/*!
	\brief		Method: Return value for a statys type
	\param		stype Status type
	\return		The value of the status for \a stype
	\internal
	\date			Oct 2003 - AGS
*/
//*************************************************************************************************
SlBase.prototype.getStatus = function(stype)
{
	return this._status[stype];
}

//*************************************************************************************************
/*!
	\brief		Method: Sets the value for a status type
	\param		stype  Status name / Array of status names
	\param		svalue Status value / Array of new status values
	\return		The new value or the first new value if use arrays
	\par		Comment:
				If \a stype is an array, \a svalue must be another one
	\internal
	\date			Oct 2003 - AGS
*/
//*************************************************************************************************
SlBase.prototype.setStatus = function(stype, svalue)
{
	if(typeof(stype) == 'object')
	{
		for(var x = 0; x < stype.length; x++)
			this._status[stype[x]] = svalue[x];
		return svalue[0];
	}
	else
	{
		return this._status[stype] = svalue;
	}
}

//*************************************************************************************************
/*!
	\brief		Method: Sets the value for a status type if not previously stablished
	\param		stype  Status name / Array of status names
	\param		svalue Status value / Array of new status values
	\return		The new value or the first new value if use arrays
	\par			Comment:
					If \a stype is an array, \a svalue must be another one
	\internal
	\date			Oct 2003 - AGS
*/
//*************************************************************************************************
SlBase.prototype.setStatusDefault = function(stype, svalue)
{
	if(typeof(stype) == 'object')
	{
		for(var x = 0; x < stype.length; x++)
			if(this._status[stype[x]] == null)
				this._status[stype[x]] = svalue[x];
		return svalue[0];
	}
	else
	{
		if(this._status[stype] == null)
			return this._status[stype] = svalue;
		return this._status[stype];
	}
}

//*************************************************************************************************
/*!
	\brief		Method: Deletes a status item
	\param		stype  Status name / Array of status names
	\internal
	\date		Sep 2007 - AGS
*/
//*************************************************************************************************
SlBase.prototype.dropStatus = function(stype)
{
	if(typeof(stype) == 'object')
	{
		for(var x = 0; x < stype.length; x++)
			delete this._status[stype[x]];
	}
	else
	{
		delete this._status[stype];
	}
}

//! Set inheritance
SlModule.inherits(SlBase);

//*************************************************************************************************
/*!
	\brief		Class: Development
	\param		id		  Id for instance, not null for singleton module vars
	\param		path    Access path
	\param		culture Culture
	\param		theme   Theme
	\internal
	\date			Aug 2003 - AGS
*/
//*************************************************************************************************
function SlModule(id, path, culture, theme)
{
	// Needed for inherits method. DON'T REMOVE!!!
	if(arguments.length == 0)
		return;

	// Mother class ctor, module instances are singletones due to unique ids
	SlBase.call(this, id);

	// For Initialize in constructors
	this._name     = null; //!< Name
	this._version  = null; //!< Versi?n
	this._created  = null; //!< Date creation
	this._updated  = null; //!< Date modification
	this._license  = null; //!< License type
	this._company  = null; //!< Company
	this._web 	   = null; //!< Web
	this._team     = null; //!< Developer team

	this._path     = path    ? path    : ''       ; //!< Path to resources and files
	this._culture  = culture ? culture : 'Default'; //!< Culture
	this._theme    = theme   ? theme   : 'Default'; //!< Theme

	//! Possible status for whole application: use, design
	this._status['runmode'] = 'use';
}

//*************************************************************************************************
/*!
	\brief		Method: Gets a resource by its type and name
	\param		type Type
	\param		name Name
	\return  	A variable type with the wanted resource
	\par			Comment:
						Types supported:                       \n
						\b img   Theme image                   \n
						\b ntimg Non theme image               \n
						\b css   Theme css                     \n
						\b theme Theme configuraton javascript \n
						\b str   Culture string                \n
						\b js	 Javascript source              \n
	\internal
	\date			Aug 2005 - AGS
*/
//*************************************************************************************************
SlModule.prototype.getResource = function(type, name)
{
	switch(type)
	{
		case 'img'  : return this._path + 'Themes/' + this._theme + '/Res/' + name;
		case 'ntimg': return this._path + 'Resources/' + name;

		// CrossBrowsing: gecko needs an unique title string in css loading, don't use more than one!
		case 'css'  : return '<link type="text/css" rel="stylesheet" href="' + this._path + 'Themes/' + this._theme + '/Css/' + name + '" title="' + document.location.href + '">';

		case 'theme': return '<' + 'script language="JavaScript" src="' + this._path + 'Themes/' + this._theme + '/' + name + '"><' + '/script' + '>';
		case 'str'  : return name; //zz need implement this!
		case 'js'   : return '<' + 'script type="text/javascript" src="' + this._path + name + '"><' + '/script' + '>';
		default     : throw  'context=[SlModule.prototype.getResource()] what=[Unknown type \"' + type + '\"]';
	}
}

//*************************************************************************************************
/*!
	\brief		Method: Include file by its resource type and name
	\param		type Type
	\param		name Name
	\par			Comment:
						Resource types are the same that in SlModule.getResource() method
	\internal
	\date			Aug 2005 - AGS
*/
//*************************************************************************************************
SlModule.prototype.include = function (type, name)
{
	document.write(this.getResource(type, name));
}

//! Set inheritance
Solera.inherits(SlModule);

//*************************************************************************************************
/*!
	\brief		Class: Solera library environment
	\param		path    Access path
	\param		culture Culture
	\param		theme   Theme
	\internal
	\date			Aug 2005 - AGS
*/
//*************************************************************************************************
function Solera(path, culture, theme)
{
	// Mother class ctor
	SlModule.call(this, this.getClassName(), path, culture, theme);

	// For Initialize in constructors
	this._name     = this.getClassName();
	this._version  = '0.01';
	this._created  = new Date(2003, 8, 18);
	this._updated  = new Date(2006, 2, 20);
	this._license  = 'LGPL';
	this._company  = 'PATANEGRA Soft S.L.';
	this._web 	   = 'www.patanegra.com/Solera';
	this._team     = 'AGS FMD';

	// Solera. js. base
	this.include('js'   , 'SlUtil.js'			);
	this.include('js'   , 'SlMessage.js'		);
	/* zz
	this.include('js'   , 'SlNetwork.js'		);
	this.include('js'   , 'SlDebug.js'		);
	this.include('js'   , 'SlNavigator.js'	);
	*/

	// Solera. js. interface
	this.include('js'   , 'SlLayer.js'			);
	this.include('js'   , 'SlEvent.js'			);
	this.include('js'   , 'SlSizer.js'			);
	this.include('js'   , 'SlLayerRelative.js'	);
	/* zz
	this.include('js'   , 'SlControl.js'			);
	this.include('js'   , 'SlGrid.js'				);
	this.include('js'   , 'SlInput.js'			);
	this.include('js'   , 'SlLabel.js'			);
	this.include('js'   , 'SlMenu.js'				);
	this.include('js'   , 'SlTree.js'				);
	this.include('js'   , 'SlWindow.js'			);
	*/

	// Solera. js. theme
	//zzthis.include('theme', 'Theme.js');

	// Solera. css. theme
	this.include('css'  , SlSys._gecko ? 'Solera_moz.css' : 'Solera.css'); // CrossBrowsing: gecko browsers special box model declaration
	/* zz
	this.include('css'  , 'SlControl.css'	);
	this.include('css'  , 'SlGrid.css'	);
	this.include('css'  , 'SlInput.css'	);
	this.include('css'  , 'SlLabel.css'	);
	this.include('css'  , 'SlMenu.css'	);
	this.include('css'  , 'SlTree.css'	);
	this.include('css'  , 'SlWindow.css'	);
	*/

	// Other libraries. js
	/*
	this.include('js'   , 'dhtmlx/dhtmlxTree/js/dhtmlXCommon.js');
	this.include('js'   , 'dhtmlx/dhtmlxTree/js/dhtmlXTree.js');
	this.include('js'   , 'dhtmlx/dhtmlxGrid/js/dhtmlXCommon.js');
	this.include('js'   , 'dhtmlx/dhtmlxGrid/js/dhtmlXGrid.js');
	this.include('js'   , 'dhtmlx/dhtmlxGrid/js/dhtmlXGridCell.js');
	*/

	// Other libraries. css
	/*
	this.include('css'  , 'dhtmlx/dhtmlxTree/css/dhtmlXTree.css');
	this.include('css'  , 'dhtmlx/dhtmlxGrid/css/dhtmlXGrid.css');
	*/
}

