/**
 * GSI Global API Library
 * Requires prototype.js
 * @author Christian Bradley - bradleyc@gsicommerce.com
 * @version 0.9
 */
//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	GSI Global

/**
 * GSI NameSpace
 * @constructor
 */
	var GSI = function() {};

/** The base path for loading scripts @type String */
	GSI.basePath = "/common/";

/** An Array of core classes for GSI framework
 * @type Array
 * @private
 */
	GSI.coreClasses =
	[
		"GSI.Event"  ,"GSI.NameSpace"  ,"GSI.Class"  ,"GSI.Enumerable"   ,
		"GSI.Scripts","GSI.Application","GSI.Browser","GSI.StatusMessage",
    "GSI.Widgets","GSI.Mouse"
	];

/**
 * Initialize the Global Library
 * @private
 */
	GSI.initialize = function()
	{
	//	Perform window onload methods
		Event.observe( window, "load", GSI.onLoad.bind(this) );
		this.loadCore();
	};

/**
 * Load the base scripts
 */
	GSI.loadCore = function()
	{
		this.loadScripts( this.coreClasses, this.basePath );
	};

/**
 * Handle the onload event
 * Called from GSI.initialize.
 * @param {Object} evt	The window Event object
 * @private
 */
	GSI.onLoad = function( evt )
	{
		GSI.Browser.initialize();
		GSI.Application.loadBuffer();
		GSI.StatusMessage.setVisibility( false );
    GSI.Widgets.parseWidgets();
    GSI.Mouse.initialize();
		Element.stopObserving( window, "load", GSI.onLoad );
	};

/**
 * Load a script into the DOM - non-asynch method
 * @param {String} url		The url of the script
 */
  GSI.loadScript = function( url )
	{
		document.write('<script type="text/javascript" src="'+url+'"></script>');
	};

/**
 * Load multiple scripts into the DOM - non-asynch method
 * @param {Array} urls		The urls of the scripts to load
 * @param {String} path		The path to add before each script name (optional).
 */
  GSI.loadScripts = function( urls, path )
	{
		var i,len;
		for( i=0,len=urls.length;i<len;i++ )
		{
			var url = urls[i];
			var ext = url.split(".").pop();
			if( ext !== "js" ) { url += ".js"; }
			this.loadScript( ( path || "" ) + url );
		}
	};

//________________________________________________________________
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
//	Utility functions

/**
 * Create an Element (advanced)
 * @param {String} 	tag							the tagname to create
 * @param {String} 	[elId]					the ID of the element
 * @param {String} 	[cssClass]			the CSS class to assign
 * @param {String} 	[inner]					the innerHTML value to assign
 * @param {Element} [parentEl]			the parent of the element
 * @param {Array} 	[childrenArr]		array of children to append to the element
 * @param {Array}		[props]					an array of properties, in name/value pairs [ "type", "hidden" ]
 * @param {Function} [beforeAdd]		a method to call on the element before adding to DOM
 * @return A reference to the element or null
 * @type Element
 */
	GSI.createElement = function( tag, elId, cssClass, inner, parentEl, childrenArr, props, beforeAdd )
	{
		var el;
		var i,len,propVal,propKey;

		if( tag === undefined ){ throw("Please pass a tag name"); }
		if( $(elId) ){ return $(elId );}

	//	Convert the array to an object
		if( props && props.length && props.length > 0 )
		{
			var newProps = {};
			for(i=0,len=props.length; i<len; i+=2 )
			{
				newProps[ props[i] ] = props[i+1];
			}
			props = newProps;
		}

	//	Check for "type" and "name" values
		if( props && ( props.type || props.name ) )
		{
		//	Try creating the tag "IE" style
			try {
				var strTag = '<';
				if( props.type ) { strTag += ' type="' + props.type + '" '; }
				if( props.name ) { strTag += ' name="' + props.name + '" '; }
				strTag += ' >';
				el = document.createElement( strTag );
			} catch(e) {}

		}

	//	Check for the node existence, if it doesn't exist, try normal method
	//	This also gets called if we didn't have props.type or props.name anyway
		if( !el || el.nodeName.toUpperCase() != tag.toUpperCase() )
		{
			el = document.createElement( tag );
			if( props && props.type ){ el.type = props.type; }
			if( props && props.name ){ el.name = props.name; }
		}

	//	Loop through the other properties and set them
		if( props )
		{
			for( key in props )
			{
				if( typeof props[key] == "function"){ continue; }
				if( key == "type" || key == "name" ){ continue; }

				el[key] = props[key];
			}
		}

	//	Set other default properties here
		if( elId !== undefined && elId !== false ) { el.id = elId; }
		if( cssClass !== undefined && cssClass !== false ) { el.className = cssClass; }
		if( inner !== undefined && inner !== false ) { el.innerHTML = inner; }
		if( parentEl !== undefined && parentEl !== false ) { parentEl.appendChild( el ); }
		if( childrenArr !== undefined && childrenArr !== false )
		{
			for( i=0,len=childrenArr.length; i<len; i++ )
			{
				el.appendChild( childrenArr[i] );
			}
		}

		return $(el);
	};
	/** Shortcut to GSI.createElement */
	GSI.$e = GSI.createElement;

/**
 * Adds an unique identifier (id) property if one doesn't exist
 * @param {Element} el			An HTML element to fix
 * @param {String} pre			A string prefix for the id
 * @return the element passed in (now has "id" attribute")
 * @type Element
 */
	GSI.fixElementId = function( el, pre  )
	{
		if( el.id === undefined || el.id.length == 0 )
		{
			el.id = GSI.uId( pre );
		}
		return el;
	}

/**
 * Create an unique identifier
 * @param {String} pre 	Prefix for the string
 * @return A new unique identifier
 * @type String
 */
	GSI.uId = function(pre)
	{
		return ( pre || "" ) + "u" + new Date().getTime() + "-" + parseInt(10000*Math.random())
	}

/**
 * Fixes a number to minum or maximum values if out of the boundaries passed
 * @param {Number} n		The number to fix
 * @param {Number} min	The minimum value for the number
 * @param {Number} max	The maximum value for the number
 * @return The fixed number
 * @type Number
 */
	GSI.minMax = function(n, min, max)
	{
		if( n < min ) return min;
		if( n > max ) return max;
		return n;
	}

/**
 * Load a stylesheet
 * @param {String} url						The url of the stylesheet to load
 * @param {Boolean} useDOM				Use DOM manipulation instead of document.write
 */
	GSI.loadStyleSheet = function( url, useDOM )
	{
		if( !useDOM )
		{
			document.write('<link rel="stylesheet" type="text/css" href="' + url + '">');
			return;
		}

		var cssEl = GSI.$e("link",false,false,false,document.getElementsByTagName("head")[0],false );
		cssEl.rel = "stylesheet";
		cssEl.href = url;
		cssEl.type = "text/css";
	}


//	Initialize the GSI framework
	GSI.initialize();
