if (typeof com == "undefined") {
  com = {};
}
else if (typeof com != "object") {
  alert("failed to create 'com'.");
  throw new Error("'com' is already defined and is not an object. Unable to create namespace.");
}

if (typeof com.tteconline == "undefined") {
  com.tteconline = {};
}
else if (typeof com.tteconline != "object") {
  throw new Error("'com.tteconline.com' is already defined and is not an object. Unable to create namespace.");
}

if (typeof com.tteconline.web == "undefined") {
  com.tteconline.web = {};
}
else if (typeof com.tteconline.web != "object") {
  throw new Error("'com.tteconline.web' already exists and is not an object. Unable to create namespace.");
}

/* Library versioning and information. */
com.tteconline.web.info = {
  "Version" : "1.0.0.0",
  "Author"  : "Craig E. Shea, Thermocouple Technology, Inc.",
  "Copyright": "Copyright (c)2007 Craig E. Shea, Thermocouple Technology, Inc. All rights reserved."
}

com.tteconline.web.browser = {
  isIE : function() { return navigator.userAgent.indexOf("MSIE") > 0 ? true : false; },
  isFirefox : function() { return (navigator.userAgent.indexOf("Firefox") > 0 || navigator.userAgent.indexOf("FireFox") > 0) ? true : false; },
  isSafari : function() { return navigator.userAgent.indexOf("Apple") > 0 ? true : false; },
  isOpera : function() { return navigator.userAgent.indexOf("Opera") > 0 ? true : false; },
  isLinks : function() { return navigator.userAgent.indexOf("Links") > 0 ? true : false; },
  isLynx : function() { return navigator.userAgent.indexOf("Lynx") > 0 ? true : false; }
};

com.tteconline.web.utilities = { 
  preloadImages: function( images ) {
    for (img in arguments) {
      var i = new Image();
      i.src = img;
    }
  }
};


if (typeof com.tteconline.xml == "undefined")
  com.tteconline.xml = { };
else if (typeof com.tteconline.xml != "object")
  throw new Error("'com.tteconline.xml' already exists and is not an ojbect!");

com.tteconline.xml.createDocument = function( rootTag, namespace ) {
  var _rootTag = "";
  var _namespace = "";

  if (rootTag) _rootTag = rootTag;
  if (namespace) _namespace = namespace;

  if (document.implementation && document.implementation.createDocument) {
    // This is the W3C standard way of doing things.
    return document.implementation.createDocument(namespace, rootTag, null);
  }
  else { // Then, there is IE's way of doing things...
    // Create an empty document as an ActiveX object.
    // If there is no root element, this is all we have to do:
    var doc = new ActiveXObject("Msxml2.DOMDocument");

    // If there is a root tag, initialize the document
    if (rootTag) {
      // Look for a namespace prefix.
      var prefix = "";
      var tagName = rootTag;
      var nsPos = rootTag.indexOf(':');
      if (nsPos != -1) {
        prefix = rootTag.substring(0, nsPos);
        tagName = rootTag.substring(nsPos+1);
      }

      // If we have a namespace, we must have a namespace prefix.
      // If we don't have a namespace, we discard any prefix.
      if (namespace)
        if (!prefix) prefix = "a0"; // This is what Firefox uses if no namespace is given.
      else
        prefix = "";

      // Create the root element (with the optional namespace) as a string of text.
      var text = "<" + (prefix ? (prefix + ":") : "") + tagName + (namespace ? (" xmlns:" + prefix + "=\"" + namespace + "\"") : "") + "/>";

      // And parse that text into the empty document.
      doc.loadXML(text);
    }

    return doc;
  }
}

com.tteconline.xml.openDocument = function ( documentUrl ) {
  // Create a new document with the previously defined function.
  var doc = com.tteconline.xml.createDocument();

  // Now let's set some attributes of our XML document.
  doc.async = false;       // We want to load synchronously
  doc.load( documentUrl ); // Load and parse.
  return doc;              // Return our loaded and parsed document.
}

