//#############################################################################
// Begin class MQBrowser
//#############################################################################
/**
 * Constructs a new MQBrowser object.
 * @class Class that will contain all information about
 * the browser in which the code is running.
 * @private
 */
function MQBrowser(){
   /** @type String
    */
   this.name       = null;
   /** @type String
    */
   this.version    = null;
   /** @type String
    */
   this.os       = null;
   /** @type String
    */
   this.appname    = null;
   /** @type String
    */
   this.appVersion = null;
   /** @type String
    */
   this.vMajor    = null;
   /** @type Boolean
    */
   this.isNS       = null;
   /** @type Boolean
    */
   this.isNS4      = null;
   /** @type Boolean
    */
   this.isNS6      = null;
   /** @type Boolean
    */
   this.isIE       = null;
   /** @type Boolean
    */
   this.isIE4      = null;
   /** @type Boolean
    */
   this.isIE5      = null;
   /** @type Boolean
    */
   this.isDOM      = null;
   /** @type Boolean
    */
   this.isSafari   = null;
   /** @type String
    */
   this.platform   = null;
}
// End class MQBrowser


//#############################################################################
// Browser  code
//#############################################################################
/**
 * Get Browser info for functions.
 * @return Returns a Browser object.
 * @type MQBrowser
 * @private
 */
function mqGetBrowserInfo()
{
    var browser             = new MQBrowser();
    browser.name            = browser.version = browser.os = "unknown";
    var userAgent           = window.navigator.userAgent.toLowerCase();
    var appname             = window.navigator.appName;
    var appVersion          = window.navigator.appVersion;
    var browserListArray    = new Array("firefox", "msie", "netscape", "opera", "safari");
    var osListArray         = new Array("linux", "mac", "windows", "x11");
    var browserListlength   = browserListArray.length;
    var strPosition         = "";
    for(var i = 0, n = browserListlength; i < n; i++)
    {   // get browser name and version
        strPosition = userAgent.indexOf(browserListArray[i]) + 1;
        if(strPosition > 0)
        {
            browser.name = browserListArray[i]; // browser name

            var versionPosition = strPosition + browser.name.length;
            var incr = ((browser.name == "safari") || (userAgent.charAt(versionPosition + 4) > 0 && userAgent.charAt(versionPosition + 4) < 9)) ? 5 : 3;
            browser.version     = userAgent.substring(versionPosition, versionPosition + incr); // browser version
        }
    }
    var osListArrayLength = osListArray.length;
    for(var j = 0, m = osListArrayLength; j < m; j++)
    {
        strPosition = userAgent.indexOf(osListArray[j]) + 1;
        if(strPosition > 0)
        {
            browser.os  = osListArray[j];
        }
    }

    if (appname == "Netscape")
        browser.appname = "ns";
    else if (appname == "Microsoft Internet Explorer")
        browser.appname = "ie";

    browser.appVersion = appVersion;
    browser.vMajor  = parseInt(browser.appVersion);
    browser.isNS    = (browser.appname =="ns" && browser.vMajor >= 4);
    browser.isNS4   = (browser.appname =="ns" && browser.vMajor == 4);
    browser.isNS6   = (browser.appname =="ns" && browser.vMajor == 5);
    browser.isIE    = (browser.appname =="ie" && browser.vMajor >= 4);
    browser.isIE4   = (browser.appVersion.indexOf ('MSIE 4')   >0);
    browser.isIE5   = (browser.appVersion.indexOf ('MSIE 5')   >0);
    browser.isDOM   = (document.createElement
                    && document.appendChild
                    && document.getElementsByTagName) ? true : false;
                    
   browser.isSafari = (browser.name == "safari");
    if (userAgent.indexOf ("win") > - 1)
        browser.platform = "win";
    else if (userAgent.indexOf("mac") > -1)
        browser.platform = "mac";
    else
        browser.platform="other";

    return browser;

} //getBrowserInfo()

var mqBrowserInfo = mqGetBrowserInfo();


//#############################################################################
// Begin class MQObject
//#############################################################################
/**
 * Constructs a new MQObject object.
 * @class Base class for almost all objects in 
 * the api.
 */
