﻿
/// <reference path="../DomElements.js" />

// Engine Version 1.0.1
/*****************************************************************************
Ajax library. Kevin Robinson 2006.
Bootstrapper (1 of 2) file containing language extensions. 
/*****************************************************************************/

// Namespace
//addNamespace("ajax.lang");    // Technically correct
//addNamespace("ajax.debug");
var ajax = {};                  // Doing it this way enables some intellisense IN THIS source file
ajax.lang = {};
ajax.debug = {};
ajax.version = "1.0.6";




// Changes
/*****************************************************************************
1.0.6 // Jan 08
Sundry changes to add Intellisense support. Currently a script must <reference> the References.js
script (in the root of ajax) to enable intellisense in VS 2008.
Added shortcut $ methods:
$getEvent -> ajax.lang.getEvent
$new      -> ajax.lang.safeNew
$call     -> ajax.lang.safeCall
$imports  -> ajax.lang.imports
$extends  -> ajax.lang.extends
Also added fillArc method to graphics (now we can do pie charts!!)
/*****************************************************************************
1.0.5 // Sept 07
Added support for MDI WinForms. Just call .addMdiChild(form) to a parent and set the parents content as the ParentNode.
Added "data" namespace and DataTable object.
Removed un-needed "window" statements from this extensions file (to enable server side use).
Removed reliance on window in addNamespace method (to enable server side use).
Changed the client app namespace to be just "app" to avoid clash with server side ASP "Application"
This version can now be included within a Server Side Javascript Library. Even Dynamic loading is working (see ajax.domain).
Also server clients can also use Server.MapPath to set the ajax & app domains (eg: ajax.domain = Server.MapPath("/") + "/";).
Also introduced ajax.lang.getType.
Also created AjaxComponent, currently supports a default .progressIndicator (Container)
/*****************************************************************************
1.0.4 
Treeview.js updated to support "requestParams" array property. These are passed on to the ContentLoader(s)
used by the treeview and facilitates passing more than just the key.
/*****************************************************************************
1.0.3
ColorPicker.js class added.
/*****************************************************************************
1.0.2
DatePicker.js .setPosition method to use getElementLayerOffset not getElementPosition.

/*****************************************************************************
1.0.1
Object Methods: Removed all object methods as although these don't clash with MS Ajax, MS Ajax has
reflection code that will baulk if it sees "properties of Object that are not numeric".

Any code that uses these object methods will now obviously break. I've run a check and no engine code does 
(it was a convienence for the client after all). The functionality offered can still be used, you must simply
pass the object in question to any of the following methods, ie:

ajax.lang.toJsonString(this, bIncludeFunctions);
ajax.lang.toXmlObject(this, bIncludeFunctions);
ajax.lang.toXmlString(this, bIncludeFunctions);
ajax.lang.getProperties(this);


/*****************************************************************************/

//-----------------------------------------------------------------------------
// ** Array stuff from Peter Belisis
if(Array.prototype.push && ([0].push(true)==true))
    Array.prototype.push = null;
if(Array.prototype.splice && typeof([0].splice(0))=="number")
    Array.prototype.splice = null;

if(!Array.prototype.shift) {
	function array_shift() {
		firstElement = this[0];
		this.reverse();
		this.length = Math.max(this.length-1,0);
		this.reverse();
		return firstElement;
	}
	Array.prototype.shift = array_shift;
}

if(!Array.prototype.unshift) {
	function array_unshift() {
		this.reverse();
		for(var i=arguments.length-1;i>=0;i--){
			this[this.length]=arguments[i]
		}
		this.reverse();
		return this.length
	}
	Array.prototype.unshift = array_unshift;
}

if(!Array.prototype.push) {
	function array_push() {
		for(var i=0;i<arguments.length;i++){
			this[this.length]=arguments[i]
		};
		return this.length;
	}
	Array.prototype.push = array_push;
}

if(!Array.prototype.pop) {
	function array_pop(){
	    lastElement = this[this.length-1];
		this.length = Math.max(this.length-1,0);
	    return lastElement;
	}

	Array.prototype.pop = array_pop;
}

