if (typeof Spar != 'object') Spar = {};
if (typeof Spar.util != 'object') Spar.util = {};

Spar.util.Connection = function (url) {
/*
    :info: 060430/1254

    :todo: Strict types checking
    :todo: Escaping while posting (incoming, outgoing)
    :todo: Switching data serialization method depending on connection type
    :todo: Different headers on Get or Post (in the Interact function)

    :note: Requiring (both) an posting (Post) content-type, encoding directives, etc
    :note: For POST: 'Content-Type', 'application/x-www-form-urlencoded';

    */

    var url         = url;
    var async       = true;

    var handlers    = {custom:[]};
    var poll        = {caller: this, id: null, method: 'get', source: null, count: 0};
    
    this.handleInteraction = function (handler) {
        handlers.interaction = handler;
    }

    this.handleSuccess = function (handler) {
        handlers.success = handler;
    }

    this.handleFailure = function (handler) {
        handlers.failure = handler;
    }

    this.handleCustom = function (code, handler) {
        handlers.custom[code] = handler;
    }

    this.say = function (method, source, period, count) {
        if (poll.id) {
            throw new Error('Reset Connection first');
            return;
        }

        poll.count  = count
        poll.method = method;
        poll.source = source

        interact();
        
        if (typeof period == 'number') {
            poll.id = setInterval(interact, period);
        }
    }

    this.reset = function () {
        if (poll.id) {
            clearInterval(poll.id);
        }
        poll.id = null;
        poll.count = 0;
    }

    function getConnector () {
        if (typeof this.$ver == 'undefined' || this.$ver == null) {
            try { 
                return new XMLHttpRequest();
            } 
            catch (e) {
            }

            var avail = [
                'MSXML2.XMLHTTP',
                'Microsoft.XMLHTTP',
                'Msxml2.XMLHTTP.7.0',
                'Msxml2.XMLHTTP.6.0',
                'Msxml2.XMLHTTP.5.0',
                'Msxml2.XMLHTTP.4.0',
                'MSXML2.XMLHTTP.3.0'
            ];
            for (var i = 0; i<avail.length; i++) {
                try {
                    this.$ver = avail[i];
                    return new ActiveXObject(avail[i]);
                }
                catch (e) {
                    this.$ver = null;
                }
            }
            throw new Error('Can not initialize Connection object');
        }
        return new ActiveXObject(this.$ver);
    }

    function query (data) {
        var query = new Array();

        if (data) {
            if ('object' != typeof data) {
                query.push(data);
            }
            else if ('undefined' != typeof data.join) {
                query = data;
            }
            else {
                for (var property in data) {
                    query.push(property +'='+ data[property]);
                }
            }
        }
        return query.length ? '?' + query.join('&') : '';
    }

    function interact () {
        try {
            poll.count--;
            if (poll.count < 0) {
                poll.caller.reset();
                return;
            }
        }
        catch (e) {
        }

        var data = null;

        if (typeof poll.source == 'function') {
            data = poll.source();
        }
        else if (typeof poll.source != 'undefined') {
            data = poll.source;
        }

        var conn = getConnector();

        conn.onreadystatechange = function () {
            if (3 == conn.readyState) {
                try {
                    return handlers.interaction(conn);
                }
                catch (e) {
                }
            }
            else if (4 == conn.readyState) {
                try {
                    if (!window.opera || (window.opera && 100 == conn.status))
                        return handlers.custom[conn.status](conn);
                }
                catch (e) {
                }
                try {
                    return conn.status > 399 ? handlers.failure(conn) : handlers.success(conn);
                }
                catch (e) {
                }
            }
        }
        
        conn.open(poll.method, url + query(data), async);

        if ('post' == poll.method) {
            conn.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
        }
        conn.setRequestHeader('Accept-Charset', 'UTF-8'); 
        conn.send(data);
    }
}