com.tteconline.xml.xsltTransformer = function ( stylesheet ) {
  var _processor, _xmlStylesheet;
  
  if (typeof stylesheet == "string" && stylesheet != "")
    _xmlStylesheet = com.tteconline.xml.OpenDocument(stylesheet);
  else if ((!com.tteconline.web.browser.isIE() && stylesheet instanceof XMLDocument) ||
           (com.tteconline.web.browser.isIE() && typeof stylesheet != "string"))
    _xmlStylesheet = stylesheet;
  else
    throw new Error("Error: 'com.tteconline.xml.xsltTransformer': stylesheet\nExpected a non-empty string argument.");

  // In Mozilla-based browsers, create an XSLTProcessor object and tell it about the stylesheet.
  if (typeof XSLTProcessor != "undefined") {
    _processor = new XSLTProcessor();
    _processor.importStylesheet(_xmlStylesheet);
  }

  this.property_getProcessor = function ( ) { return _processor; }
  this.property_getXmlStylesheet = function( ) { return _xmlStylesheet; }
}

com.tteconline.xml.xsltTransformer.prototype.getProcessor = function ( ) { return this.property_getProcessor(); }
com.tteconline.xml.xsltTransformer.prototype.getXmlStylesheet = function ( ) { return this.property_getXmlStylesheet(); }

com.tteconline.xml.xsltTransformer.prototype.transformNode = function (node, element) {
  // If we're using a Mozilla-based browser and, therefore, 'processor' is not undefined, use it.
  if (this.property_getProcessor()) {
    // Transform the node into a DOM DocumentFragment
    var fragment = (this.property_getProcessor()).transformToFragment(node, document);

    // If an element wasn't passed in, return the document fragment.
    if (typeof element == "undefined") return fragment;

    // Otherwise, erase the existing content of the element.
    element.innerHTML = "";
    // Now insert the transformed nodes.
    element.appendChild(fragment);
  }
  else if ("transformNode" in node) {  // If the node has transformNode(), we're in IE, so just use that.
    // Note that transformNode() returns a string.

    // If we are not replacing a DOM element, but instead want to return the transformed XML...
    if (typeof element == "undefined") return node.transformNode(this.getXmlStylesheet());

    // Otherwise, replace the element's contents with the transformed XML.
    element.innerHTML = node.transformNode(this.getXmlStylesheet());
  }
  else { //, this browser does not support XSLT.
    throw new Error("'com.tteconline.xml.xmltTransformer.transformNode': XSLT is not supported by this browser.");
  }
}

com.tteconline.xml.xpathExpression = function ( xpathQuery, namespaces ) {
  var _xpathQuery = xpathQuery;   // Save the text of the xpath query expression.
  var _namespaces = namespaces;   // Save any namespace mappings.
  var _xpathExpr;
  var _IENamespaceString;

  if (document.createExpression) {
    // If we,re in a W3C-compliant browser, use the W3C API to compile the text of the XPath query.
    _xpathExpr = document.createExpression(_xpathQuery, // This function is passed a namespace prefix
                                                        // and returns the URL.
                                                        function (prefix) { return _namespaces[prefix];});
  }
  else {
    // Otherwise, we're probably running in IE and must convert the namespaces object into the textual
    // form that IE requires.
    _namespaces = "";
    if (namespaces != null) {
      for (var prefix in namespaces) {
        // Add a space if there is already something there.
        if (_namespaces) _namespaces += " ";
        // Add the namespace.
        _namespaces += "xmlns:" + prefix + "=\"" + namespaces[prefix] + "\"";
      }
    }
  }

  this.property_setXPathQuery = function ( xpathQuery ) {
    if (typeof xpathQuery == "string")
      _xpathQuery = xpathQuery;
    else
      throw new Error("'com.tteconline.xml.xpathExpression.XPathQuery': Invalid argument exception: 'xpathQuery'\nExpected a string argument.");
  }
  this.property_getXPathQuery = function ( ) { return _xpathQuery; }

  this.property_setNamespaces = function ( namespaces ) {
    if ( typeof namespaces == "string" )
      _namespaces = namespaces;
    else
      throw new Error("'com.tteconline.xml.xpathExpression.Namespaces': Invalid argument exception: 'namespaces'\nExpected a string argument.");
  }
  this.property_getNamespaces = function( ) { return _namespaces; };

  this._getXPathExpr = function ( xpathQuery ) { return _xpathExpr; }
}

