/*the following line is used for checking source against javascript lint*/
/*global window, event, document, HTMLDocument, setTimeout, XMLSerializer, XPathResult */
// This must be the first script file (except for the optional debug library)
// Dependencies: none

// Use this function to generate namespaces 
// You should call this function to register any namespaces you may use.
// This ensures you do not clobber any namespaces that already exists 
// Allows the functions on a namespace to span multiple files.

function RegisterNamespaces() {
  for (var i=0;i<arguments.length;i++) {
    var splitNS = arguments[i].split(".");
    var root = window;
    for (var j=0;j<splitNS.length;j++) {
      var s = splitNS[j];
      if (!root[s]) {
        root[s] = function() {}; 
      }
      root = root[s];
    }
    if (!root._Private) {
      root._Private = function() {}; 
      //Next version of firefox does not allow Error to be overridden, so commenting out.  GTL bug 9307.
      //root.Error = function() {}; 
    }
  }
}

RegisterNamespaces("Msn.Browser","Msn.Debug.Performance");

/*
// Stub debug functions
if (!Msn.Debug.Enabled) {
  Msn.Debug.Enabled = false;
  Msn.Debug.Assert = Msn.Debug.Trace = function() {};
  Msn.Debug.Performance.Start  = function() {
    this.End = function(){};
    return this;
  };
}
*/

// Need more robust checks
Msn.Browser.IsMozilla = function() {
  return (typeof document.implementation != 'undefined') && (typeof document.implementation.createDocument != 'undefined') && (typeof HTMLDocument!='undefined');
};


// Mozilla implementation of CreatePopup
/*
Msn.Browser._Private.CreatePopup = function() {
  var obj = new Object();
  obj.document = document.createDocumentFragment();
  obj.document.body = obj.document.appendChild(document.createElement("div"));
  obj.document.close = obj.document.open = function() {};
  obj.document.write = function(v) {
    obj.document.body.innerHTML += v;
  };

  obj.show = function(x,y,width,height,offset) {
    function doHide(ev) {
      if (!obj.document.body.contains(ev.target)) {
        ev.stopPropagation();
        r.removeNode();
      }
      document.removeEventListener("mousedown",doHide,true);
    }
    
    function doClick(ev) {
      if (this.onclicktemp) {
        this.onclicktemp();
      }
      r.removeNode();
    }

    if (!offset) {offset = document.body;}
    var offsetLoc = Msn.Dom.GetLocation(offset);
    obj.document.body.style.cssText = "z-index:100;position:absolute;margin:0px;padding:0px;top:{0}px;left:{1}px;width:{2}px;height:{3}px;background:white".format(y+offsetLoc.top,x+offsetLoc.left,width,height);
    
    var r = document.body.appendChild(obj.document.body);
    document.addEventListener("mousedown",doHide,true);
    r.onclicktemp = obj.document.onclick;
    r.onclick = doClick;
    
  };

  return obj;
};
*/
/*
// Stub out filters
Msn.Browser._Private = function() {};
Msn.Browser._Private.MozillaFilterMethods = new Array("addAmbient","addCone","addPoint","apply","changeColor","changeStrength","clear","moveLight");
Msn.Browser._Private.MozillaFilterEventMethods  = new Array("play","stop");
Msn.Browser._Private.MozillaFilterSub = function() {
  function doblank() {}
  
  function doevent() {  // TODO - need to hook up event object and related properties
    if (this.onfilterchange) {
      this.onfilterchange();
    }
  }
  
  // Need to implement item, etc)
  // Use prototype to make more efficient

  var i, privFilter = Msn.Browser._Private;
  for (i=0;i<privFilter.MozillaFilterMethods.length;i++) {
    this[privFilter.MozillaFilterMethods[i]] = doblank;
  }
  for (i=0;i<privFilter.MozillaFilterEventMethods.length;i++) {
    this[privFilter.MozillaFilterEventMethods[i]] = doevent;
  }
  return this;
};
*/

