if(!window["Prototype"]){
    Object.extend = function(destination, source) {
      for (var property in source)
        destination[property] = source[property];
      return destination;
    };
    var $A = Array.from = function(iterable) {
      if (!iterable) return [];
      if (iterable.toArray) {
        return iterable.toArray();
      } else {
        var results = [];
        for (var i = 0, length = iterable.length; i < length; i++)
          results.push(iterable[i]);
        return results;
      }
    }
    Function.prototype.bind = function(){
        var __method = this, args = $A(arguments), object = args.shift();
        return function() {
          return __method.apply(object, args.concat($A(arguments)));
        }
    };
    
    var Class = {};
}
Class.extend = function(sub, superClass){
    Object.extend(sub.prototype, superClass.prototype);
    sub.superclass = superClass;
    return sub;
};

var EventDispatcher = function(){
    var listenerChain = {};
    var eventRoster = [];
    
    this.registerEvent = function(name){
        eventRoster.push(name);
        listenerChain[name] = [];
    };
    this.registerEvents = function(arr){
        for(var i = 0, len= arr.length; i < len; i++)
            this.registerEvent(arr[i]);
    };
    this.getEventRoster = function(){
        return eventRoster;
    };
    this.getListenerChain = function(){
        return listenerChain;
    };
    this.addEventListener = function(type, listener){
        if(!listenerChain[type])                    
            listenerChain[type] = [listener];
        else
            listenerChain[type].push(listener);    
    };
    this.hasEventListener = function(type){
        return (typeof listenerChain[type] != "undefined" && listenerChain[type].length > 0);
    };
    this.removeEventListener = function(type, listener){
        if(!this.hasEventListener(type))
            return false;    
        for(var i = 0, l = listenerChain[type].length; i < l; i++)
            if(listenerChain[type][i] === listener)
                listenerChain[type].splice(i, 1);        
    };
    this.dispatchEvent = function(type, arg){
        for(var i = 0, l = listenerChain[type].length; i < l; i++)
            listenerChain[type][i](arg);    
    };
    this.once = function(type, listener){
        var _listener = function(arg){
            listener(arg);
            this.removeEventListener(type, _listener);
        }.bind(this)
        this.addEventListener(type, _listener);    
    };
    this.on = this.addEventListener, this.un = this.removeEventListener, this.fire = this.dispatchEvent;
}
var AjaxService = function(url, iMethod, iSync){    
    AjaxService.superclass.call(this, null);
    
    var params = {}, requestHeader = {}, queue = [];
    var method = "";
    var self = this, transactionFlag = false, timeoutDuration = false, timeout = false, synchronous = iSync;
    var stateArr = ['uninitialized', 'loading', 'loaded', 'interactive', 'complete'];
    this.registerEvents( ["success", "failure", "exception", "timeout"].concat(stateArr));
    this.setMethod = function(meth){
        method = meth;
        if(method.toUpperCase() == "POST")
            this.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    };
    this.setParams = function(prm){
        params = prm;
    };
    this.setTimeout = function(num){
        timeoutDuration = num; 
    };
    this.setSynchronous = function(bool){
        synchronous = bool;
    };
    this.getTimeout = function(){
        return timeoutDuration;
    };
    this.setRequestHeader = function(name, value){
        requestHeader[name] = value;
    };
    this.send = function(prm){
        if(synchronous && transactionFlag)
            queueRequest(url, prm || params, method);
        else
            request(url, prm || params, method);
    }
    function queueRequest(iUrl, iPrm, iMethod){
        queue.push({ url : iUrl, params : iPrm, method : iMethod});
    }
    function serializeQueryString(obj){
        var arr = [];
        
        if(typeof obj == "string")
            return obj;            
        for(var i in obj)
            arr.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
        return arr.join("&");
    }
    function isSuccess(status){
        return (status >= 200 && status < 300);
    }
    function request(iUrl, prm, iMethod){
        transactionFlag = true;
        var xhr = getXHR();        
        xhr.onreadystatechange = handleStateChange.bind(self, xhr);
        xhr.open(iMethod, iUrl, true);
        setRequestHeaders(xhr);        
        xhr.send(serializeQueryString(prm));
        if(timeoutDuration)
            startTimeout(xhr);
    }
    function startTimeout(xhr){
        xhr.timeout = setTimeout(handleTimeout.bind(this, xhr), timeoutDuration);
    }
    function setRequestHeaders(myXhr){
        for(var i in requestHeader)
            myXhr.setRequestHeader(i, requestHeader[i]);    
    }
    function handleStateChange(xhr){
        var state = stateArr[xhr.readyState];
        try{
            if(state == "complete"){
                clearTimeout(xhr.timeout);
                transactionFlag = false;                    
            }            
            this.dispatchEvent(state, xhr);
            if(state == "complete" && isSuccess(xhr.status))
                this.dispatchEvent("success", xhr);
            else if(state == "complete" && !isSuccess(xhr.status))
                this.dispatchEvent("failure", xhr);            
            if(state == "complete" && synchronous && queue.length > 0){
                var tmp = queue.shift();
                request(tmp.url, tmp.params, tmp.method);            
            }
        }
        catch(e){
            this.dispatchEvent("exception", xhr, e);
        }
    }
    function handleTimeout(xhr){
        try{
            xhr.abort();
            this.dispatchEvent("timeout", xhr);
            }
        catch(e){
            xhr.exception = e;
            this.dispatchEvent("exception", xhr);
        }
    };
    
    
    var getXHR = function(){
        try{
            return new XMLHttpRequest();
        }
        catch(e){
            try{
                return new ActiveXObject('Msxml2.XMLHTTP')
            }
            catch(e2){
                return new ActiveXObject('Microsoft.XMLHTTP')
            }
        }
    }
    this.setMethod(iMethod || "POST");
    this.getRawXHR = getXHR;
    
};
Class.extend(AjaxService, EventDispatcher);