if(!Array.prototype.splice) {
    function array_splice(ind,cnt){
        if(arguments.length == 0) return ind;
        if(typeof ind != "number") ind = 0;
        if(ind < 0) ind = Math.max(0,this.length + ind);
        if(ind > this.length) {
            if(arguments.length > 2) ind = this.length;
            else return [];
        }
        if(arguments.length < 2) cnt = this.length-ind;
        cnt = (typeof cnt == "number") ? Math.max(0,cnt) : 0;
        removeArray = this.slice(ind,ind+cnt);
        endArray = this.slice(ind+cnt);
        this.length = ind;
        for(var i=2;i<arguments.length;i++){
            this[this.length] = arguments[i];
        }
        for(var i=0;i<endArray.length;i++){
            this[this.length] = endArray[i];
        }
        return removeArray;
    }
	Array.prototype.splice = array_splice;
}

if (!Array.prototype.roll)
{
	function array_roll (direction) {
		
		direction = direction || false
		if ( !direction )
		{
			this.splice(this.length, 1, this[0])
			this.splice(0,1)
		} else
		{
			this.splice(0,0, this[this.length-1])
			this.splice(this.length-1,1)
		}
	}
	Array.prototype.roll = array_roll; 
}

//-----------------------------------------------------------------------------
// ** Array stuff from Dave Crane
/*
append to end of array, optionally checking for duplicates
*/
Array.prototype.append=function(obj,nodup){
  if (!(nodup && this.contains(obj))){
    this[this.length]=obj;
  }
}

/*
return index of element in the array
*/
Array.prototype.indexOf=function(obj){
  var result=-1;
  for (var i=0;i<this.length;i++){
    if (this[i]==obj){
      result=i;
      break;
    }
  }
  return result;
}

/*
return true if element is in the array
*/
Array.prototype.contains=function(obj){
  return (this.indexOf(obj)>=0);
}

/*
empty the array
*/
Array.prototype.clear=function(){
  this.length=0;
}

/*
insert element at given position in the array, bumping all
subsequent members up one index
*/
Array.prototype.insertAt=function(index,obj){
  this.splice(index,0,obj);
}

/*
remove element at given index
*/
Array.prototype.removeAt=function(index){
  this.splice(index,1);
}

/*
return index of element in the array
*/
Array.prototype.remove=function(obj){
  var index=this.indexOf(obj);
  if (index>=0){
    this.removeAt(index);
  }
}

//-----------------------------------------------------------------------------
// Object JSON stuff from Kevin Robinson
/*
Object.prototype.toJsonString = function(bIncludeFunctions)
{
    return ajax.lang.toJsonString(this, bIncludeFunctions);
}
Object.prototype.toXmlObject = function(bIncludeFunctions)
{
    return ajax.lang.toXmlObject(this, bIncludeFunctions);
}
Object.prototype.toXmlString = function(bIncludeFunctions)
{
    return ajax.lang.toXmlString(this, bIncludeFunctions);
}
Object.prototype.getProperties = function()
{
    return ajax.lang.getProperties(this);
}
*/
//-----------------------------------------------------------------------------
// String JSON stuff from Kevin Robinson
String.prototype.toJsonObject = function()
{
    return ajax.lang.toJsonObject(this);
}
String.prototype.xmlToJsonString = function()
{
    return ajax.lang.xmlToJsonString(this);
}
String.prototype.xmlToJsonObject = function()
{
    return ajax.lang.xmlToJsonObject(this);
}
String.prototype.isNumeric = function()
{
    return ajax.lang.isNumeric(this);
}
String.prototype.htmlEncode = function(display, tabs)
{
    return ajax.lang.htmlEncode(this, display, tabs);
}
String.prototype.trim = function()
{
    return ajax.lang.trim(this);
}

//-----------------------------------------------------------------------------
// Bind method for Functions (from an idea in the Prototype engine).
// This will return a function pointer with a context of that passed,
// Making it perfect for event handler pointers.
Function.prototype.bind = function(obj)
{///<returns type="Function"/>    
    var method = this;
    var temp   = function()
    {
        return method.apply(obj, arguments);
    };
    return temp;
}


$ = function(doc, sId)
{///<returns type="domElement" domElement="true"/>
    return doc.getElementById(sId);
}


//-----------------------------------------------------------------------------
// ########## Start of Ajax Lang Static methods
ajax.path           = "ajax";
ajax.domain         = ""; // leave this blank for default. When using this library on the server side, this can be filled in, eg "http://www.site.com/"
ajax.registeredApps = [];
// register a default application
addApplication("app", "");


ajax.lang.isNumeric = function(sText)
{    
    var validChars = "0123456789.";
    var isNumber=true;
    var char;

    for (var i = 0; i < sText.length && isNumber == true; i++) 
    { 
        char = sText.charAt(i); 
        if (validChars.indexOf(char) == -1)        
            isNumber = false;         
    }
    return isNumber;
}

