//////////////////////////////////////////////////////////////
// usage GetData(url, vars, targets, defaults) or GetData(arrayRef)
// <span onmousedown="GetData(
// '/cgi-bin/some.pl',                     // 1. URL to fetch
// ['a=1&b=2', 'form1.name1'],             // 2. Vars to send to URL.
// ['element', 'form.field', 'new.xhr.obj']// 3. Targets to deliver answers to.
// '<!--<label>-->value<!--</label>-->',   // 4. Default return string (optional)
// )">click</span>
//
// 1. A URL on the current domain. eg '/cgi-bin/some.pl?' or './about.txt'
//    If data might change, add "?" to force refresh in IE.
//    Use '' or '#' to disable request to URL and use default return.
//    Default submit method is 'GET'. Add "?P" to force POST.
//
// 2. Vars to send to URL.
//    a. A 'get' string. eg 'a=1&b=2'
//    b. A reference to a form.field value eg 'form1.name1'
//    c. An array of both eg ['a=1&b=2', 'form1.name1', 'form1.name2']
//
//    Access history using special vars: 'BACK=0', 'FWD=0'
//
// 3. Target fields:
//    a. A reference to a form.field eg 'form1.name1'
//    b. A reference to a body ElementId. eg 'area1'
//    c. A reference to an xhrArray object name. eg 'my.hidden.element'
//    d. An array of both eg ['area1', 'form1.address', 'form1.tel']
//    'id:subtype' or 'formname.fieldname:subtype' allows result selection from a multiple value return string
//
//    The target values specify the nameset for the xmlresponse tags and the document targets.
//    For each target, empty xmlresponse tags or no tags clears the target.
//
//    A string value for the target is a special case.
//    It returns the whole xmlresponse if tagged values dont exist.
//    Returns std "File not found.." if URL does not exist.
//    
// 4. Defaults, appended to the returned data string.
//    a. A string. 
//       eg '<!--<form2.rate>-->15<!--</form2.rate>-->'
//       or 'hello world' (applies single string target)
//    b. An array of strings.
//       eg ['<!--<area1>-->Something<!--</area1>-->',
//           '<!--<form1.name1>-->George<!--</form1.name1>-->']
//       Any array value being a valid form.field reference will be substituted.
//       eg ['<!--<area1>-->', 'form1.field1a', '<!--</area1>-->']
//       The array is joined without spaces for processing.
//
//    The URL is expected to return normal html headers plus data.
//
//    Data can be:
//  1. A hash of 'text or html' data within named tags.
//         eg "<!--<area1>-->Area 1 text goes here<!--</area1>-->
//             <!--<form1.name1>-->George<!--</form1.name1>-->"
//    Contents of first match is returned to each specified target formfield or ElementId.
//    Returned values, override any defaults. 
//
//  2. A slab of text or html with no target tags.
//     If tags are not found, then the entire response is used.
//     * This applies only for a single 'non-array' print target.
//
//  Note: 
//     Default string is ignored if URL is defined and 'targets' is a single string.   
//     Default string specifies the value where no tagged response is returned.
//
//  Thus:
//   GetData('Some file.txt', '', 'here');
//   GetData('#', '', 'there', 'Put this');
//   GetData('', '', 'there', ['Put this', '<BR>and this']);
//   GetData('', '', 'there', '<!--<there>-->Put this<!--</there>-->');
//   GetData('Some.pl', 'a=1&b=2', ['there', 'perlystuffhere'], '<!--<there>-->Put this<!--</there>-->');
//   <input type="text" name="typehere" onkeyup="GetData('#', '', 'targetid', ['formname.typehere'])"
//   GetData('#', 'BACK=0');    GetData('#', 'FWD=0')
//
//  GetData also accepts a reference to:
//
//   An array of strings and/or arrays.
//    var myArray = new Array('', '', 'there', ['hello', 'world']);
//    GetData(myArray);
//
//   A function returning an array of strings and/or arrays
//    var vars = new Array('a=1&b=2', 'c=3');
//    xhrArray('set', 'urls.test', ['#', vars, 'there']);
//    GetData(xhrArray('read', 'urls.test'));
//
//   A window object returning an array of strings and/or arrays
//    GetData(register.urls.test);               // causes error if object not defined
//   
//////////////////////////////////////////////////////////////

