//
// ******************************************************************************************************
// *                                                                                                    *
// *                                  Javascript Classes and Functions                                  *
// *                                                                                                    *
// *  Class                                           Base Class                                        *
// *                                                                                                    *
// *    VCSH_Global                                     (n/a)                                           *
// *                                                                                                    *
// *    Classes from www.webtoolkit.info (freeware):    sprintfWrapper, Utf8                            *
// *                                                                                                    *
// ******************************************************************************************************
//

//
// ******************************************************************************************************
// *                                                                                                    *
// * Class VCSH_Global                                                                                  *
// *                                                                                                    *
// ******************************************************************************************************
//
// constructor
//
function VCSH_Global() { }
//
// protected (initializer)
//
VCSH_Global.prototype.init = function() { };
//
// public
//
VCSH_Global.prototype.sprint   = function() { return "VCSH_Global {" + this.toString() + "\n}"; };
VCSH_Global.prototype.toString = function() { return ""; };
//
// static
//
VCSH_Global.cache = {
  xsldoc : {}
};
VCSH_Global.errorMessage    = "";
VCSH_Global.getErrorMessage = function() {
  //
  // Consume the error message.
  //
  var s = "";
  if (VCSH_Global.errorMessage != "") {
    s = VCSH_Global.errorMessage;
    VCSH_Global.errorMessage = "";
  }
  return s;
};

VCSH_Global.and_128 = function(x, y) {
  return [Number(x[0]) & Number(y[0]), Number(x[1]) & Number(y[1]),
          Number(x[2]) & Number(y[2]), Number(x[3]) & Number(y[3]),
          Number(x[4]) & Number(y[4]), Number(x[5]) & Number(y[5]),
          Number(x[6]) & Number(y[6]), Number(x[7]) & Number(y[7])];
};

VCSH_Global.or_128 = function(x, y) {
  return [Number(x[0]) | Number(y[0]), Number(x[1]) | Number(y[1]),
          Number(x[2]) | Number(y[2]), Number(x[3]) | Number(y[3]),
          Number(x[4]) | Number(y[4]), Number(x[5]) | Number(y[5]),
          Number(x[6]) | Number(y[6]), Number(x[7]) | Number(y[7])];
};

VCSH_Global.not_128 = function(x) {
  return [0xffff ^ Number(x[0]), 0xffff ^ Number(x[1]), 0xffff ^ Number(x[2]), 0xffff ^ Number(x[3]),
          0xffff ^ Number(x[4]), 0xffff ^ Number(x[5]), 0xffff ^ Number(x[6]), 0xffff ^ Number(x[7])];
};

VCSH_Global.eq_128 = function(x, y) {
  if (x.length != y.length) return false;
  for (var i=0; i<x.length; i++) if (x[i] != y[i]) return false;
  return true;
};

//
// Input a 128-bit number from eight sixteen-bit unsigned integers.
//
VCSH_Global.makebits_128 = function(x0, x1, x2, x3, x4, x5, x6, x7) {
  return [Number(x0), Number(x1), Number(x2), Number(x3),
          Number(x4), Number(x5), Number(x6), Number(x7)];
};

//
// Make a 128-bit number with only bit x turned on.
//
VCSH_Global.makebit_128 = function(x) {
  if (Number(x) < 0 || Number(x) > 127) return FALSE;
  var z = [0, 0, 0, 0, 0, 0, 0, 0];
  z[Number(x) >> 4] = 1 << (Number(x) & 15);
  return z;
};

//
// Find the lowest y bit.
//
VCSH_Global.bit_128 = function(x, y) {
  if (Number(y)) {
    for (var j=0; j<x.length; j++) for (var i=0; i<16; i++) if (Number(x[j]) & (1 << i)) return i + 16 * j;
  } else {
    for (var j=0; j<x.length; j++) for (var i=0; i<16; i++) if (!(Number(x[j]) & (1 << i))) return i + 16 * j;
  }
  return false;
};

//
// Find the set of positions of all $y (0 or 1) bits.
//
VCSH_Global.bits_128 = function(x, y) {
  var z = [];
  if (Number(y)) {
    for (var j=0; j<x.length; j++) for (var i=0; i<16; i++) if (Number(x[j]) & (1 << i)) z.push(i + 16 * j);
  } else {
    for (var j=0; j<x.length; j++) for (var i=0; i<16; i++) if (!(Number(x[j]) & (1 << i))) z.push(i + 16 * j);
  }
  return z;
};