Msn.Browser.AttachMozillaCompatibility = function (w) {
  // Mozilla->IE Compatibility Library

  function EstablishMode() {
    var el = w.document.getElementsByName("msn-moz-custom");
    if (el.length>0) {
      Msn.Browser.MozillaCompatMode = el[0].getAttribute("content").toLowerCase()=="enabled";
    }
    else {
      Msn.Browser.MozillaCompatMode = false;
    }
  }

  EstablishMode();
  function GenWindowEvent(e) {window.event = e;}  
  function Map(el,mozillaType, callback) {
    mozillaType = mozillaType.slice(2);
    if (mozillaType!="mouseenter" && mozillaType!="mouseleave") {
      el.addEventListener(mozillaType, GenWindowEvent, true); // Grab events first to establish window object
    }
    else { // Simulate events
      el.addEventListener("mouseover", GenWindowEvent, true); // Grab events first to establish window object
      el.addEventListener("mouseout", GenWindowEvent, true); // Grab events first to establish window object
      el.addEventListener("mouseover",CheckEnter,false);
      el.addEventListener("mouseout",CheckLeave,false);
    }
    el.addEventListener(mozillaType, callback, false);    // Hook the actual event    
  }
  
  function CheckEnter() {
    if (!this.contains(event.fromElement)) {
      event.initEvent("mouseenter",false,false);
      this.dispatchEvent(event);
    }
  }
  
  function CheckLeave() {
    if (!this.contains(event.toElement)) {
      event.initEvent("mouseleave",false,false);
      this.dispatchEvent(event);
    }
  }

  function RemoveMap(el,mozillaType,callback) {
    el.removeEventListener(mozillaType.slice(2), callback, false);
  }
  
  function GetNonTextNode(n) {
    try {
      while (n && n.nodeType!=1) { 
        n=n.parentNode;
      }
    }
    catch(ex) {
      n = null;
    }
    return n;
  }
  
  w.attachEvent = w.HTMLDocument.prototype.attachEvent = w.HTMLElement.prototype.attachEvent = function (type, callback) {Map(this,type,callback);};
  w.detachEvent = w.HTMLDocument.prototype.detachEvent = w.HTMLElement.prototype.detachEvent = function (type, callback) {RemoveMap(this,type,callback);};
  //w.createPopup = Msn.Browser._Private.CreatePopup;

  /*
  // TODO - implement this on nodes 
  w.Document.prototype.__defineGetter__("xml", function () { return (new XMLSerializer()).serializeToString(this);});
  w.Document.prototype.scripts = document.getElementsByTagName("script");
  // TODO - implement selection
  w.Document.prototype.selection = new Object();
  w.Document.prototype.selection.clear = function() {}; // Need to find Mozilla equivalent
  w.Document.prototype.selection.createRange = function() {return window.getSelection().getRangeAt(0);};
  */

  w.HTMLElement.prototype.__defineGetter__("parentElement",function() {return GetNonTextNode(this.parentNode);});
  /*w.HTMLElement.prototype.removeNode = function(b) {return this.parentNode.removeChild(this);};
  w.HTMLElement.prototype.contains = function (el) {  
    while (el && el != this) {
      el = el.parentElement;
    }
    return (el !== null);
  };*/


  /*
  function CurrentStyle(el) {
    // Extend this if additional CurrentStyle properties are required
    var PropertyList = new Array("Top","Left","Right","Bottom");
    var cs = document.defaultView.getComputedStyle(el,null);
    for (var i=0;i<PropertyList.length;i++) {
      var p = PropertyList[i];
      this["border" + p + "Width"] = cs.getPropertyValue("border-" + p + "-width");
      this["margin" + p] = cs.getPropertyValue("margin-" + p);
      this["padding" + p] = cs.getPropertyValue("padding-" + p);
    }
    return this;
  }
  */

  /*
  w.HTMLElement.prototype.filters = Msn.Browser._Private.MozillaFilterSub(); // stub out
  w.HTMLElement.prototype.__defineSetter__("onfilterchange",function(v) {this.filters.onfilterchange = v;});
  w.HTMLElement.prototype.__defineGetter__("onfilterchange",function() {return this.filters.onfilterchange;});
  */
  w.HTMLElement.prototype.__defineGetter__("innerText", function(){return this.textContent;});
  w.HTMLElement.prototype.__defineSetter__("innerText", function(v){var n = document.createTextNode(v);this.innerHTML = "";this.appendChild(n);});
  /*
  w.HTMLElement.prototype.__defineGetter__("currentStyle", function(){return new CurrentStyle(this);});
  w.HTMLElement.prototype.setCapture = w.HTMLElement.prototype.releaseCapture = function() {}; // Need to see if we can do something smart here
  w.HTMLElement.prototype.insertAdjacentElement = function (sWhere,oElement) {
    switch (sWhere.toLowerCase()) {
      case "beforebegin":
        this.parentNode.insertBefore(oElement,this);
        break;
      case "beforeend":
        this.appendChild(oElement);
        break;
      case "afterbegin":
        this.insertBefore(oElement,this.firstChild);
        break;        
      case "afterend":
        if (this.nextSibling) { 
          this.parentNode.insertBefore(oElement,this.nextSibling);
        }
        else {
          this.parentNode.appendChild(oElement);
        }
        break;
      default:
        throw "Invalid Argument"; // TODO - see if I can get the error number set to 201 (match IE)
    }
  };
  */

  /*
  function parseFilter(v) {
    // Cheap parse (only look for key word) - allows opacity support
    v = v.replace(" ",""); 
    var matchString = "DXImageTransform.Microsoft.Alpha(opacity=";
    var opacityIndex = v.indexOf(matchString);
    if (opacityIndex >0) {
      var close = v.indexOf(")",opacityIndex);
      if (close==-1) {
        close = v.indexOf(",",opacityIndex);
      }
      return ("." + v.substring(opacityIndex+matchString.length,close));
    }
    else {
      return "";
    }
  }
  */

  /*
  // IE CSS Properties
  w.CSSStyleDeclaration.prototype.__defineGetter__("pixelLeft", function() {return parseInt(this.left) || 0;});
  w.CSSStyleDeclaration.prototype.__defineSetter__("pixelLeft", function (v) {this.left = v + "px";});
  w.CSSStyleDeclaration.prototype.__defineGetter__("pixelHeight", function() {return parseInt(this.height) || 0;});
  w.CSSStyleDeclaration.prototype.__defineSetter__("pixelHeight", function (v) {this.height = v + "px";});
  w.CSSStyleDeclaration.prototype.__defineGetter__("pixelTop", function() {return parseInt(this.top) || 0;});
  w.CSSStyleDeclaration.prototype.__defineSetter__("pixelTop", function (v) {this.top = v + "px";});
  w.CSSStyleDeclaration.prototype.__defineGetter__("pixelWidth", function() {return parseInt(this.width) || 0;});
  w.CSSStyleDeclaration.prototype.__defineSetter__("pixelWidth", function (v) {this.width = v + "px";});
  w.CSSStyleDeclaration.prototype.__defineSetter__("filter", function(v) {this.opacity = parseFilter(v);});
  */

  /*
  w.CSSStyleSheet.prototype.__defineGetter__("cssText",function() {
      var s = "";
      for (var j=0;j<this.cssRules.length;j++) {
        s += this.cssRules[j].cssText;
      }
      return s;
    }
  );
  */

  /*
  function selectSingleNode(d,v,c) {
    v+="[1]";
    var nl = selectNodes(d,v,c);
    if (nl.length > 0) {
      return nl[0];
    }
    else {
      return null;
    }
  }

  function selectNodes(d,v,c) {
    var oResult = d.evaluate(v, c, 
              d.createNSResolver(d.documentElement),
              XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    var nodeList = new Array();
    for(var i=0;i<oResult.snapshotLength;i++) {
      nodeList.push(oResult.snapshotItem(i));
    }
    return nodeList;
  }

  w.XMLDocument.prototype.selectNodes = function(v) {
    return selectNodes(this,v,this);
  };
  
  w.Element.prototype.selectNodes = function(v) {
    var scope = this.ownerDocument;
    if(scope.selectNodes) {
      return selectNodes(scope,v, this);
    }
    else {
      return null;
    }
  };
  
  w.Element.prototype.__defineGetter__ ("text",function() {return this.textContent;});


  w.XMLDocument.prototype.selectSingleNode = function(v) {
    return selectSingleNode(this,v,null);
  };
  
  w.Element.prototype.selectSingleNode = function(v) {
    var scope = this.ownerDocument;
    if (scope.selectSingleNode) {
      return selectSingleNode(scope,v, this);
    }
    else {
      return null;  // Only supported on XML nodes
    }
  };
  */

  // IE Event Object
  w.Event.prototype.__defineGetter__("srcElement", function () {var n = GetNonTextNode(this.target);return n;});
  w.Event.prototype.__defineSetter__("cancelBubble", function (v) {if (v) {this.stopPropagation();}});
  function QuickLoc (el) {
    var c = {x : 0, y : 0};
    while (el) {
      c.x += el.offsetLeft;
      c.y += el.offsetTop;
      el = el.offsetParent;
    }
    return c;
  }
  w.Event.prototype.__defineGetter__("offsetX", function () {return window.pageXOffset + this.clientX - QuickLoc(this.srcElement).x;});
  w.Event.prototype.__defineGetter__("offsetY", function () {return window.pageYOffset + this.clientY - QuickLoc(this.srcElement).y;}); 
  w.Event.prototype.__defineSetter__("returnValue", function (v) {if (!v) {this.preventDefault();} this.cancelDefault  = v;return v;});
  w.Event.prototype.__defineGetter__("returnValue", function() {return this.cancelDefault;});
  w.Event.prototype.__defineGetter__("fromElement", function () {
    var n;
    if (this.type == "mouseover") {
      n = this.relatedTarget;
    }
    else if (this.type == "mouseout") {
      n = this.target;
    }
    return GetNonTextNode(n);
  });
  w.Event.prototype.__defineGetter__("toElement", function () {
    var n;
    if (this.type == "mouseout") {
      n = this.relatedTarget;
    }
    else if (this.type == "mouseover") {
      n = this.target;
    }
    return GetNonTextNode(n);
  });
  w.Event.prototype.__defineGetter__("button", function() {return (this.which == 1) ? 1 : (this.which == 2) ? 4 : 2;});
};

