﻿// -----------------------------------------------------
// Copyright (c) 2008 CiderHouse. All Rights Reserved.
// ----------------------------------------------------- 
///<reference path="precore.js" />
///<reference path="core.js" />

// Upgrade XMLHttpRequest, for same interface interaction in IE as FF
if (!window.XMLHttpRequest) 
{
    window.XMLHttpRequest = function() 
    {
        var types = [
            "Microsoft.XMLHTTP",
            "MSXML2.XMLHTTP.5.0",
            "MSXML2.XMLHTTP.4.0",
            "MSXML2.XMLHTTP.3.0",
            "MSXML2.XMLHTTP"
        ];

        for (var i = 0; i < types.length; i++) 
        {
            try 
            {
                return new ActiveXObject(types[i]);
            }
            catch(e) {}
        }

        return undefined;
    }
}

function ForceAjaxAbort()
{
	///<summary>Close all still active AJAX connections on closing page</summary>
	for(var i = 0; $AJAXITEMS && i < $AJAXITEMS.length; i++)
	{
		if($AJAXITEMS[i].Abort)
		{
			$AJAXITEMS[i].Abort();
		}	
	}
}
var $AJAXITEMS = new Array();
Event.Observe(window,"beforeunload",ForceAjaxAbort,false);


function AjaxObject()
{
	///<summary>AJAX Object Class</summary>
	this.obj = new window.XMLHttpRequest;
	this.Aborted = false;
	this.Url = null;
	this.Format = null;
	this.ASync = true;
	this.InRequest = false;
	this.HandleLoading = null;
	this.HandleReceiving = null;
	this.HandleSuccess = null;
	this.HandleFailure = null;
	this.HandleFailsafe = null;
	this.FailsafeTimeout = null;
	this.FailsafeTimeoutObject = null;
	$AJAXITEMS.push(this);
}

AjaxObject.prototype.SetHeader = function(label,value)
{
	///<summary>Set the AJAX call Request Header</summary>
	///<param name="label" type="String">Request Header label</param>
	///<param name="value" type="String">Request Header value</param>
	this.obj.setRequestHeader(label,value);
}

AjaxObject.prototype.Abort = function() 
{
	/// <summary>Abort the AJAX call</summary>
	this.Aborted = true;
	this.obj.abort();
	this.Aborted = false;
}

AjaxObject.prototype.Request = function(method,url,format,async,sendParam) 
{
	///<summary>Do a AJAX request</summary>
	///<param name="method" type="String">Request method: POST or GET</param>
	///<param name="url" type="String">URL to request</param>
	///<param name="format" type="String">Format: str, xml or json</param>
	///<param name="async" type="bool">Async request: True or False</param>
	///<param name="sendParam" type="String">Parameter string</param>

	//Some browsers seem to have major troubles with the path structure. Opera for example does not like the basepath for AjaxCalls
	//So the registered $BASE param should be used to transform the url to a usable format
	if(url.indexOf("HTTP://") < 0&& url.indexOf("http://") < 0)
	{
		var newUrl = url;
		if(newUrl.indexOf("/") == 0) { newUrl = newUrl.replace("/",""); }
		
		
		var basePath = "";
		try
		{
			basePath = $BASE;
		}
		catch(ex)
		{
			basePath = "";
		}
		
		newUrl = basePath + newUrl;
		
		url = newUrl;
	}
	
	//If no handlers, an ajaxcall would be strange	
	if (this.HandleSuccess != null && this.HandleFailure != null) 
	{
		this.Format = format;
		this.Url = url;
		this.InRequest = true;
		
		// generate timestamp to ensure the request is unique
		var urlTimeStamp = (url.indexOf("?") == -1 ? "?" : "&") + "ts=" + (new Date().getTime());
		
		this.ASync = (typeof(async) == "undefined" ? true : async);
		
		if (this.HandleFailsafe != null && this.FailsafeTimeout != null) 
		{
			this.FailsafeTimeoutObject = window.setTimeout(this.OnFailsafe.bind(this),this.FailsafeTimeout);
		}
		
		this.obj.open(method,this.Url + urlTimeStamp,this.ASync);
		
		var scope = this;
		scope.OnLoading();
		
		//What to do if the ready state change
		this.obj.onreadystatechange = function() 
		{
			switch(scope.obj.readyState) 
			{
				case 0:
				case 1:
				case 2:
					scope.OnLoading();
					break;
				case 3: 
					scope.OnReceiving();
					break;
				case 4:
					if (!scope.Aborted) 
					{
						scope.OnLoaded();
					}
					break;
			}
		}
		
		if(method == "post" || method == "POST")
		{
			this.obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		}
		
		//Do the real request
		this.obj.send(sendParam);
	} 
	else 
	{
		var handlers = [];
		if (this.HandleSuccess == null) {handlers.push("HandleSuccess");}
		if (this.HandleFailure == null) {handlers.push("HandleFailure");}
		
		Debug("Please define '" + handlers.toString() + "' function" + (handlers.length>1?"s":"") + " for request to '" + url + "'.");
	}
}