function MQObject(){
   /**
    * Value to represent the xml
    * @type Document
    * 
    */
   var m_xmlDoc = null;
   /**
    * Returns the m_xmlDoc object.
    * @return The m_xmlDoc object.
    * @type Document
    * 
    */
   this.getM_XmlDoc = function() {
      return m_xmlDoc;
   };   
   /**
    * Sets the m_xmlDoc object.
    * @param {Document} xmlDoc the Document to set m_xmlDoc to.
    * @type void
    * 
    */
   this.setM_XmlDoc = function(xmlDoc) {
      m_xmlDoc = xmlDoc;
   };   
   /**
    * Value to represent the xpath of this object
    * @type Document
    * 
    */
   var m_xpath = null;
   /**
    * Returns the m_xpath string.
    * @return The m_xpath string.
    * @type String
    * 
    */
   this.getM_Xpath = function() {
      return m_xpath;
   };   
   /**
    * Sets the m_xpath object.
    * @param {String} xpath the String m_xpath is set to.
    * @type void
    * 
    */
   this.setM_Xpath = function(xpath) {
      m_xpath = xpath;
   };
}
   /**
    * Returns the text name of this class.
    * @return The text name of this class.
    * @type String
    */
   MQObject.prototype.getClassName = function(){
      return "MQObject";
   };
   /**
    * Returns the version of this class.
    * @return The version of this class.
    * @type int
    */
   MQObject.prototype.getObjectVersion = function(){
      return 0;
   };
   
   /**
    * Sets values in xml.
    * @param {String} strPropName the property to set
    * @param {String} strPropValue the value to set the property to
    * @type void
    * 
    */
   MQObject.prototype.setProperty = function (strPropName, strPropValue) {
      var strXPathExpression;
      if (strPropName!==null) strXPathExpression= "/" + this.getM_Xpath() + "/" + strPropName;
      else strXPathExpression= "/" + this.getM_Xpath();
      var ndNewProp = mqSetNodeText(this.getM_XmlDoc(),strXPathExpression,strPropValue);
      if ( ndNewProp === null) {
         var ndNewPropParent = this.getM_XmlDoc().createElement(strPropName);
         var ndRoot = this.getM_XmlDoc().documentElement.appendChild(ndNewPropParent);
         ndNewProp = mqSetNodeText(this.getM_XmlDoc(),strXPathExpression,strPropValue);
      }
      return ndNewProp;
   };
   /**
     * Gets values from xml.
     * @param {String} strPropName the property to get
     * @return The property
     * @type String
     * 
     */
   MQObject.prototype.getProperty = function (strPropName) {
      var strXPathExpression;
      if (strPropName!==null) strXPathExpression= "/" + this.getM_Xpath() + "/" + strPropName;
      else strXPathExpression= "/" + this.getM_Xpath();
      return mqGetXPathNodeText(this.getM_XmlDoc(),strXPathExpression);
   };
   /**
    * Create a copy of this object.
    * @return The new object which is a copy of this
    * @type MQObject
    */
   MQObject.prototype.copy = function () {
       var cp = new this.constructor;
       cp.loadXml(this.saveXml());
       return cp;
    };
   /**
    * Create a copy of this object where the outermost tag remains the same.
    * @return The new object which is a copy of this except the outermost tag.
    * @type MQObject
    * @private
    */
   MQObject.prototype.internalCopy = function (obj) {
      var strXml = "<" + obj.getM_Xpath();
      if(this.getObjectVersion() > 0){
         strXml = strXml + " Version=\"" + this.getObjectVersion() + "\"";
      }
      strXml = strXml + ">";
      var root = this.getM_XmlDoc().documentElement;
      var nodes = root.childNodes;
      var maxCount = nodes.length;
      for (var count=0;count<maxCount;count++){
         strXml = strXml + mqXmlToStr(nodes[count]);
      }
      strXml = strXml + "</" + obj.getM_Xpath() + ">"; 
      var cp = new this.constructor;
      cp.loadXml(strXml);
      return cp;
    };
// End class MQObject


//#############################################################################
// Begin Class MQPoint
// Inheirit from MQObject
MQPoint.prototype = new MQObject();
MQPoint.prototype.constructor = MQPoint;
//#############################################################################
/**
 * Constructs a new MQPoint object.
 *
 * @class Encapsulates X and Y coordinates.
 * @param {int/string} param1 OPTIONAL: Depending on the absence of param2. 
 * If param2 exists then param1 is initial x (int - default is 0) otherwise
 * param1 is xpath (string - default is "Point").
 * @param {int} param2 OPTIONAL: initial y (default is 0).
 * @extends MQObject
 */