VCSH_Global.hex_128 = function(x) {
  //
  // Format a 128-bit number as an array of 16-digit hex strings.
  //
  return {_00 : sprintf('%04x%04x%04x%04x', Number(x[3]), Number(x[2]), Number(x[1]), Number(x[0])),
          _01 : sprintf('%04x%04x%04x%04x', Number(x[7]), Number(x[6]), Number(x[5]), Number(x[4]))};
};

//
// ******************************************************************************************************
// *                                                                                                    *
// * RPC queries (see the PHP fuction VCSH_Global.query() in class_Global.php).                         *
// * Note:  These can be used only while logged in to the server.                                       *
// *                                                                                                    *
// ******************************************************************************************************
//
VCSH_Global.query = function(server, q) {
  if (q === null) {
    result = null;
  } else if (typeof q == "function") {
    //
    // Asynchronous XML-RPC query.
    //
    var args = [];
//***** Convert strings to base64, just to be safe ...
    for (var i=3; i<arguments.length; i++) args.push(typeof arguments[i] == "string" ?
      new xmlrpcval(arguments[i],"base64") : xmlrpc_encode(arguments[i]));
//***** ... or don't, and live dangerously.
//  for (var i=3; i<arguments.length; i++) args.push(xmlrpc_encode(arguments[i]));
//*****
    var client = new xmlrpc_client(TRANSPORT + server + "/index.php?s=AJAX");
    result = client.send(new xmlrpcmsg(arguments[2], args), 0, q);
  } else if (typeof q == "object" && q instanceof Array) {
    //
    // Multi-call XML-RPC query.
    //
    var request = [];
    for (var i=0; i<q.length; i++) {
      var args = [];
//***** Convert strings to base64, just to be safe ...
      for (var j=1; j<q[i].length; j++) args.push(typeof q[i][j] == "string" ?
        new xmlrpcval(q[i][j],"base64") : xmlrpc_encode(q[i][j]));
//***** ... or don't, and live dangerously.
//    for (var j=1; j<q[i].length; j++) args.push(xmlrpc_encode(q[i][j]));
//*****
      request.push(new xmlrpcmsg(q[i][0], args));
    }
    var client = new xmlrpc_client(TRANSPORT + server + "/index.php?s=AJAX");
    client.no_multicall = true;
    // client.debug = true;
    var result = client.send(request, 0);
    if (typeof result == "object" && result instanceof Array) for (var i=0; i<result.length; i++) {
      if (result[i].faultCode()) VCSH_Global.errorMessage +=
        "RPC Error " + result[i].faultCode() + ": " + result[i].faultString() + "\n";
      result[i] = request[i].parseResponse(result[i].raw_data);
      if (typeof result[i] == "string") {
        VCSH_Global.errorMessage += "RPC Error: xmlrpcmsg.parseResponse() returned a string\n";
        result[i] = null;
      } else if (typeof result[i].value() == "object") {
        result[i] = result[i].value();
        if (typeof result[i] == "object" && result[i] instanceof xmlrpcval)
          result[i] = xmlrpc_decode(result[i]);
      } else {
        result[i] = null;
      }
    }
  } else {
    //
    // Simple XML-RPC query.
    //
    var args = [];
//***** Convert strings to base64, just to be safe ...
    for (var i=2; i<arguments.length; i++) args.push(typeof arguments[i] == "string" ?
      new xmlrpcval(arguments[i],"base64") : xmlrpc_encode(arguments[i]));
//***** ... or don't, and live dangerously.
//  for (var i=2; i<arguments.length; i++) args.push(xmlrpc_encode(arguments[i]));
//*****
    var request = new xmlrpcmsg(q, args);
    var client = new xmlrpc_client(TRANSPORT + server + "/index.php?s=AJAX");
    // client.debug = true;
    var result = client.send(request, 0);
    if (result.faultCode()) VCSH_Global.errorMessage +=
      "RPC Error " + result.faultCode() + ": " + result.faultString() + "\n";
    result = request.parseResponse(result.raw_data);
    if (typeof result == "string") {
      VCSH_Global.errorMessage += "RPC Error: xmlrpcmsg.parseResponse() returned a string\n";
      result = null;
    } else if (typeof result.value() == "object") {
      result = result.value();
      if (typeof result == "object" && result instanceof xmlrpcval) result = xmlrpc_decode(result);
    } else {
      result = null;
    }
  }
  return result;
};
//
// Process the response to an asynchronous query.
//
VCSH_Global.response = function(result) {
  if (result.faultCode()) VCSH_Global.errorMessage +=
    "RPC Error " + result.faultCode() + ": " + result.faultString() + "\n";
  var result = (new xmlrpcmsg).parseResponse(result.raw_data);
  if (typeof result == "string") {
    VCSH_Global.errorMessage += "RPC Error: xmlrpcmsg.parseResponse() returned a string\n";
    result = null;
  } else if (typeof result.value() == "object") {
    result = result.value();
    if (typeof result == "object" && result instanceof xmlrpcval) result = xmlrpc_decode(result);
  } else {
    result = null;
  }
  return result;
};