//-----------------------------------------------------------------------------
ajax.lang.getType = function(obj)
{///<summary>Returns the string representing the basic type of the object passed (string, date, array, numeric, etc)</summary>
 ///<returns type="string"/>
    // special case for Array and date, otherwise use typeof
    var t   = "null";
    try
    {
        t   = (obj.constructor == Array) ? "array" : typeof(obj); 
        t       = (obj.constructor == Date) ? "date" : t;
    }
    catch(ex){}
    return t;
}

//-----------------------------------------------------------------------------
// Helper function to return a valid new XmlDocDom
ajax.lang.createXmlDoc = function()
{
    var xmlDoc = null;
    if (document.implementation && document.implementation.createDocument)
	    xmlDoc = document.implementation.createDocument("", "", null);	        
    else if (ActiveXObject)    
	    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");   	    
	return xmlDoc;
}

//-----------------------------------------------------------------------------
ajax.lang.loadXmlDoc = function(sXml)
{
    var xmlDoc = null;
    var w3c = false;
    try
    {
        w3c = document && document.implementation && document.implementation.createDocument;
    } catch(ex){}
    
    if (w3c)
    {
        //create a DOMParser
        var objDOMParser = new DOMParser();
            
        //create new document from string
        var xmlDoc = objDOMParser.parseFromString(sXml, "text/xml");
    }        	            
    else if (ActiveXObject)    
    {
	    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");   	    
	    xmlDoc.loadXML(sXml);
	}	
	return xmlDoc;
}

//-----------------------------------------------------------------------------
// Helper function to return an xml Header if needed
ajax.lang.getXmlHeader = function(sEncoding)
{
    var xmlHeader = "<?xml version=\"1.0\"";
        
    if (sEncoding)
        xmlHeader += " encoding=\"" + sEncoding + "\"";
    
    xmlHeader += "?>\n\r";    
    return xmlHeader;    
}

//-----------------------------------------------------------------------------
ajax.lang.getXmlInnerText = function(node) 
{    
    if (typeof node.textContent != 'undefined') 
    {
        return node.textContent;
    }
    else if (typeof node.innerText != 'undefined')
    {        
        return node.innerText;
    }
    else if (typeof node.text != 'undefined') 
    {
        return node.text;
    }
    else
    {
        switch (node.nodeType) 
        {
            case 3:
            case 4:
                return node.nodeValue;
                break;
            case 1:
            case 11:
                var innerText = '';
                for (var i = 0; i < node.childNodes.length; i++) 
                {
                    innerText += getInnerText(node.childNodes[i]);
                }
                return innerText;
                break;
            default:
                return '';
        }
    }    
}