function XHConn() {
 var xmlhttp, bComplete = false;
 try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
 catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
 catch (e) { try { xmlhttp = new XMLHttpRequest(); }
 catch (e) { xmlhttp = false; }}}
 if (!xmlhttp) return null;
 this.connect = function(sURL, sMethod, sVars, fnDone) {
  if (!xmlhttp) return false;
  bComplete = false;
  sMethod = sMethod.toUpperCase();
  try {
   if (sMethod == "GET") {
    xmlhttp.open(sMethod, sURL+"?"+sVars, true);
    sVars = "";
   } else {
    xmlhttp.open(sMethod, sURL, true);
    xmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
   }
   xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && !bComplete) {
     bComplete = true;
     fnDone(xmlhttp);
    }
   };
   xmlhttp.send(sVars);
// alert('hi'); // test pause before returning
  }
  catch(z) { return false; }
  return true;
 };
 return this;
}

function escApos(instring) {  // as in <form.. value=\'', escApos(this.innerHTML), '\'>
 var escaped = "";
 for (var i = 0; i < instring.length; i++ ) {
  var ch = instring.charAt(i);
  if (ch == "'") {
   escaped += "&apos;";
  } else {
   escaped += ch;
  }
 }
 return escaped;
}


function URLEncode(varstring) {
 // [a-zA-Z0-9] plus RFC2396 Mark characters
 var SAFECHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
 var HEX = "0123456789ABCDEF";
 var encoded = "";
 for (var i = 0; i < varstring.length; i++ ) {
  var ch = varstring.charAt(i);
  if (ch == " ") {
   encoded += "+";				// x-www-urlencoded, rather than %20
  } else if (SAFECHARS.indexOf(ch) != -1) {
   encoded += ch;
  } else {
   var charCode = ch.charCodeAt(0);
   if (charCode > 255) {
    encoded += "+";
   } else {
    encoded += "%";
    encoded += HEX.charAt((charCode >> 4) & 0xF);
    encoded += HEX.charAt(charCode & 0xF);
   }
  }
 }
 return encoded;
};

