/**
 * @author 		DucthuanX
 * @link		http://www.ducthuan.info
 * @copyright	(c) 2007 Nguyen Duc Thuan <me at ducthuan dot info>
 */

if ('undefined' == typeof Ducthuans) {
    alert('This component needs Ducthuans.js to work properly');
}

/**
 * Lớp Ajax Request
 * @param {Object} configs đối tượng các thiết lập
 *
 * configs gồm các thuộc tính:
 * - url: đường dẫn để gửi request
 * - method: phương thức (POST/GET/HEAD/PUT), mặc định là GET
 * - isAsync: có bất đồng bộ hay không (true/false), mặc định là true
 */
function Ducthuans_AjaxRequest(configs){
    /**
     * Request method
     * @private
     * @type {String} must be POST/GET/HEAD/PUT
     */
    this._method = 'GET';
    /**
     * Asyncronous or not?
     * @private
     * @type {Boolean}
     */
    this._isAsync = true;
    /**
     * Inits handlers
     */
    this.initHandlers();
    /**
     * Assigns basic configurations
     */
    this.setConfig(configs);
    /**
     * Query parameters
     * @private
     * @type {Array}
     */
    this._params = [];
}

Ducthuans_AjaxRequest.prototype.init = function() {
    this.removeAllHandlers();
    this.clearParams();
};

/**
 * Initializes handlers
 */
Ducthuans_AjaxRequest.prototype.initHandlers = function(){
    var handlers = [];
    handlers['onCreateFailed'] = [];
    handlers['onComplete'] = [];
    handlers['onSucceed'] = [];
    handlers['onServerError'] = [];
    handlers['onInteractive'] = [];
    handlers['onLoaded'] = [];
    handlers['onLoading'] = [];
    handlers['onUninitialized'] = [];
    
    this._handlers = handlers;
}

/**
 * Thiết lập các thông số cho AjaxRequest
 * @param {Object} configs đối tượng các thiết lập
 */
Ducthuans_AjaxRequest.prototype.setConfig = function(configs){
    if (configs != null) {
        if (configs.url != null) {
            this._url = configs.url;
        }
        if (configs.method != null) {
            this._method = configs.method.toUpperCase();
        }
        if (configs.isAsync != null) {
            this._isAsync = configs.isAsync;
        }
    }
};

/**
 * Thêm tham số submit
 * @param {String} name 	tên tham số
 * @param {String} value	giá trị tham số
 */
Ducthuans_AjaxRequest.prototype.addParam = function(name, value){
    this._params.push({
        'name': name,
        'value': value
    });
};

/**
 * Clears query parameters
 */
Ducthuans_AjaxRequest.prototype.clearParams = function(){
    this._params = [];
};

/**
 * Serializes and adds params from form
 * @param {HTMLElement} formElement
 */
Ducthuans_AjaxRequest.prototype.getParamsFromForm = function(formElement){
    try {
        var inputs = formElement.getElementsByTagName('input');
        var textareas = formElement.getElementsByTagName('textarea');
        var selects = formElement.getElementsByTagName('select');
        
        for (var inputCounter = 0, input; input = inputs[inputCounter]; inputCounter++) {
            if (input.name && !input.disabled && (('radio' == input.type.toLowerCase() && input.checked) || input.type.toLowerCase() != 'radio')) {
                this.addParam(input.name, input.value);
            }
        }
        
        for (var textareaCounter = 0, textarea; textarea = textareas[textareaCounter]; textareaCounter++) {
            if (textarea.name && !textarea.disabled) {
                this.addParam(textarea.name, textarea.value);
            }
        }
        
        for (var selectCounter = 0, select; select = selects[selectCounter]; textareaCounter++) {
            if (select.name && !select.disabled) {
                this.addParam(select.name, select.options[select.selectedIndex].value);
            }
        }
    } 
    catch (e) {
        alert(e);
    }
};

/**
 * Thêm handler cho các sự kiện của Request
 * @param {String} event	tên sự kiện
 * @param {String} command	đoạn mã cần thực thi
 * @see   Ducthuans_AjaxRequest
 */
Ducthuans_AjaxRequest.prototype.addHandler = function(event, command){
    this._handlers[event].push(command);
};

/**
 * Removes handlers of an event
 * @param {String} event
 */
Ducthuans_AjaxRequest.prototype.clearHandlers = function(event){
    this._handlers[event] = [];
};

/**
 * Removes all handlers
 */
Ducthuans_AjaxRequest.prototype.removeAllHandlers = function(){
    this.initHandlers();
}

/**
 * Gửi request
 * @param {Object} configs đối tượng các thông tin thiết lập
 */
Ducthuans_AjaxRequest.prototype.send = function(configs){
    this.setConfig(configs);
    
    var req = this._createRequest();
    var current = this;
    
    req.onreadystatechange = function(){
        current.readyState = req.readyState;
        switch (req.readyState) {
            case 4:
                current.status = req.status;
                current.statusText = req.statusText;
                current._runHandlers('onComplete');
                
                if (req.status == 200 || req.status == 304) {
                    current.responseText = req.responseText;
                    current.responseXML = req.responseXML;
                    current._runHandlers('onSucceed');
                }
                else {
                    current._runHandlers('onServerError');
                }
                break;
            case 3:
                current._runHandlers('onInteractive');
                break;
            case 2:
                current._runHandlers('onLoaded');
                break;
            case 1:
                current._runHandlers('onLoading');
                break;
            default:
                current._runHandlers('onUninitialized');
                break;
        }
        
    };
    req.open(this._method, this._url, this._isAsync);
    
    var queryString = this._genQueryString();
    if ('POST' == this._method) {
        req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        req.setRequestHeader('Content-length', queryString.length);
        req.setRequestHeader('Connection', 'close');
    }
    req.send(queryString);
    
    this.prototype = current;
};

/**
 * Khởi tạo đối tượng XMLHttpRequest
 */
Ducthuans_AjaxRequest.prototype._createRequest = function(){
    var httpRequest = null;
    if (window.XMLHttpRequest) {
        httpRequest = new XMLHttpRequest();
        if (httpRequest.overrideMimeType) {
            httpRequest.overrideMimeType('text/xml');
        }
    }
    else 
        if (window.ActiveXObject) {
            try {
                httpRequest = new ActiveXObject('Msxml2.XMLHTTP');
            } 
            catch (e) {
                try {
                    httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
                } 
                catch (e) {
                }
            }
        }
    
    if (!httpRequest) {
        this._runHandlers('onCreateFailed');
    }
    
    return httpRequest;
};

/**
 * Tạo chuỗi truy vấn để gửi vào XMLHttpRequest
 */
Ducthuans_AjaxRequest.prototype._genQueryString = function(){
    var queryArray = [];
    for (var paramCounter = 0, param; param = this._params[paramCounter]; paramCounter++) {
        queryArray.push(param.name + '=' + encodeURIComponent(param.value));
    }
    return queryArray.join('&');
};

/**
 * Thực thi các trình xử lí
 * @param {Object} event tên sự kiện
 * @see	  Ducthuans_AjaxRequest
 */
Ducthuans_AjaxRequest.prototype._runHandlers = function(event){
    var object = this;
    for (var cCounter = 0, command; command = this._handlers[event][cCounter]; cCounter++) {
        if ('function' == typeof command) {
            command.call(object);
        }
        else {
            eval(command);
        }
        this._handlers[event].slice(cCounter, cCounter + 1);
    }
};

Ducthuans.Ajax = new Ducthuans_AjaxRequest();
