//////////////////////////////////////////////////////////////////////////////
//	jaxajax
//
//	Description:
//		XML over HTTP request wrapper.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// 	Jax.Ajax constructor.
//
//	Usage:
//      new Jax.Ajax({method, url, isAsync, user, password});
//      new Jax.Ajax(url);
//      new Jax.Ajax(method, url);
//      new Jax.Ajax(method, url, isAsync);
//////////////////////////////////////////////////////////////////////////////
Jax.Ajax = function() {
    var m_request = null;
    var m_method = "POST";
    var m_url = null;
    var m_isAsync = false;
    var m_user = null;
    var m_password = null;
    var m_callbacks = new Hashtable();

    // Declare class and set instance.
    Jax.oop.declare(Jax.Ajax);
    this.setInstance();

	// Argument settings.
    if (arguments.length > 0) {
        if (!Jax.js.isString(arguments[0]) && Jax.js.isObject) {
            m_method = arguments[0].method;
            m_url = arguments[1].url;
            m_user = arguments[2].user;
            m_password = arguments[3].password;
        }
        else {
            switch (arguments.length) {
                case 1:
                    m_url = arguments[0];
                    break;
                        
                case 2:
                    m_method = arguments[0];
                    m_url = arguments[1];
                    break;
                    
                case 3:
                    m_method = arguments[0];
                    m_url = arguments[1];
                    m_isAsync = arguments[2];
                    break;
                    
                default:
                    throw new Error("Jax.Ajax: Argument Exception");
            }
        }
        
        // Create the request object.
        _createRequest();
    }
    else {
        throw new Error("Jax.Ajax: Argument Exception");
    }
    
    //////////////////////////////////////////////////////////////////////////
    //  Abort
    //
    //  Description:
    //      Cancels the HTTP request.
    //////////////////////////////////////////////////////////////////////////
    this.abort = function() {
        m_request.abort();
    }

    //////////////////////////////////////////////////////////////////////////
    //  getResponseHeaders
    //
    //  Description:
    //      Retrieves the values of all the HTTP headers.
    //////////////////////////////////////////////////////////////////////////
    this.getResponseHeaders = function() {
        return m_request.getAllResponseHeaders;
    }

    //////////////////////////////////////////////////////////////////////////
    //  GetResponseHeader
    //
    //  Description:
    //      Retrieves the response HTTP header.
    //////////////////////////////////////////////////////////////////////////
    this.getResponseHeader = function(responseHeader) {
        return m_request.getResponseHeader(responseHeader);
    }
	
    //////////////////////////////////////////////////////////////////////////
    //  Open
    //
    //  Description:
    //      Opens the HTTP request.
    //////////////////////////////////////////////////////////////////////////
    this.open = function() {
        try {
            m_request.open(m_method, m_url, m_isAsync, m_user, m_password);
        }
        catch (e) {
            _throwError(e);			
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //  onComplete
    //
    //  Description:
    //      Ajax request complete handler.
	//////////////////////////////////////////////////////////////////////////
	this.onComplete = function(handler) {
        m_callbacks.setItem("complete", handler);
	}
	
    //////////////////////////////////////////////////////////////////////////
    //  onError
    //
    //  Description:
    //      Ajax request error handler.
    //////////////////////////////////////////////////////////////////////////
	this.onError = function(handler) {
        m_callbacks.setItem("error", handler);
	}
	
    //////////////////////////////////////////////////////////////////////////
    //  getResponseText
    //
    //  Description:
    //      Returns the response text.
    //////////////////////////////////////////////////////////////////////////
    this.getResponseText = function()
    {
        if (m_request.status == Jax.Ajax.OK) {
            return m_request.responseText;
        }
        else {
            var e = new Error();
            e.name = "StatusError";
            e.number = m_request.status;
            e.message = "Jax.Ajax: " + m_request.statusText;
            _throwError(e);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //  getResponseXml
    //
    //  Description:
    //      Returns the response body as XML.
    //////////////////////////////////////////////////////////////////////////
    this.getResponseXml = function() {
        if ( m_request.status == Jax.Ajax.OK ) {
            return m_request.responseXML;
        }
        else {
            var e = new Error();
            e.name = "StatusError";
            e.number = m_request.status;
            e.message = "Ajax: " + m_request.statusText;
            _throwError(e);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //  Send
    //
    //  Description:
    //      Sends HTTP request to the server.
    //
    //      Usage:
    //          Send();
    //          Send(body);
    //////////////////////////////////////////////////////////////////////////
    this.send = function()
    {
        // Validate ready state.
        if (m_request.readyState != Jax.Ajax.LOADING && 
            m_request.readyState != Jax.Ajax.COMPLETED ) {
            
            // Invalid ready state; dispatch error.
            var e = new Error();
            e.name = "ReadyStateError";
            e.number = m_request.readyState;
            e.message = ( m_request.readyState == Jax.Ajax.UNINITIALIZED )
                ? "Ajax not opened"
                : "Ajax in progress";
            _throwError(e);
        }
		
        try {
            // Perform send over HTTP.
            var params = (arguments[0]) ? arguments[0] : null;
            var paramsLength = (params == null) ? 0 : params.length;
            m_request.setRequestHeader("Content-length", paramsLength);
            m_request.send(params);
        }
        catch(e) {
            _throwError(e);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //  setRequestHeader
    //
    //  Description:
    //      Specifies the request header.
    //
    //  Usage:
    //      SetRequestHeader()
    //	SetRequestHeader( mimeType );
    //	SetRequestHeader( headerName, headerValue );
    //////////////////////////////////////////////////////////////////////////
    this.setRequestHeader = function() {
        var hdrName = "Content-type";
        var hdrValue = null;

        // Set the internal request header.
        if (m_request.readyState == Jax.Ajax.LOADING) {
            switch (arguments.length) {
                case 0:
                    break;

                case 1:
                    switch (arguments[0]) {
                        case Jax.Ajax.MIME_ENCODED:
                        case Jax.Ajax.MIME_TEXT:
                            hdrValue = arguments[0]
                            break;

                        default:
                            hdrValue = Jax.Ajax.MIME_TEXT;
                    }
                    break;

                case 2:
                    hdrName = arguments[0];
                    hdrValue = arguments[1];
                    break;

                default:
                    throw new Error("SetRequestHeader:  Argument error");
            }
            
            // Set the request header.
            m_request.setRequestHeader(hdrName, hdrValue);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //  valueOf
    //
    //  Description:
    //      Returns request object.
    //////////////////////////////////////////////////////////////////////////
    this.valueOf = function() {
        return m_request;
    }

    ///////////////////////////////////////////////////////////////////////////
    //	Helpers.
    ///////////////////////////////////////////////////////////////////////////
	function _createRequest() {
        if (window.XMLHttpRequest) {
            m_request = _getHttpRequest();
        }
        else if (window.ActiveXObject) {
            var microsoft = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
            microsoft.forEach(function(item) {
                try {
                    m_request = new ActiveXObject(item);
                    return !!m_request;
                }
                catch (e) {
                    return false;
                }
            });
        }
            
        if (!m_request) {
            throw new Error( "Ajax requests are unsupported" );
        }
        
        // set up delegation.
		m_request.onreadystatechange = new Delegate(m_request, _onreadystatechange);
        m_callbacks.setItem("complete", function() {});
        m_callbacks.setItem("error", function() {});
	}
    
    function _getHttpRequest() {
        var request;
        try {
            request = new XMLHttpRequest();
        }
        catch (e) {
            request = false;
        }
        return request;
    }
	
	function _throwError(e) {
		if (m_request.onerror) {
			m_request.onerror(e);
        }
		else {
			throw e;
        }
	}
    
    function _onreadystatechange() {
        switch (this.readyState) {
            case Jax.Ajax.COMPLETED:
                var callback = (this.status == Jax.Ajax.OK)
                    ? m_callbacks.getItem("complete")
                    : m_callbacks.getItem("error");
                callback(this.status);
                break;
            
            default:
                break;
        }
    }
}

//////////////////////////////////////////////////////////////////////////////
//	Jax.Ajax ReadyState and Status enumerators.
//////////////////////////////////////////////////////////////////////////////
Jax.Ajax.UNINITIALIZED = 0;
Jax.Ajax.LOADING = 1;
Jax.Ajax.LOADED = 2;
Jax.Ajax.INTERACTIVE = 3;
Jax.Ajax.COMPLETED = 4;

Jax.Ajax.OK = 200;
Jax.Ajax.BAD_REQUEST = 400;
Jax.Ajax.UNAUTHORIZED = 401;
Jax.Ajax.PAYMENT_REQUIRED = 402;
Jax.Ajax.FORBIDDEN = 403;
Jax.Ajax.NOT_FOUND = 404;
Jax.Ajax.REQUEST_TIMEOUT = 408;
Jax.Ajax.SERVER_ERROR = 500;
Jax.Ajax.NOT_IMPLEMENTED = 501;
Jax.Ajax.SERVICE_UNAVAILABLE = 503;

Jax.Ajax.MIME_ENCODED = "application/x-www-form-urlencoded";
Jax.Ajax.MIME_TEXT = "text/html";