//
// ******************************************************************************************************
// *                                                                                                    *
// *    Classes from www.webtoolkit.info (freeware):    sprintfWrapper, Utf8                            *
// *                                                                                                    *
// ******************************************************************************************************
//
/**
*
*  Javascript sprintf
*  http://www.webtoolkit.info/
*
*
**/

sprintfWrapper = {

	init : function () {

		if (typeof arguments == "undefined") { return null; }
		if (arguments.length < 1) { return null; }
		if (typeof arguments[0] != "string") { return null; }
		if (typeof RegExp == "undefined") { return null; }

		var string = arguments[0];
		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
		var matches = new Array();
		var strings = new Array();
		var convCount = 0;
		var stringPosStart = 0;
		var stringPosEnd = 0;
		var matchPosEnd = 0;
		var newString = '';
		var match = null;

		while (match = exp.exec(string)) {
			if (match[9]) { convCount += 1; }

			stringPosStart = matchPosEnd;
			stringPosEnd = exp.lastIndex - match[0].length;
			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);

			matchPosEnd = exp.lastIndex;
			matches[matches.length] = {
				match: match[0],
				left: match[3] ? true : false,
				sign: match[4] || '',
				pad: match[5] || ' ',
				min: match[6] || 0,
				precision: match[8],
				code: match[9] || '%',
				negative: parseInt(arguments[convCount]) < 0 ? true : false,
				argument: String(arguments[convCount])
			};
		}
		strings[strings.length] = string.substring(matchPosEnd);

		if (matches.length == 0) { return string; }
		if ((arguments.length - 1) < convCount) { return null; }

		var code = null;
		var match = null;
		var i = null;

		for (i=0; i<matches.length; i++) {

			if (matches[i].code == '%') { substitution = '%' }
			else if (matches[i].code == 'b') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'c') {
				matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'd') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'f') {
				matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'o') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 's') {
				matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'x') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'X') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
			}
			else {
				substitution = matches[i].match;
			}

			newString += strings[i];
			newString += substitution;

		}
		newString += strings[i];

		return newString;

	},

	convert : function(match, nosign){
		if (nosign) {
			match.sign = '';
		} else {
			match.sign = match.negative ? '-' : match.sign;
		}
		var l = match.min - match.argument.length + 1 - match.sign.length;
		var pad = new Array(l < 0 ? 0 : l).join(match.pad);
		if (!match.left) {
			if (match.pad == "0" || nosign) {
				return match.sign + pad + match.argument;
			} else {
				return pad + match.sign + match.argument;
			}
		} else {
			if (match.pad == "0" || nosign) {
				return match.sign + match.argument + pad.replace(/0/g, ' ');
			} else {
				return match.sign + match.argument + pad;
			}
		}
	}
}

sprintf = sprintfWrapper.init;

/**
*
*  UTF-8 data encode / decode
*  http://www.webtoolkit.info/
*
**/

var Utf8 = {

	// public method for url encoding
	encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// public method for url decoding
	decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = 0, c1 = 0, c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}

/**
*
*  UTF-8 data encode / decode
*  http://www.webtoolkit.info/
*
**/

var Utf8 = {

	// public method for url encoding
	encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// public method for url decoding
	decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = 0, c1 = 0, c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}
