/* Ajax Library
 *
 * Nima Khoshini
 * Last Updated: April 3, 2006
 *
 */

/**
 * 
 * Ajax Object
 * Used to create a remote scripting object to fetch data asyncronously or synchronously
 *
 * Properties:
 *    WebURL - The URL to connect. This property is of type 'AjaxURL'.
 *    Callback - Specifies a function that will get called once a connection has been opened an a result has been received
 *    ReturnedResults - The complete data returned from the call.
 *    ResultSet - An object of type AjaxResultSet that contains the returned dataset
 */

/*
 * Constructor
 */
var AjaxObject = function(url)
{
    this.WebURL          = new AjaxURL(url);
    this.Callback        = null;
    this.ReturnedResults = null;
    
    this.ResultSet       = null;
}

/*
 * Open() - Opens the connection to the URL. 
 * If the Callback Property is defined, the underlying protocol will call the Callback function
 * once a result is received.
 */
AjaxObject.prototype.Open = function()
{
	if (null == this.XMLHttp)
		this.XMLHttp = this.GetXmlHttp();
	
	this.WebURL.AddRandom();
	
	if (null != this.Callback)
	{
		this.XMLHttp.onreadystatechange = this.Callback;
		this.XMLHttp.open("GET", this.WebURL.FullURL, true);
		this.SendXML();
	}
	else
	{
		this.XMLHttp.open("GET", this.WebURL.FullURL, false);
		this.SendXML();
		
		this.ReturnedResults = this.XMLHttp.responseText;
		this.PrepareResults(this.XMLHttp.responseText);
	}
}

/*
 * GetXmlHttp() - Private - Gets the XmlHttp object for connection
 */
AjaxObject.prototype.GetXmlHttp = function()
{
	var ret = null;
	if (window.XMLHttpRequest)
    {
    	try
    	{
			ret = new XMLHttpRequest();
        }
        catch(e)
        {
          	ret = null;
        }
    }
    else if (window.ActiveXObject)
    {
        try
        {
            ret = new ActiveXObject("Msxml2.XMLHTTP");
      	}
        catch(e)
        {
            try
            {
          		ret = new ActiveXObject("Microsoft.XMLHTTP");
        	}
            catch(e)
            {
          		ret = null;
        	}
		}
    }
    
	return ret;
}

/*
 * Close() - Closes and de-allocates the Ajax Object 
 */
AjaxObject.prototype.Close = function()
{ 
	if (null != this.XMLHttp)
		this.XMLHttp = null;
}

/*
 * SendXML() - Private - Sends the command
 */
AjaxObject.prototype.SendXML = function()
{ 
	if (document.all)
		this.XMLHttp.send();
	else
		this.XMLHttp.send(null);
}

/*
 * HasResults() - Determines whether the call returned valid data.
 * Returns - True - If the call returned valid data. False otherwise
 */
AjaxObject.prototype.HasResults = function()
{
	return null != this.ReturnedResults && null != this.ResultSet && this.ResultSet.HasResults();
}

/*
 * PrepareResults() - Private - Initializes the dataset
 */
AjaxObject.prototype.PrepareResults = function()
{
    if (null == this.ReturnedResults)
        return;
        
    //since we are not using XML at the time, remove the <?xml tag at the beginning of the result set
    var results = this.ReturnedResults;
    
    var xmlTagIndex = results.indexOf("?>");
    if (xmlTagIndex > 0)
    {
        results = results.substring(xmlTagIndex+2);
        this.ResultSet = new AjaxResultSet(results);
    }
    else
        this.ResultSet = null; 
}

/**
 * 
 * AjaxResultSet Object
 * Used to retrieve data from an Ajax Object.
 */
var AjaxResultSet = function(setToParse)
{
    /* initialize the properties
     */
    this.ResultsArray = new Array();
    this.ResultKeys   = new Array();
    this.ResultValues = new Array();
    this.CurItemIndex = 0;
    
    var delimItem  = "^^";
    var delimItem2 = "~~";
    var delimLine  = "@!";
    
    var res = setToParse.split(delimLine);
	var i=0;
	for (i=0; i<res.length; ++i)
	{
	    if (null == res[i] || TrimString(res[i]) == '')
	        continue;
	        
	    this.ResultsArray[i] = new Array();
	    var items = res[i].split(delimItem2);
	    
	    var j=0;
	    for (j=0; j<items.length; ++j)
	    {
	        var vals = items[j].split(delimItem);
	        var itemName  = TrimString(vals[0]);
	        var itemValue = (vals.length == 1) ? "" : TrimString(vals[1]);
	        
	        if (0 == i && itemName.length > 0)
	        {
				this.ResultKeys[this.ResultKeys.length++] = itemName;
				this.ResultValues[this.ResultValues.length++] = itemValue;
			}
	        	        
	        this.ResultsArray[i][itemName] = itemValue;
	    }
	}
}

/*
 * HasResults() - Determines whether the call returned valid data.
 * Returns - True - If the call returned valid data. False otherwise
 */