function GetData (url, variables, targets, xmlstrings) {
 if (typeof(url) == 'object') { // if url is array, use as inputs
  var spec = url;
  url = spec[0];
  variables  = spec[1];
  targets = spec[2];
  xmlstrings = spec[3]
 }
 var vars = "";
 var vartype = typeof (variables);
 if (vartype == 'string') {
  var variablesstring = variables;
  variables = new Array();
  variables[0] = variablesstring;
 }
 for(var n = 0; n < variables.length; n++) {
  var formvar = variables[n].split(".");
  var thisvarval = variables[n].split("=");
  var thispair = "";
  var thisval = "";
  if (thisvarval[1]) {
   thispair = variables[n];
  } else {
   if (formvar[1]) {
    thisval = URLEncode (document[formvar[0]][formvar[1]].value);
    thispair = formvar[1]+"="+thisval;
   } else { // assume form name is 'form'
    if (formvar[0]) {
     thisval = URLEncode (document.form[formvar[0]].value);
     thispair = formvar[1]+"="+thisval;
    }
   }
  }
  vars += thispair+"&";
 }
 var mymethod = 'GET';
 var undefined;
 var urlsplit = url.split('?'); 
 if (urlsplit[1] != undefined) {
  url = urlsplit[0];
  vars += Math.round(100000*Math.random());
  if (urlsplit[1] == 'P') {
   mymethod = 'POST';
  }
 }
 if (vars.length > 512) {
  mymethod = 'POST';
 }
 var xmlstring = '';
 if (xmlstrings) {
  vartype = typeof (xmlstrings);
  if (vartype == 'string') {
  xmlstring = xmlstrings;
  } else {
   for(var n = 0; n < xmlstrings.length; n++) {
    if (xmlstrings[n]) {
     if (xmlstrings[n].match(/^[-\w]+\.[-\w]+$/))  {
      var xmlvar = xmlstrings[n].split(".");
      if ( typeof document[xmlvar[0]] != "undefined")  {
       if ( typeof document[xmlvar[0]][xmlvar[1]] != "undefined")  { 
        xmlstring += document[xmlvar[0]][xmlvar[1]].value;
       }else {
        xmlstring += xmlstrings[n];
       }
      } else {
       xmlstring += xmlstrings[n];
      }
     } else {
      xmlstring += xmlstrings[n];
     }
    }
   }
  }
 }


 var params = new Array(url, vars, targets, xmlstring);
 if (vars == 'BACK=0&') {
  if (xhrArray('read', 'history.back')) {
   params = xhrArray('shift', 'history.back');
   xhrArray('unshift', 'history.fwd', xhrArray('read', 'history.now'));
   xhrArray('set', 'history.now', params);
  } else {
   alert('history.back is empty');
   params = xhrArray('read', 'history.now');
  }
 } else if (vars == 'FWD=0&') {
  if (xhrArray('read', 'history.fwd')) {
   params = xhrArray('shift', 'history.fwd');
   xhrArray('unshift', 'history.back', xhrArray('read', 'history.now'));
   xhrArray('set', 'history.now', params);
  } else {
   alert('history.fwd is empty');
   params = xhrArray('read', 'history.now');
  }
 } else {
  xhrArray('unshift', 'history.back', xhrArray('read', 'history.now'));
  xhrArray('set', 'history.now', params);
  xhrArray('del', 'history.fwd');
 }
 url = params[0];
 vars = params[1];
 targets = params[2];
 xmlstring = params[3];

 var myConn = new XHConn(); 

 if (myConn) {
  if (url == '') {
   url = "#";
  }
  if (url) {
   var fnWhenDone = function (oXML) {
    var xmlresponsetext = '';
    if (url == "#") {
     xmlresponsetext = xmlstring;
    } else {
     if (oXML.responseText) {
      xmlresponsetext = oXML.responseText;
     }
    }
    var targettype = typeof (targets);
    if (targettype == 'string') {               // convert to array(1)
     var targetstring = targets;
     targets = new Array();
     targets[0] = targetstring;
    } else {
     xmlresponsetext += xmlstring;
    }
    for(var i = 0; i < targets.length; i++) {
     var value = undefined;
     var opentag = "<!--<"+targets[i]+">-->";
     var closetag = "<!--<\/"+targets[i]+">-->";
     var opensplit = xmlresponsetext.split(opentag);
     if (opensplit[1]) {
      var postopen = opensplit[1]+"\n";         // so split[1] exists
      var closesplit = postopen.split(closetag);
      if (closesplit[1]) {
       value = closesplit[0];
      }
     }
     if (value == undefined) {
      if (targettype == 'string') {
       value = xmlresponsetext;
      } else {
       value = "";
      }
     }
     if (!(value == undefined)) {
      var target = "";
      var subtype = "";
      var typesplit = targets[i].split(":");
      if (typesplit[1]) {
       subtype = typesplit[1];
       target = typesplit[0].split(".");
      }else {
       target = targets[i].split(".");
      }
      if (target[2]) {
       xhrArray('set', target[0] + "." + target[1] + "." + target[2], value);
      } else {
       if (target[1]) {                              // form id
        if (document[target[0]][target[1]]) {        // ignore non existent target
         document[target[0]][target[1]].value=value; // watch line feeds in value
        }
       } else {
        if (target[0]) {                             // document id
         if (document.getElementById(target[0])) {   // ignore non existent
          document.getElementById(target[0]).innerHTML=value;
         }                                           
        }
       }
      }
     }
    }
   };
   if (url == '#') {
    fnWhenDone();
   } else {
    myConn.connect(url, mymethod, vars, fnWhenDone);
   }
  }
 } else {
  alert("XMLHTTP not available. Try a newer/better browser.");
 }
};

