/**
 * @copyright 2007
 * @author PVOID
 */

/**
 * @constructor
 * @classDescription AJAX запрос к серверу
 */
function AjaxRequest(){
  /**
   * @type {Boolean} Выполнять синхронный или асинхронный запрос к серверу 
   */ 
   this.async = false;
  /**
   * @type {Function} Вызывается когда запрос к серверу завершен
   */
  this.onready = null;
  /**
   * @type {Function} Вызывается когда при запросе произошел таймаут
   */
   this.ontimeout = null;
  //  Остальные свойства внутренние 
   this.params = null;
   this.request = null;
   this.state = false;  
   this.postURL = null;
   this.postParams = null;
  this.timeout   = 240000;  // 4ре минуты по умолчанию
  
  this.timeoutobject = null;
   
   this.response = new Object();
}
/**
 * Отправляет GET запрос.
 * 
 * @param {String} url URI запроса к серверу
 * @return {Boolean}
 */
AjaxRequest.prototype.openGET = function (url){
   //---
   if(! this.request) this.createRequest();
   //---
   if(! this.request){
      this.state = false;
      return false;
   }  
   //--- за врмя пока асинхронный запрос исполняется многое может изменится
   this.request.open('GET',url,this.async);
   //---
   return this.sendRequest('',this.async);
};

AjaxRequest.prototype.Stop = function ()
  {
   window.clearTimeout(this.timeoutobject);
   this.timeoutobject = null;
   this.request.abort();
   this.response = null; 
  }

/**
 * Подготавливает POST запрос на сервер.
 * 
 * @param {String} url        URI по которому будет совершен запрос
 * @param {Boolean} multypart  тип запроса * 
 */
AjaxRequest.prototype.startPOST = function (url, multypart){
   this.postURL = url;
   this.postMultypart = multypart;
   this.postParams = null;
   this.postParams = new Array();
}
/**
 * Добавляет параметр к запросу. Одноименные параметры не будут заменены
 * 
 * @param {String} name
 * @param {Object} value
 */
AjaxRequest.prototype.addPOSTParam = function (name, value){
   this.postParams.push({'name':name,'value':value});
}
/**
 * Отправляет текущий POST запрос
 * @return {Boolean}
 */
AjaxRequest.prototype.sendPOST = function (){
   //---
   if(! this.request) this.createRequest();
   //---
   if(! this.request){
      this.state = false;
      return false;
   }  
   //---
   var data = '';
   //--- за врмя пока асинхронный запрос исполняется многое может изменится
   this.request.open('POST',this.postURL,this.async);
   //---
   for(var i=0, len = this.postParams.length;i<len;i++)
      data = this.appendParam(data,this.postParams[i].name,this.postParams[i].value,this.postMultypart);
   //---
   if((data!='')&&(this.postMultypart)){
      data+="--AJAXREQUEST----------------7d7230d601aa--\r\n";
      this.request.setRequestHeader("Content-Type","multipart/form-data; boundary=AJAXREQUEST----------------7d7230d601aa");
   } else   
      this.request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
   return this.sendRequest(data,this.async);       
}
/**
 * Отправляет форму. Все данные по типу отправки беруться из формы
 *  
 * @param {Form} form  форма для отправки
 * @return {Boolean}
 */