// TODO - Needs thorough testing (especially timing related tests)
/*
Msn.Browser._Private.MozillaModal = function(sURL,oArguments,sFeatures,fnCallback) {
  if (!sFeatures) { sFeatures = ""; }
  sFeatures = sFeatures.removeSpaces();
  var featureList = sFeatures.split(",");
  sFeatures = "";
  var bCenter = false, bNoCenter = false;
  var w=0,h=0,s='';
  for (var i=0;i<featureList.length;i++) {
    var feature = featureList[i].split(":");
    var k = feature[0].toLowerCase();
    var v = feature[1];
    switch (k) {
      case "dialogheight": s+="height=" + v; w=v;break;
      case "dialogwidth": s+="width=" + v; h=v;break;
      case "dialogtop": s+="top=" + v; bNoCenter = true; break;
      case "dialogleft": s+="left=" + v; bNoCenter = true; break;
      case "resizable": s+="resizable=" + v; break;
      case "status": s+="status=" + v; break;
      case "center": bCenter = true; break;
    }
    if (k!="center") {s+=",";}
  }
  if (bCenter && (!bNoCenter) && Msn.Conversion) {
    
    if (w) {w = Msn.Conversion.CoerceInt(w);} else {w=300;}
    if (h) {h = Msn.Conversion.CoerceInt(h);} else {h=300;}
    if (w !== "" || h !== "") {
      s+="screenX=" + ((screen.availHeight-h)/2) + ",";
      s+="screenY=" + ((screen.availWidth-w)/2);
    }
  }
  var mWin = window.open(sURL,"",s);
  Msn.Browser._Private.MozillaCompat(mWin);
  mWin.dialogArguments = oArguments;

  var rValue = "";
  grabReturn = function() {
    if (mWin && !mWin.closed) {
      rValue = mWin.returnValue;
      setTimeout(CheckClose,0); // Test timer
    }
  };
  
  resetModal = function(ev) {
    if (mWin && !mWin.closed) {
      ev.stopPropagation();
      mWin.focus();
    }
  };
  
  CheckClose = function() {
    if (mWin.closed) {        
      if (fnCallback) {
        fnCallback(rValue);
      }
      window.removeEventListener("focus",resetModal,true);
    }
  };
  
  hookEvents = function() {
    mWin.onunload = grabReturn; //("onunload",grabReturn,true);
    window.addEventListener("focus",resetModal,true);
  };
  setTimeout(hookEvents,0); // Need to test timing of this (e.g., slow connection)
};
*/

if (Msn.Browser.IsMozilla()) {Msn.Browser.AttachMozillaCompatibility(self);}

