/* TransAjax (Transport Ajax Library) v1.2 by Sergey Shuchkin, sshuchkin@sibvision.ru */
/*---------------- One function wrappers for TransAjax class ----------------*/
/* Loads text/html content or object (JSON or serialized php object (array,int,double,string)
 * Example "Load news":
 *  == test.html
 *  <script type="text/javascript" src="ajax.js"></script>
 *  <div id="divNews">News here...</div>
 *  <script type="text/javascript">
 *  <!--
 *     ajax("?ajax=1&get=news", "divNews");
 *  -->
 *  </script>
 *
 * Example "JSON"
 *   == ajax.php
 *   <?php $r = '{success: false, error: "Validation error"}'; die($r); ?>
 *   == test_json.js
 *   function onSubmitForm() { ajax('ajax.php', onLoadObj); }
 *   function onLoadObj(obj) { alert(obj.error); } // "Validation error"
 *
 * Example "PHP serialized data"
 *   == ajax.php
 *   <?php $a = array("One","Two","Three"); die(serialize($a)); ?>
 *   == test_php_serialized.js
 *   function onButtonClick() { ajax("ajax.php", onLoadObj); }
 *   function onLoadObj(obj) { alert(obj[2]); } // "Three";
 */
function ajax(url, container_id_or_callback) {
  if (typeof(container_id_or_callback) == "function") {
    var objArgs = {
      url: url,
	  onLoadObject: container_id_or_callback
	}
  } else {
    var objArgs = {
      url: url,
      target: container_id_or_callback
	}
  }
  TransAjax.exec(objArgs);
}
// Submit form (FILES supported!);
function ajax_submit(form, container_id_or_callback) {
	if (typeof(form) == "string") form = document.getElementById(form);
	var iid = form.id+"_IFrame";
	if (typeof(form.iframed) == "undefined") {
		div = document.createElement("DIV");
		div.style.display = 'none';
		div.innerHTML = "<iframe id=\""+iid+"\" name=\""+iid+"\" src=\"about:blank\" style=\"\" onload=\"parent.ajax_submit_callback('"+iid+"',this.contentWindow.document.body.innerHTML);\" style=\"width:0px;height:0px;overflow:hidden;border:none\"></iframe>";
		form.appendChild(div);
		iframe = document.getElementById(iid);
		iframe._trans_callback = container_id_or_callback;
		form.iframed = true;
	}
	iframe = document.getElementById(iid);
	form.oldtarget = form.target;
	form.target = form.id+"_IFrame";
	form.submit();
	form.target = form.oldtarget;
}
function ajax_submit_callback(iid,txt) {
  iframe = document.getElementById(iid);
  if (typeof(iframe._trans_callback) == "function") {
    if (TransAjax.detectResponseType(txt) != TransAjax.IS_UNKNOWN)
	    iframe._trans_callback(TransAjax.result);
	else
		iframe._trans_callback(txt);
  } else {
    TransAjax.setInnerHtml(iframe._trans_callback,txt);
  }
}
var TransAjax = [];
// detect type
TransAjax.IS_JSON = 1;
TransAjax.IS_PHP = 2;
TransAjax.IS_XML = 3;
TransAjax.IS_UNKNOWN = 0;
// detect result
TransAjax.result = null;
// cache
TransAjax.cache = false;
// global busy image flag
TransAjax.showBusyImage = false;
TransAjax.busyContainer = false;
//TransAjax.objRequest = null;
TransAjax.counter = 0;
/* Full featured method "exec"
 * Arguments simple format:
 *    TransAjax.exec(url, container_id);
 *
 * Arguments object format:
 * {
 *   url: [string] relative or absolute URL to fetch,
 *   target: [string or object, optional] DOM element to loaded content
 *   method: [string, optional] method ('GET', 'POST', 'HEAD', 'PUT'),
 *   async: [boolean, optional] use asynchronous mode (default: true),
 *   contentType: [string, optional] content type when using POST,
 *   content: [string or object, optional] postable string or DOM object data
 *    when using POST,
 *   onLoad: [function, optional] function reference to call on success, returns obj.responseText,
 *   onLoadNotify: [function, optional] function reference to call on success load/replace content,
 *   onError: [function, optional] function reference to call on error,
 *   username: [string, optional] username,
 *   password: [string, optional] password,
 *   busyContainer: [object or string, optional] element or id of element where
 *    to put "Busy" animated GIF
 * }
*/
TransAjax.exec = function(objArgs) {
  if (arguments.length == 2) { // Simple call format
    objArgs = {url: arguments[0], target: arguments[1]};
  }
  // Check arguments
  if (objArgs == null || typeof objArgs != 'object') {  return null;  }
  if (!objArgs.url) {  return null;  }
  if (!TransAjax.cache) {
	  var rnd = 'rnd='+Math.random();
	  if (objArgs.url.search(/\?/) != -1) objArgs.url += '&'+rnd;
	  else objArgs.url += '?'+rnd;
  }
  if (typeof(objArgs.target) == "string") {
    objArgs.target = document.getElementById(objArgs.target);
    if (objArgs.target == null) return alert('Container "'+objArgs.target+'" not found!');
  }
  if (!objArgs.target) { objArgs.target = null;  } else {
    
  }
  if (!objArgs.method) {  objArgs.method = 'GET';  }
  if (typeof objArgs.async == 'undefined') {  objArgs.async = true;  }
  if (!objArgs.contentType && objArgs.method.toUpperCase() == 'POST') {
    objArgs.contentType = 'application/x-www-form-urlencoded';
  }
  if (!objArgs.content) { objArgs.content = null;  }
  if (!objArgs.onLoad) {  objArgs.onLoad = null;  }
  if (!objArgs.onLoadNotify) {  objArgs.onLoadNotify = null;  }
  if (!objArgs.onError) {  objArgs.onError = null;  }
  // Request URL
  //TransAjax.objRequest = (TransAjax.objRequest) ? TransAjax.objRequest : TransAjax.createRequestObject();
  var objRequest = TransAjax.createRequestObject();
  if (objRequest == null) { return null; }
  // Show "Busy" animated GIF
  var bc = document.getElementById('busyContainer');
  if (bc != null) TransAjax.showBusyImage = true;
  if (typeof(objArgs.busyContainer) == "undefined" && TransAjax.showBusyImage) {
      objArgs.busyContainer = (bc != null) ? bc : ((objArgs.target && objArgs.target.tagName=="DIV") ? objArgs.target : null);
  } else if (typeof(objArgs.busyContainer) == "string") {
	  objArgs.busyContainer = document.getElementById(objArgs.busyContainer);
  } else if (typeof(TransAjax.busyContainer) == "string") {
     objArgs.busyContainer = document.getElementById(TransAjax.busyContainer);
  }
  if (objArgs.busyContainer) {
    var busyImg = document.createElement("IMG");
	busyImg.src = TransAjax.path+'loading.gif';
	busyImg.style.cssFloat = "right";
	busyImg.id = "bim_"+Math.floor(Math.random()*900)+100;
	objArgs.busyContainer.img_id = busyImg.id;
    if (objArgs.busyContainer.firstChild) {
      objArgs.busyContainer.insertBefore(busyImg, objArgs.busyContainer.firstChild);
    } else {
      objArgs.busyContainer.appendChild(busyImg);
	}
  }
  if (objArgs.target != null && (objArgs.target.tagName == "INPUT" || objArgs.target.tagName == "SELECT")) {
     objArgs.target.disabled="disabled";
  }
  // IE 6 calls onreadystatechange and then raises an exception if local file is
  // not found. This flag is used to prevent duplicate onError calls.
  var boolErrorDisplayed = false;
  try {
    // Open request
    if (typeof objArgs.username != 'undefined' &&
     typeof objArgs.password != 'undefined') {
      objRequest.open(objArgs.method, objArgs.url, objArgs.async,
       objArgs.username, objArgs.password);
    } else {
      objRequest.open(objArgs.method, objArgs.url, objArgs.async);
    }
    // Onready handler
    var funcOnReady = function () {
		TransAjax.counter++;
		//alert('['+TransAjax.counter+'] '+objArgs.url);
      // Process response
      if (TransAjax.checkRequestStatus(objRequest)) {
        // OK or found, but determined unchanged and loaded from cache
        if (typeof objArgs.onLoad == 'function') {
          objArgs.onLoad(objRequest.responseText);
		} else if (typeof objArgs.onLoadObject == 'function') {
		  switch (TransAjax.detectResponseType(objRequest.responseText)) {
		    case TransAjax.IS_JSON:
			case TransAjax.IS_PHP:
			case TransAjax.IS_XML: objArgs.onLoadObject(TransAjax.result); break;
			case TransAjax.IS_UNKNOWN: objArgs.onLoadObject(objRequest);
		  }
        } else if (objArgs.target) {
          TransAjax.setInnerHtml(objArgs.target,objRequest.responseText);
		  if (typeof(objArgs.onLoadNotify) == 'function') {
            objArgs.onLoadNotify();
		  }
        }
		// Remove busy
		if (objArgs.busyContainer && (bim = document.getElementById(objArgs.busyContainer.img_id)) != null)   {
		bim.parentNode.removeChild(bim);
	    }		
      } else if (!boolErrorDisplayed) {
        boolErrorDisplayed = true;
        // 404 Not found, etc.
		if (!objArgs.onError) {
          alert('Error: Cannot fetch ' + objArgs.url + '.\n' + (objRequest.statusText || ''));
		} else {																
          objArgs.onError;
		}
      }
    };
    
	
	// Prevent duplicate funcOnReady call in synchronous mode
    if (objArgs.async) {
      // Set onreadystatechange handler
      objRequest.onreadystatechange = function () {
        if (objRequest.readyState == 4) {
          // Request complete
          funcOnReady();
          // Prevent memory leak 
 	      objRequest.onreadystatechange = {}; 
 	    }
      };
    }
    // Set content type if needed
    if (objArgs.contentType) {
      objRequest.setRequestHeader('Content-Type', objArgs.contentType);
    }
    // Send request
    objRequest.send(objArgs.content);
    // In synchronous mode the result is ready on the next line
    if (!objArgs.async) {
      funcOnReady();
      return objRequest;
    }
  } catch (objException) {
    // Remove "Busy" animated GIF
    //removeBusy(objArgs);
    // Process error
    if (!boolErrorDisplayed) {
      boolErrorDisplayed = true;
      if (objException.name && objException.name == 'NS_ERROR_FILE_NOT_FOUND') {
        alert('Error: Cannot load ' + objArgs.url + '.\nFile not found.');
        if (objArgs.onError) objArgs.onError;
	  } else {
        alert('Error: Cannot load ' + objArgs.url + '.\n' + (objException.message || ''));
        if (objArgs.onError) objArgs.onError;
      }
    }
  };
}
TransAjax.detectResponseType = function(txt) {
  TransAjax.result = null;
  if (txt.substr(0,1) == "{" || txt.substr(0,1) == '[') {
    // is JSON
    eval("TransAjax.result = "+txt+";");
	return TransAjax.IS_JSON;
  } else if (txt.substr(0,2).search(/[aOsidbNorCRU]+:/) != -1) {
    //alert(objRequest.responseText);
    // is serialized PHP object
	TransAjax.result = phpUnserialize(txt);
    return TransAjax.IS_PHP;
  } else if (txt.substr(0,5) == "<?xml") {
    // is XML
    if (window.DOMParser) {
      // Mozilla
      try {
        TransAjax.result = (new DOMParser()).parseFromString(txt,'text/xml');
        return TransAjax.IS_XML;
      } catch (objException) {
        alert('Error: Cannot parse.\nString does not appear to be a valid XML fragment.:\n'+txt);
      };
	}
	if (typeof ActiveXObject != 'undefined') {
      // IE
      try {
        TransAjax.result = new ActiveXObject(TransAjax.XMLActiveX);
        TransAjax.result.loadXML(objArgs.strXml);
        return TransAjax.IS_XML;
      } catch (objException) {
        alert('Error: Cannot parse '+objException);
      };
    }
  }
  return TransAjax.IS_UNKNOWN;
}
TransAjax.setInnerHtml = function(target, html) {
  if (typeof(target) == "string") target = document.getElementById(target);
  if (target == null) return;
  //alert(target.tagName);
  if (target.tagName == "INPUT" || target.tagName == "SELECT") {
	 target.disabled="";
  }
  if (target.tagName == "INPUT") {
	var t = target.type;
	if (t == "text" ||  t == "password" || t == "hidden" || t == "submit" || t == "button") {
	  target.value = html;
	}
  } else if (target.tagName == "SELECT") { // && navigator.userAgent.indexOf("MSIE")
	target.options.length = 0;
	//alert(html);
	var items = html.split("</option>");
	for (var i=0; i<items.length; i++) {
	  items[i] += '</option>';
	  var r = items[i].match(/<option value="([^"]*)"(.*?)>([^<]*)<\/option>/i);
	  if (r) {
		  var val = r[1];
		  var sel = r[2].search(/selected/) != -1;
		  var txt = r[3];
		  var nOption = document.createElement('OPTION'); 
		  var nText = document.createTextNode(txt);
		  nOption.setAttribute('value',val); 
		  if (sel) nOption.setAttribute('selected','selected');
		  nOption.appendChild(nText); 
		  target.appendChild(nOption);
	  }
	}
  } else {
	target.innerHTML = html;
	TransAjax.evalScripts(html);
  }
}
TransAjax.setInnerHTML = TransAjax.setInnerHtml; // alias
/*--------------- Mini XMLHttpRequest wrapper ---------------*/
TransAjax.createRequestObject = function() {
  try {
    if (typeof XMLHttpRequest != 'undefined') {
      obj = new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined') {
      obj = new ActiveXObject(TransAjax.HTTPActiveX);
    }
	if (!obj) {
      alert("Please install new version of browser!");
      return false;
	}
	return obj;
  } catch(e) {
	alert(e);
  }
  return false;
}
TransAjax.getNameOfActiveX = function() {
  if (typeof ActiveXObject == 'undefined') return '';
  var v = ['Microsoft.XMLHTTP','Msxml2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP'];
  for (var i = 0; i < v.length; i++) {
    try {
      var objDocument = new ActiveXObject(v[i]);
      // If it gets to this point, the string worked
      return v[i];
    } catch (objException) {};
  }
  return null;
}
TransAjax.getXMLNameOfActiveX = function() {
  if (typeof ActiveXObject == 'undefined') return '';
  var v = ['Msxml2.DOMDocument.4.0','Msxml2.DOMDocument.3.0','MSXML2.DOMDocument','MSXML.DOMDocument','Microsoft.XMLDOM'];
  for (var i = 0; i < v.length; i++) {
    try {
      var objDocument = new ActiveXObject(v[i]);
      // If it gets to this point, the string worked
      return v[i];
    } catch (e) {
		//alert(e);
	};
  }
  return null;
}
TransAjax.checkRequestStatus = function(obj) {
  try {
    if (obj.readyState == 4) {
      if (obj.status == 200 || obj.status == 304 || (location.protocol == 'file:' && !obj.status)) {
        return true;
      }
	}
  } catch(e) {
    return false
  };
  return false;
}
//----------------- Search/Eval scripts
TransAjax.evalScripts = function(s) {
  if (s.search(/<\s*script[^>]*>/) != -1) {
    var r = s.split(/<\s*\/\s*script\s*>/i);
    var r2 = []; var r3 = []; var strScript = '';
    for (var i=0; i < r.length; i++) {
      // process "src"
      r2 = r[i].match(/<\s*script[^>]+src="([^"]+)"[^>]*>/i)
      if (r2) {
        var objContainer = document.body;
        if (!objContainer) {
          objContainer = document.getElementsByTagName('head')[0];
          if (!objContainer) {
            objContainer = document;
          }
        }
        var objScript = document.createElement("SCRIPT");
        objScript.src = r2[1];
        objContainer.appendChild(objScript);
        continue;
      }
      r3 = r[i].split(/<\s*script[^>]*>/i);
      if (r3.length == 2) {
        strScript = r3[1].replace(/function\s+([^(]+)/g, '$1=function');
        strScript = strScript.replace(/^(\s*<!--|\s*<!\[CDATA\[)/,"");
        strScript = strScript.replace(/(-->\s*|\]\]>\s*)$/g,"");
        //alert(strScript);
        window.eval(strScript);
      }
    }
  }
}