function MQPoint(param1, param2) {
   MQObject.call(this);
   /**
    * Value to represent the x value
    * @type int
    */
   this.x = 0;
   /**
    * Value to represent the y value
    * @type int
    */
   this.y = 0;

   // Set default path
   this.setM_Xpath("Point");

   if (arguments.length == 1){
      this.setM_Xpath(param1);
   }
   else if (arguments.length == 2){
      this.x = parseInt(param1);
      this.y = parseInt(param2);
      if (isNaN(this.x) || isNaN(this.y))
         throw new Error("MQPoint constructor called with invalid parameter");
   }
   else if (arguments.length > 2){
      throw new Error("MQPoint constructor called with "
         + arguments.length
         + " arguments, but it expects 0, 1, or 2 arguments");
   }

}

   /**
    * Returns the text name of this class.
    * @return The text name of this class.
    * @type String
    */
   MQPoint.prototype.getClassName = function(){
      return "MQPoint";
   };
   /**
    * Returns the version of this class.
    * @return The version of this class.
    * @type int
    */
   MQPoint.prototype.getObjectVersion = function(){
      return 0;
   };
   /**
    * Assigns the xml that relates to this object.
    * @param {String} strXml the xml to be assigned.
    * @type void
    * 
    */
   MQPoint.prototype.loadXml = function (strXml) {
      if("undefined" !== typeof(mqutils)){
         this.setM_XmlDoc(mqCreateXMLDoc(strXml));       
         this.x = this.getProperty("X");
         this.y = this.getProperty("Y");  
      }
   };
   /**
    * Build an xml string that represents this object.
    * @return The xml string.
    * @type String
    * 
    */
   MQPoint.prototype.saveXml = function () {
      return "<" + this.getM_Xpath() + "><X>" + this.x + "</X><Y>" + this.y + "</Y></" + this.getM_Xpath() + ">";
   };
   /**
     * Sets X.
     * @param {int} x the value to set X to
     * @type void
     */
   MQPoint.prototype.setX = function(x){
      this.x = parseInt(x);
      if (isNaN(this.x))
         throw new Error("MQPoint.setX called with invalid parameter");
   };
   /**
     * Gets X.
     * @return The X value
     * @type int
     */
   MQPoint.prototype.getX = function(){
      return this.x;
   };
   /**
     * Sets Y.
     * @param {int} y the value to set Y to
     * @type void
     */
   MQPoint.prototype.setY = function(y){
      this.y = parseInt(y);
      if (isNaN(this.y))
         throw new Error("MQPoint.setY called with invalid parameter");
   };
   /**
     * Gets Y.
     * @return The Y value
     * @type int
     */
   MQPoint.prototype.getY = function(){
      return this.y;
   };   
   /**
     * Sets the horizontal and vertical coordinates to the values passed in.
     * @param {int} x the value to set X to
     * @param {int} y the value to set Y to
     * @type void
     */
   MQPoint.prototype.setXY = function(x, y){
      this.x = parseInt(x);
      this.y = parseInt(y);
      if (isNaN(this.x) || isNaN(this.y))
         throw new Error("MQPoint.setXY called with invalid parameter");
   };
   /**
   * Returns a true if both the X and Y values are set
   * to a value other than the static "INVALID" value.
   * @return True if both the X and Y values are not
   * equal to the static "INVALID".
   * @type Boolean
   */
   MQPoint.prototype.valid = function(){
      if("undefined" !== typeof(mqutils)){
         return ( Math.abs(this.x != MQCONSTANT.MQPOINT_INVALID) && 
         Math.abs(this.y != MQCONSTANT.MQPOINT_INVALID));
      }
      return false;
   };
   /**
   * Determines whether or not two points are equal. Two instances
   * of Point are equal if the values of their x and y member
   * fields, representing their position in the coordinate space,
   * are the same.
   * @param {MQPoint} pt an MQPoint object to be compared with this MQPoint
   * @return True if both the X and Y values are equal.
   * @type Boolean
   */
   MQPoint.prototype.equals = function(pt){
      if (pt){
         return (this.x === pt.x && this.y === pt.y);
      }
      return false;
   };

   /**
    * Returns a string representation of this <code>MQPoint</code>.
    * The format is <code>"x,y"</code>.
    *
    * @returns {string} a string representation of this <code>MQPoint</code>.
    */
   MQPoint.prototype.toString = function() {
      return this.x + "," + this.y;
   };