AjaxResultSet.prototype.HasResults = function()
{
	return null != this.ResultsArray && this.ResultsArray.length > 0;
}

/*
 * NextItem() - Advances the result set to the next item. Returns the next item, if existant, in the result set
 */
AjaxResultSet.prototype.NextItem = function()
{
    if (null ==  this.ResultsArray || 0 == this.ResultsArray.count || this.CurItemIndex > this.ResultsArray.count)
        return null;
        
    return this.ResultsArray[this.CurItemIndex++]
}

/*
 * LastItem() - Retrieves teh previous item in the result set.
 */
AjaxResultSet.prototype.LastItem = function()
{
    if (null ==  this.ResultsArray || 0 == this.ResultsArray.count)
        return null;
        
    var ret = this.ResultsArray[this.CurItemIndex];
    if (this.CurItemIndex > 0)
        --this.CurItemIndex;
        
    return ret;
}

/*
 * ResetPosition() - Resets the position of the result set enumerator.
 */
AjaxResultSet.prototype.ResetPosition = function()
{
    this.CurItemIndex = 0;
}

/*
 * GetKeys() - Gets the keys of the first item returned in the result set. The returned result is an array of strings containing the keys.
 */
AjaxResultSet.prototype.GetKeys = function()
{
    return this.ResultKeys;
}

/*
 * GetValues() - Gets the values of the first item returned in the result set. The returned result is an array containing the values.
 */
AjaxResultSet.prototype.GetValues = function()
{
    return this.ResultValues;
}

/*
 * GetFirstResult() - Returns the first result in the set.
 */
AjaxResultSet.prototype.GetFirstResult = function()
{
    if (null ==  this.ResultsArray || 0 == this.ResultsArray.count)
        return null;
        
    return this.ResultsArray[0];
}

/*
 * GetLastResult() - Returns the last result in the set.
 */
AjaxResultSet.prototype.GetLastResult = function()
{
    if (null ==  this.ResultsArray || 0 == this.ResultsArray.count)
        return null;
        
    return this.ResultsArray[this.ResultsArray.length-1];
}

/**
 * 
 * AjaxURL Object
 * Used to create a URL. AjaxURL manages escaping of characters and proper formatting of the URL string.
 *
 * Properties:
 *    FullURL - The complete URL path.
 */
 
/*
 * Constructor - Creates an AjaxURL object.
 *
 * Paramaters:
 *    url - the initial URL
 *    replacePound - specifies whether or not to trim pound characters found on the end of the URL string (ex: http://localhost/test.aspx#)
 */
var AjaxURL = function(url, replacePound)
{
    this.FullURL = url;
    
    if (true == replacePound)
        this.FullURL = this.FullURL.replace("#", '');
}

/*
 * AddParam(name, val, replaceIfExists) - Adds a paramater or query string to the URL
 *
 * Paramaters:
 *    name - the name of the query string or paramater
 *    val - the value
 *    replaceIfExists - determines whether or not to replace the value of paramater if it already exists in the URL. By default, this paramater is set to false.
 */
AjaxURL.prototype.AddParam = function(name, val, replaceIfExists)
{
    if (null == this.FullURL)
        this.FullURL = "";
        
    if (this.FullURL.length > 0)
    {
        if (this.FullURL.indexOf('?') == -1)
            this.FullURL += "?";
        else
        {
            if (this.FullURL.charAt(this.FullURL.length - 1) != '&')
               this.FullURL += "&";
        }
    }
    if (null == val)
        val = '';
        
    val = escape(val);
    
    if (null != replaceIfExists && true == replaceIfExists)
    {
        /* if the paramater already exists, find it in the string and replace it
        */
        var tokenBefore= "?";
        var toFind     = tokenBefore + name + "=";
        var toFindLen  = toFind.length; 
        var itemIndex  = this.FullURL.indexOf("?"+name+"=");
        if (-1 == itemIndex)
        {
            tokenBefore = "&";
            toFind      = tokenBefore + name + "=";
            itemIndex   = this.FullURL.indexOf(toFind);
        }
        
        if (itemIndex > 0)
        {
            var finalString = this.FullURL.substring(0, itemIndex+1);
            var rest = this.FullURL.substring(itemIndex+toFindLen);
            var nextToken = rest.indexOf("&");
            
            if (-1 != rest)
                rest = rest.substring(nextToken);
            
            this.FullURL = finalString + name + "=" + val + rest;
        }
        else
            this.FullURL += name + "=" + val;
    }
    else
        this.FullURL += name + "=" + val;
}

/*
 * AddRandom() - Adds a random number to the paramaters
 */
AjaxURL.prototype.AddRandom = function()
{
	var t = "" + Math.random();
	
	if (t.length > 0)
		this.AddParam("random", t.substring(2), true);
}

/*
 * GetURL() - Retrieves the complete URL
 */
AjaxURL.prototype.GetURL = function()
{
	return this.FullURL;
}
