/******************************************************
 * by Alexander Chechet, 2006 <al.chechet@gmail.com>.
 ******************************************************/

function AjaxRequest() {

    var timeout = 3000;

    var conn, rq, t;
    
    var ready = true;

    this.debug = false;

    function getConnection() {
        if (conn) {
            return conn;
        } else {
            return this.createConnection();
        }
    }
    
    this.getConnection = getConnection;
    
    function createConnection() {
        if (window.XMLHttpRequest) {
            conn = new XMLHttpRequest();
            return conn;
        } else if (window.ActiveXObject) {
            conn = new ActiveXObject("Microsoft.XMLHTTP");
            return conn;
        } else {
            if (this.debug) {
                alert('AjaxRequest::createConnection: XMLHttpRequest not supported');
            }
            return false;
        }
    }
    
    this.createConnection = createConnection;

    function send(data) {
        if (! ready) { if (data.onBusy) { data.onBusy(me); } return false; }
        this.createConnection()
        if (! conn) { return false; }
        if (data.async !== false) { data.async = true; }
        rq = data; ready = false;
        conn.onreadystatechange = this.stateHandler;
        if (rq.onTimeout) {
            t = setTimeout(function() { conn.abort(); ready = true; rq.onTimeout(); }, timeout);
        } else { t = setTimeout(function() { conn.abort(); ready = true; }, timeout); }
        if (rq.user) {
            conn.open(rq.method, rq.url, rq.async, rq.user, rq.passwd);
        } else {
            conn.open(rq.method, rq.url, rq.async);
        }
        if (rq.method == 'POST') {
            var datastr = this.mkQueryString(rq.data, '').join('&');
            conn.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            conn.send(datastr);
        } else {
            conn.send(null);
        }
        return true;
    }
    
    this.send = send;

    function mkQueryString(data, prop) {
        if (null === data) {
            return prop.length ? [prop + '='] : [];
        }
        var res = new Array;
        switch (typeof(data)) {
            case 'object':
            if(data instanceof Array) {
                for(var i=0; i < data.length; i++) {
                    res = res.concat(this.mkQueryString(data[i], prop+'['+i+']'));
                }
            } else {
                for (var val in data) {
                    res = res.concat(this.mkQueryString(data[val], prop.length ? prop+'['+val+']' : val));
                }
            }
            break;
            case 'string':
            case 'number':
            res.push(prop + '=' + escape(data));
            break;
            case 'boolean':
            res.push(prop + '=' + (data ? '1' : '0'));
            break;
        }
        return res;
    }
    
    this.mkQueryString = mkQueryString;

    function stateHandler() {
        switch (conn.readyState) {
            case 0: break;
            case 1: if(rq.onLoading) rq.onLoading(me); break;
            case 2: if(rq.onLoaded) rq.onLoaded(me); break;
            case 3: if(rq.onInteractive) rq.onInteractive(me); break;
            case 4:
            switch (conn.status) {
                case 200:
                clearTimeout(t); ready = true; rq.onSuccess(me); break;
                default : if(rq.onError) rq.onError(me); break;
            }
            break;
        }
    }
    
    this.stateHandler = stateHandler;
    
    function getInfo() {
        return rq;
    }
    
    this.getInfo = getInfo;
    
    function isReady() {
        return ready;
    }
    
    this.isReady = isReady;
    
    var me = this;
}