AjaxRequest.prototype.sendForm = function (form){
   //---
   if(! this.request) this.createRequest();
   //---
   if(! this.request){
      this.state = false;
      return false;
   }  
   //---
   // по уму конечно, что бы рефакторинг надо б заюзать отправку через пост, но тогда будет медленнее
   var url = form.action;
  url+=((url.indexOf('?')!=-1)?'&':'?')+Math.random();
   var method = form.method.toUpperCase();
  if(! method) method = 'GET';
   var type = (form.encoding == 'multipart/form-data');
   var data = '';
   
   for(var i=0,len = form.elements.length;i<len;i++)
    {
     var e = form.elements[i];
      switch(e.type)
        {
          
          case 'submit':
          case 'picture':
          case 'button':
            break;
          case 'checkbox':
          case 'radio':
            if(! e.checked) break;
          default:
            data = this.appendParam(data,e.name,e.value,(method=='POST')&&(type));
        }
    }
      
   if(method=='POST'){
      this.request.open(method,url,this.async);
      if((data!='')&&(type)){
         data+="--AJAXREQUEST----------------7d7230d601aa--\r\n";
         this.request.setRequestHeader("Content-Type","multipart/form-data; boundary=AJAXREQUEST----------------7d7230d601aa");
      } else   
         this.request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
   }else{
      this.request.open(method,url+((url.indexOf('?')!=-1)?'&':'?')+data,this.async);
      data = '';
   }
   
   return this.sendRequest(data,this.async); 
}
/***********************************************************************************
 *   
 *   Внутренние методы.
 *   
 ***********************************************************************************/
 /**
  * Добавляет к строке запроса параметр
  *  
  * @param {Object} data    Строка данных
  * @param {Object} name    Имя параметра
  * @param {Object} value   Значение параметра
  * @param {Object} multi   Тип запроса
  */
AjaxRequest.prototype.appendParam = function (data,name,value,multi){
   if(! multi)
         data += ((data!='')?'&':'') + encodeURIComponent(name)+'='+encodeURIComponent(value);
      else
         data += '--AJAXREQUEST----------------7d7230d601aa\r\nContent-Disposition: form-data; name="'
                  +  encodeURIComponent(name) + '"\r\n\r\n'+encodeURIComponent(value)+'\r\n';
   return data;
}
/**
 * Создает объект запроса
 */   
AjaxRequest.prototype.createRequest = function ()
   {
      this.request = null;
      this.state = false; 
      try{
         if (window.XMLHttpRequest)
            this.request = new XMLHttpRequest();
         else if(window.ActiveXObject){
            this.request = new ActiveXObject("Msxml2.XMLHTTP");
            if (! this.request)
               this.request = new ActiveXObject("Microsoft.XMLHTTP");
         }
      }catch(exception)
         {
            this.request = null;
         }
      this.state = (this.request!=null);
   }
/**
 * Проставляет параметры ответа
 */
AjaxRequest.prototype.setResponse = function (){
   try{
      this.response.code = this.request.status;
      this.response.message = this.request.statusText;
      this.response.text = this.request.responseText;
      this.response.XML = this.request.responseXML;
    this.response.contentType = this.request.getResponseHeader('Content-Type');
   }catch(e) {}
}
/**
 * Отправляет текущий запрос
 * 
 * @param {String} data данные для отправки в пакете.
 * @param {bool} async отправлять в синхронном или асинхронном режиме
 */
AjaxRequest.prototype.sendRequest = function (data, async){ 
   var object = this;
   this.request.onreadystatechange = function () { object.stateCallBack(object);};
  
  this.timeoutobject = window.setTimeout(function () { object.timeoutOcure(); },this.timeout);
  
   this.request.send(data);
   if(! async){
      this.setResponse();
      if(this.response.code == 200)
         return true;
      else return false;
   }
   return true;
}
/**
 * отработка смены статуса аякс запроса
 * 
 * @param {AjaxRequest} object
 * @param {int} type
 */
AjaxRequest.prototype.stateCallBack = function (object)
   {
      switch(object.request.readyState){
         case 4:
        if(this.timeoutobject == null) return;
        window.clearTimeout(this.timeoutobject);
        this.timeoutobject = null;
            this.setResponse();
            if(object.onready) object.onready(object);
            break;
      }
   }
/**
 * Вызывается при таймауте запроса
 */
AjaxRequest.prototype.timeoutOcure = function ()
  {
    this.request.abort();
    this.timeoutobject = null;
    this.response = null;    
    if(this.ontimeout) this.ontimeout(this);
  }