//-----------------------------------------------------------------------------
// Takes an xmlDom node and returns the json string from it.
// REPLACED
ajax.lang.xmlNodeToJson = function(node)
{    
    var json = "";
    var name = node.nodeName;
    
    if (name == "#text") /// WTF?? some firefox crap...
        return "";
            
    var bArray = (node.getAttribute("type") == "array");
    var beginObj = (bArray) ? "[\n\r" : "{\n\r";
    var endObj   = (bArray) ? "\n\r]" : "\n\r}";
    
    // We can't convert an xml header node to json
    if (name == "xml")
        return "";
    
    // Get the "type" of the node (if it has one)
    var nodeType = node.getAttribute("type");        

    if (nodeType == "object" || nodeType == "array")
    {                   
        // This has sub elements so recurse through again
        if (name != "object")
            json += name + ": ";
            
        json += beginObj;
            
        for (var i = 0; i < node.childNodes.length; i++)
            json += ajax.lang.xmlNodeToJson(node.childNodes[i]);
        
        json += endObj;
    }        
    else if (nodeType == "date")
    {
        if (name != "object")
            json += name + ": ";
        
        json += "\"" + node.text + "\"";
    }
    else if (nodeType == "string")    
    {
        // Deal with quote marks in the string...
        var txtVal = ajax.lang.getXmlInnerText(node);        
        
        // We must be very carefull about newline characters in any string - we must double escape 
        txtVal = txtVal.replace(/\r/gi, "\\r");
        txtVal = txtVal.replace(/\n/gi, "\\n");
        txtVal = txtVal.replace(/\"/gi, '\\"');
        
        if (name != "object")
            json += name + ": ";
        
        json += "\"" + txtVal + "\"";
    }
    else if (nodeType == "function" && node.parentNode.getAttribute("type") == "array")
        // Oh dear..
        return "";
    else
    {
        if (name != "object")
            json += name + ": ";
        json += ajax.lang.getXmlInnerText(node);
    }           
    
    if (node.nextSibling != null)
        json += ",\n\r";
    
    return json;            
}

//-----------------------------------------------------------------------------
// Takes an xml Doc DOM and return the json string from it.
ajax.lang.xmlDocToJson = function(xmlDoc)
{      
    var sItems = "";
    for (var i = 0; i < xmlDoc.childNodes.length; i++)
    {
        var node = xmlDoc.childNodes[i];
        
        if (sItems != "")
            sItems += ",";
  
        sItems += ajax.lang.xmlNodeToJson(node);

    }
    return sItems;
}

//-----------------------------------------------------------------------------
// (String prototype) Takes an xml string and returns the json string from it.
ajax.lang.xmlToJsonString = function(string)
{
    var xmlDoc = ajax.lang.loadXmlDoc(string);
    return ajax.lang.xmlDocToJson(xmlDoc);    
}

//-----------------------------------------------------------------------------
// (String prototype) Takes an xml string and converts it to a javascript object
ajax.lang.xmlToJsonObject = function(string)
{
    // Convert the xml string into json
    var json = ajax.lang.xmlToJsonString(string);
    
    var obj = null;
    try
    {
        obj = eval("(" + json + ")");
    }
    catch(ex) {}
    return obj;
}

//-----------------------------------------------------------------------------
// (OBJECT prototype) Takes a javascript object and converts it to an xml Doc DOM object
ajax.lang.toXmlObject = function(obj, bIncludeFunctions)
{
    var xmlString = ajax.lang.toXmlString(obj, bIncludeFunctions);
    var xmlDoc = ajax.lang.loadXmlDoc(xmlString);    
    return xmlDoc;
}

//-----------------------------------------------------------------------------
// (OBJECT prototype) Takes a javascript object and converts it to an xml string
ajax.lang.toXmlString  = function(obj, bIncludeFunctions, sName)
{
    bIncludeFunctions = (typeof(bIncludeFunctions) != "boolean") ? false : bIncludeFunctions;    
    sName = (typeof(sName) == "undefined" || sName == null) ? "object" : sName
    var objType = (obj.constructor == Array) ? "array" : typeof(obj);    
    
    // We kow its an object - just what TYPE.
    var beginTag = "<" + sName + " type=\"" + objType + "\">\n\r";
    var endTag   = "\n\r</" + sName + ">";
        
    var sItems = "";
    
    // Loop through all properties of this object
    for (var prop in obj)
    {
        var type    = (obj[prop].constructor == Array) ? "array" : typeof(obj[prop]); 
        type        = (obj[prop].constructor == Date) ? "date" : type;
                     
        var tab     = "    ";
        var tagName = prop;
        
        // if the type is a number, then it's part of an array so must be object.
        if (tagName.isNumeric())
            tagName = "object";
                    
        // Skip Functions?
        if (type == "function" && !bIncludeFunctions)
            continue;                    
        
        if (type == "string")
        {
            var s = obj[prop];
            
            // Deal with the nasty chars in the string...            
            s = s.replace(/\&/ig, "&amp;");
            s = s.replace(/\</ig, "&lt;");
            s = s.replace(/\>/ig, "&gt;");            
            s = s.replace(/\'/ig, "&apos;");
            s = s.replace(/\"/ig, "&quot;");            
                       
            sItems += tab + "<" + tagName + " type=\"" + type + "\">" + s + "</" + tagName + ">\n\r";
        }        
        else if (type == "object")                
                sItems += ajax.lang.toXmlString(obj[prop], bIncludeFunctions, tagName);        
        else if (type == "function")
        {
            // Function objects need to be CDATA         
            sItems += tab + "<" + tagName + " type=\"" + type + "\"><![CDATA[" + obj[prop] + "]]>" + "</" + tagName + ">\n\r";
        }   
        else
            // This is numeric or boolean etc...
            sItems += tab + "<" + tagName + " type=\"" + type + "\">" + obj[prop] + "</" + tagName + ">\n\r";           
    }
    var xml = beginTag + sItems + endTag;
    return xml;
}

//-----------------------------------------------------------------------------
// (Object Prototype) takes a javascript objects and returns a JSON string
ajax.lang.toJsonString = function(obj, bIncludeFunctions, bIncludeObjects)
{    
    bIncludeFunctions = (typeof(bIncludeFunctions) != "boolean") ? false : bIncludeFunctions; // default false
    bIncludeObjects   = (typeof(bIncludeObjects) != "boolean") ? true : bIncludeObjects; // default true
    var json = "";
    var bArray = (obj && obj.constructor == Array);
    var bDate  = (obj && obj.constructor == Date);
    var beginTag = (bArray) ? "[\n\r" : "{\n\r";
    var endTag   = (bArray) ? "\n\r]" : "\n\r}";
    var sItems   = "";
    for (var prop in obj)
    {
        var type = typeof(obj[prop])
        
        // Skip functons if told to or if we have an array?
        if (type == "function")
            if (!bIncludeFunctions || bArray)
                continue;
        
        if (sItems != "")
            sItems += ",\n\r";
        
        if (!bArray)
            sItems += prop + ": ";
        
        if (obj[prop] && obj[prop].constructor == Date)
            sItems += "\"" + obj[prop] + "\"";
        else if (type == "string")
        {
            // Deal with quote marks in the string...
            var txtVal =  obj[prop];
            
            // We must be very carefull about newline characters in any string - we must double escape 
            txtVal = txtVal.replace(/\r/gi, "\\r");
            txtVal = txtVal.replace(/\n/gi, "\\n");
            txtVal = txtVal.replace(/\"/gi, '\\"');
            
            sItems += "\"" + txtVal + "\"";
            
        }
        else if (type == "object")     
        {       
            if (bIncludeObjects)
            {
                // Could be a non ajax object so use the generic json creator
                sItems += ajax.lang.toJsonString(obj[prop], bIncludeFunctions);
            }
            else
            {
                sItems += "null";
            }
        }
        else
            sItems += obj[prop];
    }
    json = beginTag + sItems + endTag; 
    
    return json;        
}

//-----------------------------------------------------------------------------
// (String Prototype) takes a JSON string and converts to a javascript object.
ajax.lang.toJsonObject = function(string)
{
    var ret = null;
    try
    {
        ret = eval("(" + string.toString() + ")");
    }catch(ex){}        
    return ret;   
}

//-----------------------------------------------------------------------------
//(String)  source   The text to be encoded.
//(boolean) display   The output is intended for display.
//(integer) tabs      The number of spaces to expand tabs to. 
ajax.lang.htmlEncode = function(source, display, tabs)
{
    // Only do this for strings and dates, otherwise return the original
    var sourceType = ajax.lang.getType(source);    
    if (sourceType != "string" && sourceType != "date")
        return source;
        
	function special(source)
	{
		var result = '';
		for (var i = 0; i < source.length; i++)
		{
			var c = source.charAt(i);
			if (c < ' ' || c > '~')
			{
				c = '&#' + c.charCodeAt() + ';';
			}
			result += c;
		}
		return result;
	}
	
	function format(source)
	{
		// Use only integer part of tabs, and default to 4
		tabs = (tabs >= 0) ? Math.floor(tabs) : 4;
		
		// split along line breaks
		var lines = source.split(/\r\n|\r|\n/);
		
		// expand tabs
		for (var i = 0; i < lines.length; i++)
		{
			var line = lines[i];
			var newLine = '';
			for (var p = 0; p < line.length; p++)
			{
				var c = line.charAt(p);
				if (c === '\t')
				{
					var spaces = tabs - (newLine.length % tabs);
					for (var s = 0; s < spaces; s++)
					{
						newLine += ' ';
					}
				}
				else
				{
					newLine += c;
				}
			}
			// If a line starts or ends with a space, it evaporates in html
			// unless it's an nbsp.
			newLine = newLine.replace(/(^ )|( $)/g, '&nbsp;');
			lines[i] = newLine;
		}
		
		// re-join lines
		var result = lines.join('<br />');
		
		// break up contiguous blocks of spaces with non-breaking spaces
		result = result.replace(/  /g, ' &nbsp;');
		
		// tada!
		return result;
	}

	var result = source;
	
	// ampersands (&)
	result = result.replace(/\&/g,'&amp;');

	// less-thans (<)
	result = result.replace(/\</g,'&lt;');

	// greater-thans (>)
	result = result.replace(/\>/g,'&gt;');
	
	if (display)
	{
		// format for display
		result = format(result);
	}
	else
	{
		// Replace quotes if it isn't for display,
		// since it's probably going in an html attribute.
		result = result.replace(new RegExp('"','g'), '&quot;');
	}

	// special characters
	result = special(result);
	
	// tada!
	return result;
}

//-----------------------------------------------------------------------------
ajax.lang.trim = function(str)
{
    // Force str to become a string...then use string replace function
    return ("" + str + "").replace(/^\s+|\s+$/g, '');   
}







//-----------------------------------------------------------------------------
ajax.debug.defaultOutput    = 
{
    writeLn: function(s){this.log += s + "\n"},
    clear: function(){this.log = ""},
    log: ""
};
ajax.debug.Output    = ajax.debug.defaultOutput;
ajax.debug.writeToNewWindow = function(sText)
{
    try
    {
        var win = window.open("about:blank");
        win.document.open();
        win.document.write(sText);
        win.document.close();
    }
    catch(ex)
    {
        alert("Unable to open window (blocked?). " + ex.message);
    }
    
}

//-----------------------------------------------------------------------------
ajax.lang.safeDestroy = function(ele)
{
    if (ele)
        if (ele.outerHTML)
		    ele.outerHTML = "";
		else if (ele.parentNode)
            ele.parentNode.removeChild(ele);        
	ele = null;	
	return ele;	
};


//-----------------------------------------------------------------------------
// This helper method gets the path to the Class File from the class name.
// It uses a rule, that the first UPPER case letter denotes the class file.
ajax.lang.getClassPath = function(sClassName, sExt, sDelimeter)
{
    sExt        = ( typeof(sExt) == "undefined" ) ? ".js" : sExt;
    sDelimiter  = ( typeof(sDelimiter) == "undefined" ) ? "/" : sDelimiter;
    
    var arr = sClassName.split('.');
    var sPath = "";
    for (var i = 0; i < arr.length; i++)
    {
        var sName = arr[i];
        var firstLetter = arr[i].substring(0, 1);
        
        if (sPath != "")
            sPath += sDelimiter;
        
        if (sName == "ajax")
            sPath += ajax.path;
        else if (ajax.registeredApps.contains(sName))
            sPath += eval(sName).path;
        else
            sPath += sName;
        
        /*
        if (sName == "ajax")
            sPath += ajax.path;
        else if (sName == "app")
            sPath += app.path;
        else
            sPath += sName; 
        */
            
        // If this is the first part with a capital letter at the start
        // Then THIS is the class file to return
        if (firstLetter == firstLetter.toUpperCase())
            break;         
    }
    // Add the js at the end
    sPath += sExt;
    return sPath;
};

//-----------------------------------------------------------------------------
ajax.lang.getClassName = function(sName)
{
    return sName.replace(/\./ig, "-");
}

//-----------------------------------------------------------------------------
ajax.lang.safeNew = function(stringClassName, params)
{///<summary>Creates an instance of any class. Use as factory, then call .parse (for intellisense) for dynamic class loading.</summary>
    
    // Copy arguments into one of our new extended Arrays
    var args = new Array();
    for (var i = 0; i < arguments.length; i++)    
        args[i] = arguments[i];
    args.shift();  
        
    var className = arguments[0];
    // Ensure that the ClassName exists.
    ajax.lang.imports(className);
    var classObject = ajax.lang.toJsonObject(className);// eval(className);
    // Return a new instance of what they wanted, allowing for 16 arguments!!! Needs work?
    // to be passed to  the constuctor    
    return new classObject(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
};
var $new = ajax.lang.safeNew;

//-----------------------------------------------------------------------------
ajax.lang.safeCall = function(stringClassName, stringMethodName, params)
{///<summary>Calls a static class method</summary>
    var args = new Array();
    for (var i = 0; i < arguments.length; i++)
        args[i] = arguments[i];
    args.shift();
    args.shift();
    
    var className = arguments[0];
    var methodName= arguments[1];
    
    ajax.lang.imports(className);
    var classObject = eval(className);
    // Return the result of calling the method in question.
    return classObject[methodName](args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
};
var $call = ajax.lang.safeCall;

//-----------------------------------------------------------------------------
ajax.lang.imports = function(classNamesParams)
{
    // for clients wanting to know the results for each className passed in
    // we will tell them true (1) or false (0) depending on if it ends up in existance
    var results = new Array();
    
    for (var i = 0; i < arguments.length; i++)
    {
        // Does this object definition exist?
        var className   = arguments[i];
        var classObject = null;
        try
        {
            classObject = eval(className);
        }
        catch(ex){}
        
        // If not then we must attempt to load it
        if (classObject == null || typeof(classObject) == "undefined")
        {
            // Does not (yet) exist
            var classPath = ajax.lang.getClassPath(className);
            try
            {
                ajax.debug.Output.writeLn("Class " + className + " does not yet exist\nloading it now from " + classPath);
                // Load it sync fashion
                var cl = new ajax.net.ContentLoader(this, function(){}, null, ajax.domain + classPath, "GET", null, false);
                var req = cl.sendRequest();
                // Execute the package                
                classObject = eval(req.responseText);
                ajax.debug.Output.writeLn(className + " loaded OK.\n");
                results[i] = true;
            }
            catch(ex)
            {
                results[i] = false;
                var sErr = "";
                for (var j in ex)
                    sErr += j + ": " + ex[j] + "\n";
                ajax.debug.Output.writeLn("Unable to load " + className + " from " + ajax.domain + classPath + " because\n\n" + sErr);
            }
        }
        else
            // Exists already
            results[i] = true;     
                          
    }
    // return the array to the client, all SHOULD be true
    return results;
};
var $imports = ajax.lang.imports;


//

//-----------------------------------------------------------------------------
ajax.lang.extend = function(subClass, baseClassName)
{///<summary>This allows a class to INHERIT from another base class</summary>
    // Ensure that the base class exists
    ajax.lang.imports(baseClassName);        
    var baseClass = eval(baseClassName);    
    
    // Create a "dummy" class to avoid calling the base
    // Class constructor with NO Params!
    function inheritance(){};
    inheritance.prototype           = baseClass.prototype;
    
    // We can now call the dummy - no problem
    subClass.prototype              = new inheritance();
  
    // And specify its constructor to avoid confusion
    subClass.prototype.constructor  = subClass;
    // And store away refrences to the base constructor and the base class prototype itself
    subClass.superConstructor       = baseClass;
    subClass.superClass             = baseClass.prototype;
}
var $extend = ajax.lang.extend;

//-----------------------------------------------------------------------------
   
ajax.lang.isInstanceOf = function(obj, className)
{///<summary>Method to determine if one class is of a partucular type.</summary>
 ///<returns type="Boolean">Returns true if the object passed INHERITS from the className passed.</returns>
 
    if (!obj)
        return false;
        
    // Evaluate the className we are to compare to into a class definition
    var classDef = ajax.lang.toJsonObject(className);
    if (!classDef) // Class is not defined so passed object cannot possibly inherit from it as it is not even loaded.
        return false;
    
    // attempt to get a handle to the constructor of the object we are passed
    var con = obj.constructor;
    if (!con)
        return false; // Object does not have a constructor so does not inherit from anything.
    
    // Assume the negative    
    var ret = false;
    while (con)
    {
        if (con == classDef)
            ret = true;
        con = con.superConstructor; // Step up the inheritance chain
    }        
    return ret;      
}

//-----------------------------------------------------------------------------
// This allows a class to DECLARE THAT IT SUPPORTS a particular INTERFACE
ajax.lang.supports = function(subClass, baseClassName)
{    
    // Ensure that the base class (and interface definition) exists
    ajax.lang.imports(baseClassName);
    var baseClass = eval(baseClassName);
    
    // copy over the Interface (properties) to the prototype of the subClass
    ajax.lang.copyInterface(subClass, baseClass);
}

//-----------------------------------------------------------------------------
ajax.lang.addNamespace = addNamespace;
function addNamespace(sName)
{        
    var arr = sName.split(".");
    var sSpace = "";
    for (var i = 0; i < arr.length; i++)
    {
        sSpace += (i == 0) ? arr[i] : "." + arr[i];
                
        try
        {
            if (typeof(eval(sSpace)) == "undefined") 
                eval(sSpace + " = {}");        
        }
        catch(ex)
        {
            eval(sSpace + " = {}");
        }
    }
}
//-----------------------------------------------------------------------------
ajax.lang.addApplication = addApplication;
function addApplication(lowerCaseName, path)
{
    // Add a namespace for this app
    addNamespace(lowerCaseName);
    // set the path
    eval(lowerCaseName).path = path;
    // add to the list of applications (so namespace can transform to path).
    ajax.registeredApps.push(lowerCaseName);
}
//-----------------------------------------------------------------------------



//-----------------------------------------------------------------------------
// This is an easy wrapper to get an event router from ANY object, however derived
ajax.lang.getEvent = function(wind, obj, eventType)
{
    ///<summary>Returns the existing or new event router (delegate) for the event name of the given object</summary>
    ///<returns type="ajax.events.EventRouter"></returns>
    ///<param name="wind" type="Window">A window handle</param>
    ///<param name="obj" type="Object">The object instance to publishing the event we want</param>
    ///<param name="eventType" type="String">The string name of the event we want</param>
    var ret = ajax.lang.safeCall("ajax.events.EventRouter", "getEvent", wind, obj, eventType);
    return ret;
}
var $getEvent = ajax.lang.getEvent;


//-----------------------------------------------------------------------------
// Interface support
ajax.lang.nullInterfaceFunction = function(sInterfaceClass)
{
    ajax.debug.Output.writeLn(this + " declares that it supports the " + sInterfaceClass + " interface but does not implement all methods.");
}

ajax.lang.copyInterface = function(targetClass, interfaceClass)
{    
    var propString = "";
    for (var prop in interfaceClass)    
        // Only if not already exist, pop in a debug function
        if (!targetClass.prototype[prop])       
            targetClass.prototype[prop] = function(){ajax.lang.nullInterfaceFunction.call(this, interfaceClass.toString())};
     
}


//-----------------------------------------------------------------------------
ajax.lang.copyProperties = function(target, style, bPreserve, bIncludeFunctions)
{
    for (var prop in style)
        // Only if not preserved or does not already exist.
        if (!bPreserve || !target[prop])
        {
            if ( (typeof(style[prop]) == "function") && !bIncludeFunctions )
                continue;
            if ( (typeof(style[prop]) == "object") )
                ajax.lang.copyProperties(target[prop], style[prop], bPreserve, bIncludeFunctions)
            else                    
                target[prop] = style[prop];
        }                
}

//-----------------------------------------------------------------------------
// Helper function to return an array of properties from an object 
//(useful for iterating without the Object-level enhancements appearing as functions)
ajax.lang.getProperties = function(obj)
{
    var properties = new Array();    
    for (var property in obj)
    {
        var prop = obj[property];
        if (typeof(prop) == "function")
            continue;
        properties[properties.length] = prop;
    }
    return properties;
}

//-----------------------------------------------------------------------------
// A library here for simple cross browser stuff...?
ajax.lang.getDocumentWindow = function(doc)
{///<returns type="domWindow"/>
    if (!doc) // allow parameterless constructors for components.
        return window; // Pretty good guess...
        
	if (doc.parentWindow)
		return doc.parentWindow;
	else if (doc.defaultView)
		return doc.defaultView;
		
	return null;
}

//-----------------------------------------------------------------------------
ajax.lang.getQueryParams = function(doc)
{
    var E=doc.location.search;
    var F=E.substring(1,E.length).split('&');
    var AS=new Array();
    for(var i=0; i < F.length; i++)
    {
        var I=F[i].split('=');
        AS[I[0]]=I[1]
    }
    return AS;
}

//-----------------------------------------------------------------------------
ajax.lang.multiDimensionalArray = function(iRows,iCols) 
{ 
   var a = new Array(iRows); 
   for (var i=0; i < iRows; i++) 
   { 
       a[i] = new Array(iCols); 
       for (var j=0; j < iCols; j++) 
       { 
           a[i][j] = 0; 
       } 
   } 
   return(a); 
}

//-----------------------------------------------------------------------------
ajax.lang.activatePlugins = function(doc, tagNames)
{    
    var ret = 0; // Return # of replaced items
    // return if not ie or no tagNames were passed.
    if (!doc.all || !tagNames || !tagNames.length)
        return;
        
    // An array of collections (multiD array)
    var tagCollections = [];
    for (var i = 0; i < tagNames.length; i++)   
        tagCollections[tagCollections.length] = doc.getElementsByTagName(tagNames[i]);
        
    // Loop through array of collections
    for (var col = 0; col < tagCollections.length; col++)
    {    
        var collection = tagCollections[col];
        // Loop through this collection
        for (var i = 0; i < collection.length; i++)
        {
            var node = collection[i];
            var html = node.outerHTML;
            // Create new span and inserted it just before the object to be replaced.
            var span = doc.createElement("span");            
            node.parentNode.insertBefore(span, node);
            // remove the original node
            node.parentNode.removeChild(node);
            // set the deleted nodes original html value (string) as the inner HTML value of the new span tag
            span.innerHTML = html;
            ret++;
        }
    }   
    return ret;
}

var $getDesignMode = function()
{///<summary>THis method always returns false at runtime. Use this method to coax intellisense into doing the right thing.</summary>
 ///<returns type="boolean"/>
    return false;
}

