// XMLHTTP JS class is is developed by Alex Serebryakov (#0.9)
// For more information, consult www.ajaxextended.com

XMLHTTP = function() {

  // The following two options are configurable
  // you don't need to change the rest. Plug & play!
  var _maximumRequestLength = 1500;
//  var _apiURL = 'http://ajaxextended.com/api/';
  var _apiURL = 'http://www.fine.pl/_stat/js/xmlhttp.php';

  this.status = null;
  this.statusText = null;
  this.responseText = null;
  this.responseXML = null;
  this.synchronous = false;
  this.readyState = 0;
  
  this.onreadystatechange =  function() { }
  this.onerror = function() { };
  this.onload = function() { };
  
  this.abort = function() {
    _stop = true;
    _destroyScripts();
  };
  
  this.getAllResponseHeaders = function() {
    // Returns all response headers as a string
    var result = '';
    for (property in _responseHeaders){
      result += property + ': ' + _responseHeaders[property] + '\r\n';
	}
    return result;
  };
  
  this.getResponseHeader = function(name) {
    // Returns a response header value
    // Note, that the search is case-insensitive
    for(property in _requestHeaders) {
      if(property.toLowerCase() == name.toLowerCase()){
        return _responseHeaders[property];
	  };
    };
    return null;
  };
  
  this.overrideMimeType = function(type) {
    _overrideMime = type;
  };
  
  this.open = function(method, url, sync, userName, password) {
    // Setting the internal values
    if (!_checkParameters(method, url)) return;
    _method = (method) ? method : '';
    _url = (url) ? url : '';
    _userName = (userName) ? userName : '';
    _password = (password) ? password : '';
    _setReadyState(1);
  };
  
  this.openRequest = function(method, url, sync, userName, password) {
    // This method is inserted for compatibility purposes only
    return this.open(method, url, sync, userName, password);
  };
  
  this.send = function(data) {
    if (_stop) return;
    var src = _createQuery(data);
    _createScript(src);
//    _setReadyState(2)
  };
  
  this.setRequestHeader = function(name, value) {
    // Set the request header. If the defined header
    // already exists (search is case-insensitive), rewrite it
    if (_stop) return;
    for(property in _requestHeaders) {
      if(property.toLowerCase() == name.toLowerCase()) {
        _requestHeaders[property] = value; return;
      }
    }
    _requestHeaders[name] = value;
  };

  var _method = '';
  var _url = '';
  var _userName = '';
  var _password = '';
  var _requestHeaders = {
    "HTTP-Referer": document.location,
    "Content-Type": "application/x-www-form-urlencoded"
  }
  var _responseHeaders = { }
  var _overrideMime = "";
  var self = this;
  var _id = '';
  var _scripts = [];
  var _stop = false;
  
  var _throwError = function(description) {
    // Stop script execution and run
    // the user-defined error handler
    self.onerror(description);
    self.abort();
    return false;
  };
  
  var _createQuery = function(data) {
    if(!data) data = '';
    var headers = '';
    for (property in _requestHeaders)
      headers += property + '=' + _requestHeaders[property] + '&';
    var originalsrc = _method
    + '$' + _id
    + '$' + _userName
    + "$" + _password
    + "$" + headers
    + '$' + _escape(data)
    + '$' + _url;
    var src = originalsrc;
    var max =  _maximumRequestLength, request = [];
    var total = Math.floor(src.length / max), current = 0;
    while(src.length > 0) {
      var query = _apiURL + '?'
      + 'multipart' 
      + '$' + _id
      + '$' + current++
      + '$' + total
      + '$' + src.substr(0, max);
      request.push(query);
      src = src.substr(max);
    };
    if(request.length == 1)
      src = _apiURL + '?' + originalsrc;
    else
      src = request;
    return src;
  }
  
  var _checkParameters = function(method, url) {
    // Check the method value (GET, POST, HEAD)
    // and the prefix of the url (http://)
    if(!method)
      return _throwError('Please, specify the query method (GET, POST or HEAD)');
    if(!url)
      return _throwError('Please, specify the URL');
    if(method.toLowerCase() != 'get' &&
      method.toLowerCase() != 'post' &&
      method.toLowerCase() != 'head')
      return _throwError('Please, specify either a GET, POST or a HEAD method');
    if(url.toLowerCase().substr(0,7) != 'http://')
      return _throwError('Only HTTP protocol is supported (http://)');
    return true;
  }

  var _createScript = function(src) {
    if ('object' == typeof src) {
      for(var i = 0; i < src.length; i++)
        _createScript(src[i]);
      return;
    }
    // Create the SCRIPT tag
    var script = document.createElement('script')
    script.src = src;
    script.type = 'text/javascript';
    if (navigator.userAgent.indexOf('Safari'))
      script.charset = 'utf-8'; // Safari bug
    script = document.getElementsByTagName('head')[0].appendChild(script);
    _scripts.push(script);
    return script;
  }
  
  var _escape = function(string) {
    // Native escape() function doesn't quote the plus sign +
    string = escape(string);
    string = string.replace('+', '%2B');
    return string;
  }
  
  var _destroyScripts = function() {
    // Removes the SCRIPT nodes used by the class
    for(var i = 0; i < _scripts.length; i++)
      _scripts[i].parentNode.removeChild(_scripts[i]);
  }
  
  var _registerCallback = function() {
    // Register a callback variable (in global scope)
    // that points to current instance of the class
    _id = 'v' + Math.random().toString().substr(2);
    window[_id] = self;
  }
  
  var _setReadyState = function(number) {
    // Set the ready state property of the class
    self.readyState = number;
    self.onreadystatechange();
    if(number == 4) self.onload()
  }
    
  var _parseXML = function() {
    // innerHTML is TIMES faster than DOM functions and it is
    // supported by all major browsers. It sure has lots of drawbacks
    // but for the time being its the best solution I have.
    // "Correct" but slow JS-parsing class is still to come
    var type = self.getResponseHeader('Content-type') + _overrideMime
    if(!(type.indexOf('html') > -1 || type.indexOf('xml') > -1)) return
    var xml = document.body.appendChild(document.createElement('div'))
    xml.style.display = 'none'
    xml.innerHTML = self.responseText
    _cleanWhitespace(xml, true)
    self.responseXML = xml.childNodes[0]
    document.body.removeChild(xml)
  }
  
  var _cleanWhitespace = function(element, deep) {
    var i = element.childNodes.length; if(i == 0) return
    do {
      var node = element.childNodes[--i]
      if (node.nodeType == 3 && !_cleanEmptySymbols(node.nodeValue))
        element.removeChild(node)
      if (node.nodeType == 1 && deep)
        _cleanWhitespace(node, true)
    } while(i > 0)
  }

  var _cleanEmptySymbols = function(string) {
    string = string.replace('\r', '')
    string = string.replace('\n', '')
    string = string.replace(' ', '')
  	return (string.length == 0) ? false : true 
  }
 
  this._parse = function(object) {
    // Parse the received data and set all
    // the appropriate properties of the class
    if(_stop) return
    if(object.multipart) return
    if(!object.success)
      return _throwError(object.description)
    _responseHeaders = object.responseHeaders
    this.status = object.status
    this.statusText = object.statusText
    this.responseText = object.responseText
    _parseXML()
    _destroyScripts()
    _setReadyState(4)
  }
    
   _registerCallback()

}