/**
 * @author Falko Zander, www.falko-zander.de
 */

function cXHR() {
    this.conn = {};
    this.next_id = 0;
    this.lw_disabled = 0;
}

/**
 * @return Object
 */
cXHR.prototype.destructor = function() {
    this.conn = null;
    
    return null;
}

cXHR.prototype.disable_local_workaround = function() {
    this.lw_disabled = 1;
}

/**
 * @param url String
 * @param onsuccess Function
 * @param asynch Boolean
 * @param onerror Function
 */
cXHR.prototype.get = function(url, onsuccess, asynch, onerror) {
    var call = {
        method: 'GET',
        url: url,
        onsuccess: onsuccess,
        asynch: (asynch == null) ? true : asynch,
        onerror: onerror
    }
    this.request(call);
}

/**
 * @param url String
 * @param onsuccess Function
 * @param content String
 * @param asynch Boolean
 * @param onerror Function
 */
cXHR.prototype.post = function(url, onsuccess, content, asynch, onerror) {
    var call = {
        method: 'POST',
        url: url,
        onsuccess: onsuccess,
        content: content,
        asynch: (asynch == null) ? true : asynch,
        onerror: onerror
    }
    this.request(call);
}

/**
 * @param url String
 * @param onsuccess Function
 * @param content String
 * @param asynch Boolean
 * @param onerror Function
 */
cXHR.prototype.put = function(url, onsuccess, content, asynch, onerror) {
    var call = {
        method: 'PUT',
        url: url,
        onsuccess: onsuccess,
        content: content,
        asynch: (asynch == null) ? true : asynch,
        onerror: onerror
    }
    this.request(call);
}

/**
 * @param url String
 * @param onsuccess Function
 * @param content String
 * @param asynch Boolean
 * @param onerror Function
 */
cXHR.prototype.del = function(url, onsuccess, content, asynch, onerror) {
    var call = {
        method: 'DELETE',
        url: url,
        onsuccess: onsuccess,
        content: content,
        asynch: (asynch == null) ? true : asynch,
        onerror: onerror
    }
    this.request(call);
}

/**
 * @param p Object
 */
cXHR.prototype.request = function(p) {
    if (typeof p.method != 'string' || p.method == '') error('method has to be an unempty string');
    if (typeof p.url != 'string' || p.url == '') error('url has to be an unempty string');
    if (typeof p.onsuccess != 'function') error('onsuccess has to be a function');
    if (typeof p.onerror != 'function' && typeof p.onerror != 'undefined') error('optional onerror has to be a function if specified');
    if (p.method.toLowerCase() != 'get' && (typeof p.content != 'string' || p.content == '')) {
        error('cXHR request param errors:\n  - content in cXHR.method != GET has to be an unempty string');
    }

    p.xhr = this.create_();

    var THIS = this;    
    this.next_id++;

    if (this.lw_disabled == 0) {
        if (p.url.substr(p.url.length - 1, 1) == '/') p.url += 'data.json';
    }

    p.id = this.next_id;
    p.asynch = (p.asynch != null) ? p.asynch : true;
    if (p.asynch == 1) p.asynch = true;
    if (p.asynch == 0) p.asynch = false;
    this.conn[p.id] = p;

    p.xhr.open(p.method, p.url, p.asynch);

    if (p.method.toLowerCase() == 'post') {
        try {
            if (p.content_type) {
                p.xhr.setRequestHeader('Content-Type', p.content_type);
            } else {
                p.xhr.setRequestHeader('Content-Type', 'application/json');
            }
        } catch (e) {
            error(e.name + ' (' + e.number + '):' + e.message);
        }
    }

    if (p.asynch == 1) {
        p.xhr.onreadystatechange = function() {
            if (p.xhr.readyState == 4) {
                var cbx = function () {THIS.callback_(p.id);}
                window.setTimeout(cbx, 1);
            } else {
                // TODO: timeout should be implemented here
            }
        }
    }
    
    if (p.method.toLowerCase() == 'get') {
        p.xhr.send(null);
    } else {
        p.xhr.send(p.content);
    }

    if (!p.asynch) {
        THIS.callback_(p.id);
    }
}

/* end of public interface */

/**
 * @return Object
 */
cXHR.prototype.create_ = function() {
    var x = null;    

    try {
        x = new XMLHttpRequest();
    } catch(e1) {
        try {
            x = new ActiveXObject('Msxml2.XMLHTTP');
        } catch(e2) {
            try {
                x = new ActiveXObject('Microsoft.XMLHTTP');
            } catch(e3) {
                error('can not create XHR object');
            }
        }
    }

    return x;
}

/**
 * @param id String
 */
cXHR.prototype.callback_ = function(id) {
    var info = this.conn[id];    
    if (info == null) return;    

    if (info.xhr.status == 200) {
        info.onsuccess(info.xhr.responseText);
        delete this.conn[id];
    } else if (info.xhr.status == 401) {
		/*
		 * TODO: to be implemented
		 */ 
        this.onerror_(info.xhr.status, info.xhr.responseText);
    } else {
        if (typeof info.onerror == 'function') {
            info.onerror(info.xhr.status, info.xhr.responseText);
        } else {
            this.onerror_(info.xhr.status, info.xhr.statusText, info.xhr.responseText);
        }
        delete this.conn[id]; 
    }
}

/**
 * @param s String
 * @param st String
 * @param msg String
 */
cXHR.prototype.onerror_ = function(s, st, msg) {
    error('XMLHttpRequest error:\nStatus: ' + s + ' ' + st + '\nServermessage: ' + msg);
}