//----------------- Get current path
TransAjax.setPath = function() {
  // Get last script element
  var objContainer = document.body;
  if (!objContainer) {
    objContainer = document.getElementsByTagName("head")[0];
    if (!objContainer)  objContainer = document;
  }
  var objScript = objContainer.lastChild;
  // Get path
  var path = "";
  var strSrc = objScript.getAttribute("src");
  if (strSrc) {
    var arrTokens = strSrc.split("/");
    // Remove last token
    arrTokens = arrTokens.slice(0, -1);
    if (arrTokens.length)
	  path = arrTokens.join("/") + "/";
  }
  TransAjax.path = path;
}
// -------------------- INITIALIZATION
TransAjax.setPath();
TransAjax.HTTPActiveX = TransAjax.getNameOfActiveX();
TransAjax.XMLActiveX = TransAjax.getXMLNameOfActiveX();




/*---------------- PHP serialization style support ----------------*/
function phpSerialize(val) {
  switch (typeof(val)) {
    case "number": return (Math.floor(val) == val ? "i" : "d") + ":" + val + ";";
    case "string": return "s:" + val.length + ":\"" + val + "\";";
    case "boolean": return "b:" + (val ? "1" : "0") + ";";
    case "object":
      if (val == null) {
        return "N;";
      } else if ("length" in val) { // collection
        var idxobj = {idx: -1 };
		return "a:" + val.length + ":{" + val.map(
          function (item) {
            this.idx++;
            var ser = phpSerialize(item);
            return ser ? phpSerialize(this.idx) + ser : false;
          }, idxobj).filter(
            function (item) {
              return item;
            }
          ).join("") + "}";
      } else {
        var class_name = getObjectClass(val);
        if (class_name == "undefined") {
          return false;
        }
        var props = new Array();
        for (var prop in val) {
          var ser = phpSerialize(val[prop]);
            if (ser) { props.push(phpSerialize(prop) + ser); }
        }
        return "O:" + class_name.length + ":\"" + class_name + "\":" + props.length + ":{" + props.join("") + "}";
      }
    case "undefined":
      return "N;";
    }
	return false;
}