AjaxObject.prototype.OnFailsafe = function() 
{
	///<summary>A failsafe check is implemented after a certain amount of time, at that moment the request would be canceled and the wait stopped</summary>
	this.Abort();
	this.HandleFailsafe();
}

AjaxObject.prototype.OnReceiving = function() 
{
	///<summary>Event to be called when receiving data</summary>
	if (this.HandleReceiving!=null) 
	{
		this.HandleReceiving();
	}
}
	
AjaxObject.prototype.OnLoading = function() 
{
	///<summary>Event to be called when loading the page for the request</summary>
	if (this.HandleLoading!=null) 
	{
		this.HandleLoading();
	}
}

AjaxObject.prototype.OnLoaded = function() 
{
	///<summary>Event to be called when loading is done</summary>
	this.InRequest = false;

	//Clear the failsafe timeout
	if (this.FailsafeTimeoutObject != null) 
	{
		window.clearTimeout(this.FailsafeTimeoutObject);
	}
	var errorObject = {Code:"UNKNOWN",Text:Language.ErrorMessages.GetMessage("UNKNOWN_ERROR_MESSAGE")};
	
	//Read the response
	if ((this.obj.status >= 200 && this.obj.status <300) || this.obj.status == 304) 
	{
		
		var response = null;
		//Parse the response to the correct format
		switch(this.Format.toLowerCase()) {
			case "str": 
			{
				if (this.IsValid(this.obj.responseText)) 
				{
					response = this.obj.responseText;
				}
			}
			break;
			case "xml": 
			{
				if (this.IsValid(this.obj.responseXML)) 
				{
					response = this.obj.responseXML;
				}
			}
			break;
			case "json": 
			{
				if (this.IsValid(this.obj.responseText)) 
				{
					try
					{
						response = eval("(" + this.obj.responseText + ")");
					}
					catch(e)
					{
						response = null;
					}
				}
			}
			break;
			//if no supported format is selected, terminate
			default: Debug(this.Format.toLowerCase() + Language.ErrorMessages.GetMessage("INVALID_AJAX_TYPE")); break;
		}
		//If the response is not null handle the success
		if (response) 
		{	
			this.HandleSuccess(response);
			return; //Stop executing, everything below this code will call HandleFailure
		}
		//If an error occeured make a valid error message
		else if (this.obj.responseText.indexOf("AjaxError") != -1) 
		{
			var obj2 = eval("(" + this.obj.responseText + ")");			
			errorObject.Code = obj2.AjaxError.Code;
			errorObject.Text = obj2.AjaxError.Text;
			if(obj2.AjaxError.Code == "NO_SESSION_COOKIE")
			{
				errorObject.Text = Language.ErrorMessages.GetMessage("NO_SESSION_COOKIE_MESSAGE");
			}
		}
	}
	else 
	{
		try
		{
			errorObject.Code = obj.Code;
			errorObject.Text = obj.Text;
		}
		catch(except)
		{
			errorObject.Code = "INV_RESPONSE";
			errorObject.Text = Language.ErrorMessages.GetMessage("INVALID_RESPONSE_MESSAGE");
		}
	}
	
	// fire handlefailure function (if not success)
	this.HandleFailure(errorObject);
}

AjaxObject.prototype.IsValid = function(responseValue) 
{
	///<summary>Check if the response value from the request is a valid response</summary>
	///<returns type="Boolean" />
	if (responseValue.indexOf("AjaxError") != -1) 
	{
		return false;
	}
	if (typeof(responseValue) == "undefined") 
	{
		return false;
	}
	if (responseValue == null) 
	{
		return false;
	}
	if (responseValue.length == 0) 
	{
		return false;
	}	
	return true;
}