com.tteconline.xml.xpathExpression.prototype.xpathQuery = function ( xpathQuery ) {
  if (typeof xpathQuery != "undefined")
    this.property_setXPathQuery(xpathQuery);
  else
    return this.property_getXPathQuery();
}

com.tteconline.xml.xpathExpression.prototype.namespaces = function ( namespaces ) {
  if (typeof namespaces != "undefined")
    this.property_setNamespaces(namespaces);
  else
    return this.property_getNamespaces();
}

com.tteconline.xml.xpathExpression.prototype.getNode = function ( context ) {
  if (this._getXPathExpr()) {
    var result = this._getXPathExpr().evaluate(context, // We want just the first match...
                                                        XPathResult.FIRST_ORDERED_NODE_TYPE, null);

    return result.singleNodeValue;
  }
  else {
    try {
      var doc = context.ownerDocument;

      if (doc == null) doc = context;

      doc.setProperty("SelectionLanguage", "XPath");
      doc.setProperty("SelectionNamespaces", this.property_getNamespaces());

      if (context == doc) context = doc.documentElement;

      // In IE, call selectSingleNode instead of selectNodes
      return context.selectSinglenode(com.tteconline.xml.xpathExpression.property_getXPathQuery());
    }
    catch (e) {
      throw new Error("'com.tteconline.xml.xpathExpression.getNode()': XPath not supported by this browser.\n" + e.message);
    }
  }
}

com.tteconline.xml.xpathExpression.prototype.getNodes = function ( context ) {
  if (this._getXPathExpr()) {
    // If we are in a W3C-compliant browser, we compiled the expression in the constructor. We now
    // evaluate that compiled expression in the specified context.
    var result = this._getXPathExpr().evaluate(context, // We want all matching nodes...
                                                        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

    // Copy the results we get into an array...
    var a = new Array(result.snapshotLength);

    for (var i = 0; i < result.snapshotLength; i++) {
      a[i] = result.snapshotItem(i);
    }

    return a;
  }
  else {
    // If we are not in a W3C-compliant browser, attempt to evaluate the expression using the IE API.
    try {
      // We need the Document object to specify namespaces
      var doc = context.ownerDocument;

      // If the context doesn't have ownerDocument, it is the Document...
      if (doc == null) doc = context;

      // This is IE-specific magic to specify prefix-to-URL mapping...
      doc.setProperty("SelectionLanguage", "XPath");
      doc.setProperty("SelectionNamespaces", this.property_getNamespaces());

      // In IE, the context must be an Element, not a Document, so if context is the Document, use
      // documentElement instead.
      if (context == doc) context == doc.documentElement;

      // Now use the IE method selectNodes() to evaluate the expression.
      return context.selectNodes(this._getXPathExpr());
    }
    catch (e) {
      // If the IE API doesn't work, we just give up...
      throw new Error("'com.tteconline.xml.xpathExpression.getNodes()': XPath not supported by this browser.\n" + e.message);
    }
  }
}

com.tteconline.xml.getNode = function (context, xpathExpr, namespaces) {
  return (new com.tteconline.xml.xpathExpression(xpathExpr, namespaces)).getNode(context);
}

com.tteconline.xml.getNodes = function (context, xpathExpr, namespaces) {
  return (new com.tteconline.xml.xpathExpression(xpathExpr, namespaces)).getNodes(context);
}

com.tteconline.xml.transformNode = function (xmldoc, stylesheet, element) {
  var transformer = new com.tteconline.xml.xsltTransformer(stylesheet);

  transformer.transformNode(xmldoc, element);
}