function phpUnserialize(input) {
  var result = phpUnserialize_(input);
  return result[0];
}
/**
* Function which performs the actual unserializing
*
* @param string input Input to parse
*/
function phpUnserialize_(input) {
  var length = 0;
  switch (input.charAt(0)) {
    case 'a': // Array
      length = phpUnserialize_GetLength(input);
      input  = input.substr(String(length).length + 4);
      var arr   = new Array();
      var key   = null;
      var value = null;
      for (var i=0; i<length; ++i) {
        key = phpUnserialize_(input);
        input = key[1];
        value = phpUnserialize_(input);
        input = value[1];
		if (typeof(key[0]) == "number") {
          arr[key[0]] = value[0];
	    } else {
          eval("arr."+key[0]+" = '"+value[0]+"';");
		}
      }
      input = input.substr(1);
      return [arr, input];
    case 'O': // Objects
      length = phpUnserialize_GetLength(input);
      var classname = String(input.substr(String(length).length + 4, length));
      input  = input.substr(String(length).length + 6 + length);
      var numProperties = Number(input.substring(0, input.indexOf(':')))
      input = input.substr(String(numProperties).length + 2);
      var obj = new Object();
      var property = null;
      var value    = null;
      for (var i=0; i<numProperties; ++i) {
        key = phpUnserialize_(input);
        input = key[1];		
        // Handle private/protected
        key[0] = key[0].replace(new RegExp('^\x00' + classname + '\x00'), '');
        key[0] = key[0].replace(new RegExp('^\x00\\*\x00'), '');
        value = phpUnserialize_(input);
        input = value[1];
        obj[key[0]] = value[0];
      }
      input = input.substr(1);
      return [obj, input];
    case 's': //Strings
      length = phpUnserialize_GetLength(input);
      return [String(input.substr(String(length).length + 4, length)), input.substr(String(length).length + 6 + length)];
	case 'i': //Integers and doubles
    case 'd':
      var num = Number(input.substring(2, input.indexOf(';')));
      return [num, input.substr(String(num).length + 3)];
    case 'b': //Booleans
      var bool = (input.substr(2, 1) == 1);
      return [bool, input.substr(4)];
    case 'N': //Null
      return [null, input.substr(2)];
    // Unsupported
    case 'o':
    case 'r':
    case 'C':
    case 'R':
    case 'U':
      alert('Error: Unsupported PHP data type found!');
    default:
      return [null, null];
  }
}
function phpUnserialize_GetLength(input) {
  input = input.substring(2);
  var length = Number(input.substr(0, input.indexOf(':')));
  return length;
}
function getObjectClass(obj) {
 if (obj && obj.constructor && obj.constructor.toString) {
   var arr = obj.constructor.toString().match(/function\s*(\w+)/);
   if (arr && arr.length == 2) {
     return arr[1];
   }
 }
 return undefined;
}