// End class MQPoint


//#############################################################################
// Begin Class MQLatLng
// Inheirit from MQObject
MQLatLng.prototype = new MQObject();
MQLatLng.prototype.constructor = MQLatLng;
//#############################################################################
/**
 * Constructs a new MQLatLng object.
 *
 * @class Contains a latitude/longitude pair.
 * @param {float/string} param1 OPTIONAL: Depending on the absence of param2.
 * If param2 exists then param1 is initial latitude (float - default is 0.0)
 * otherwise param1 is xpath (string - default is "LatLng"). 
 * @param {float} param2 OPTIONAL: initial longitude (default is 0.0).
 * @extends MQObject
 */
function MQLatLng (param1, param2) {
   MQObject.call(this);
   /**
    * Value to represent the latitude
    * @type float
    */
   this.lat = 0.0;
   /**
    * Value to represent the longitude
    * @type float
    */
   this.lng = 0.0;

   // Set default path
   this.setM_Xpath("LatLng");

   if (arguments.length == 1){
      this.setM_Xpath(param1);
   }
   else if (arguments.length == 2){
      this.lat = parseFloat(param1);
      this.lng = parseFloat(param2);
      if (isNaN(this.lat) || isNaN(this.lng))
         throw new Error("MQLatLng constructor called with invalid parameter");
   }
   else if (arguments.length > 2){
      throw new Error("MQLatLng constructor called with "
         + arguments.length
         + " arguments, but it expects 0, 1, or 2 arguments.");
   }

}
   /**
    * Returns the text name of this class.
    * @return The text name of this class.
    * @type String
    */
   MQLatLng.prototype.getClassName = function(){
      return "MQLatLng";
   };
   /**
    * Returns the version of this class.
    * @return The version of this class.
    * @type int
    */
   MQLatLng.prototype.getObjectVersion = function(){
      return 0;
   };
   /**
    * Assigns the xml that relates to this object.
    * @param {String} strXml the xml to be assigned.
    * @type void
    * 
    */
   MQLatLng.prototype.loadXml = function (strXml) {
      if("undefined" !== typeof(mqutils)){
         this.setM_XmlDoc(mqCreateXMLDoc(strXml));     
         this.lat = this.getProperty("Lat");
         this.lng = this.getProperty("Lng");
      }
   };
   /**
    * Build an xml string that represents this object.
    * @return The xml string.
    * @type String
    * 
    */
   MQLatLng.prototype.saveXml = function () {
      return "<" + this.getM_Xpath() + "><Lat>" + this.lat + "</Lat><Lng>" + this.lng + "</Lng></" + this.getM_Xpath() + ">";
   };
   /**
     * Sets the latitude value.
     * @param {float} fLatitude the value to set lat to
     * @type void
     */
   MQLatLng.prototype.setLatitude = function(fLatitude){
      this.lat = parseFloat(fLatitude);
      if (isNaN(this.lat))
         throw new Error("MQLatLng.setLatitude called with invalid parameter");
   };
   /**
     * Returns the latitude value.
     * @return the latitude value.
     * @type float
     */
   MQLatLng.prototype.getLatitude = function(){
      return this.lat;
   };
   /**
     * Sets the longitude value.
     * @param {float} fLongitude the value to set lng to
     * @type void
     */
   MQLatLng.prototype.setLongitude = function(fLongitude){
      this.lng = parseFloat(fLongitude);
      if (isNaN(this.lng))
         throw new Error("MQLatLng.setLongitude called with invalid parameter");
   };
   /**
     * Returns the longitude value.
     * @return the longitude value.
     * @type float
     */
   MQLatLng.prototype.getLongitude = function(){
      return this.lng;
   };   
   /**
     * Sets the latitude and longitude values.
     * @param {float} fLatitude the value to set lat to
     * @param {float} fLongitude the value to set lng to
     * @type void
     */
   MQLatLng.prototype.setLatLng = function(fLatitude, fLongitude){
      this.lat = parseFloat(fLatitude);
      this.lng = parseFloat(fLongitude);
      if (isNaN(this.lat) || isNaN(this.lng))
         throw new Error("MQLatLng.setLatLng called with invalid parameter");
   };
   /**
    * Calculates the distance between two lat/lng's in miles or meters. If LUnits not
    * provide then miles will be the default.
    * @param {MQLatLng} ll2   Second lat,lng position to calculate distance to.
    * @param {MQDistanceUnits} lUnits Units to calculate distance
    * @return Returns the distance in meters or miles.
    * @throws SomeException If the ll2 parameter is not the type MQLatLng
    * @throws SomeException If the lUnits parameter exists and is not the type MQDistanceUnits
    * @type double
    */
   MQLatLng.prototype.arcDistance = function( ll2, lUnits){
      if("undefined" !== typeof(mqutils)){
      // type checks
      if (ll2){
         if(ll2.getClassName()!=="MQLatLng"){
            alert("failure in arcDistance");
            throw "failure in arcDistance";
         }
      } else {
         alert("failure in arcDistance");
         throw "failure in arcDistance";
      }
      if(lUnits){
         mqIsClass("MQDistanceUnits", lUnits, false);
      } else {
         lUnits = new MQDistanceUnits(MQCONSTANT.MQDISTANCEUNITS_MILES);
      }
         
     // Check for same position
      if (this.getLatitude() == ll2.getLatitude() && this.getLongitude() == ll2.getLongitude()){
         return 0.0;
      }
      // Get the Lng difference.  Don't need to worry about
      //    crossing 180 since  cos(x) = cos(-x)
      var dLon = ll2.getLongitude() - this.getLongitude();
      var a = MQCONSTANT.MQLATLNG_RADIANS * (90.0 - this.getLatitude());
      var c = MQCONSTANT.MQLATLNG_RADIANS * (90.0 - ll2.getLatitude());
      var cosB = (Math.cos(a) * Math.cos(c)) + (Math.sin(a) * Math.sin(c) *
                     Math.cos(MQCONSTANT.MQLATLNG_RADIANS * (dLon)));
      var radius = (lUnits.getValue() === MQCONSTANT.MQDISTANCEUNITS_MILES) ? 3963.205 : 6378.160187;

      // Find angle subtended (with some bounds checking) in radians and
      //    multiply by earth radius to find the arc distance
      if (cosB < -1.0)
         return MQCONSTANT.PI * radius;
      else if (cosB >= 1.0)
         return 0;
      else
         return Math.acos(cosB) * radius;
      }
      return -1;
   };
   /**
   * Returns a true if both the latitude and longitude values are set
   * to a value other than the static "INVALID" value.
   * @return True if both the latitude and longitude values are not
   * equal to the static "INVALID".
   * @type Boolean
   */
   MQLatLng.prototype.valid = function(){
      if("undefined" !== typeof(mqutils)){
         return ( Math.abs(this.getLatitude()  - MQCONSTANT.MQLATLNG_INVALID) > MQCONSTANT.MQLATLNG_TOLERANCE && 
         Math.abs(this.getLongitude() - MQCONSTANT.MQLATLNG_INVALID) > MQCONSTANT.MQLATLNG_TOLERANCE );
      }
      return false;
   };
   /**
   * Determines whether or not two latlngs are equal. Two instances
   * of MQLatLng are equal if the values of their latitude and longitude member
   * fields, representing their position in the coordinate space,
   * are the same.
   * @param {MQLatLng} ll an MQLatLng object to be compared with this MQLatLng
   * @return True if both the latitude and longitude values are equal.
   * @type Boolean
   */
   MQLatLng.prototype.equals = function(ll){
      if (ll!==null){
         return (this.getLongitude() === ll.getLongitude() && this.getLatitude() === ll.getLatitude());
      }
      return false;
   };

   /**
    * Returns a string representation of this <code>MQLatLng</code>.
    * The format is <code>"latitude,longitude"</code>.
    *
    * @returns {string} a string representation of this <code>MQLatLng</code>.
    */
   MQLatLng.prototype.toString = function() {
      return this.lat + "," + this.lng;
   };
// End class MQLatLng


