// ============================================================================
// Map object to store all map related properties
// ============================================================================
function SWMap(ID, ServerID)
{
  this.id = "SWMap";
  this.ServerID = ServerID;
  this.GliderLayer = null;                       // Glider layer
  this.MapRequest = null;                        // XMLHttpRequest object
  this.ParentDiv = document.getElementById(ID);  // Main div layer that we must create our layers inside
  this.MapDiv = null;                            // Map div layer
  this.BusyDiv = null;                           // Busy icon div layer
  this.GliderDiv = null;                         // Glider div layer
  this.InitialGliderData = false;                // A start up flag to figure out when to get the first lot of glider data

  // Map variables
  this.ExtentEast  = 0;
  this.ExtentWest  = 0;
  this.ExtentNorth = 0;
  this.ExtentSouth = 0;
  this.ImageURL    = "";
  this.NewCenterX  = 0;
  this.NewCenterY  = 0;
  this.MapButtonDown = "pan";
  this.ImageURL = "";
  this.LegendLayersInitialized = false;
  this.StartX  = 0;
  this.StartY  = 0;
  this.MapLeft = 0;
  this.MapTop  = 0;
  this.IsDragging = false;

// Tuples of layer names, legend img URL and layer status (ON/OFF) separated with an asterisk
  this.LayerTuples = new Array();

  this.Init();
}

// ============================================================================
SWMap.prototype.Init = function ()
{
  // div element containing the map
  this.MapDiv = document.createElement("div");
  this.MapDiv.id = "MapDiv";
  this.MapDiv.style.position = "absolute";
  this.MapDiv.style.height = this.ParentDiv.style.height;
  this.MapDiv.style.width = this.ParentDiv.style.width;
  this.MapDiv.style.left = "0px";
  this.MapDiv.style.top = "0px";
  this.MapDiv.style.visibility = "visible";
  this.MapDiv.zIndex = 1;
  this.ParentDiv.appendChild(this.MapDiv);

  // This seems to be necessary on IE?
  this.MapDiv.onmousedown = this.OnMouseDown.bindEventListener(this);
  this.MapDiv.onmouseup = this.OnMouseUp.bindEventListener(this);
  this.MapDiv.onmousemove = this.OnMouseMove.bindEventListener(this);

  // div element containing the busy icon
  this.BusyDiv = document.createElement("div");
  this.BusyDiv.style.position = "relative";
  this.BusyDiv.style.left = ((this.ParentDiv.clientWidth / 2) - 50)+"px";
  this.BusyDiv.style.top = ((this.ParentDiv.clientHeight / 2) - 50)+"px";
  this.BusyDiv.zIndex = 3;
  this.BusyDiv.style.visibility = "visible";
  this.BusyDiv.id = "BusyDiv";
  this.BusyDiv.innerHTML = "<img src='images/busy.gif'>";
  this.ParentDiv.appendChild(this.BusyDiv);

  // div element containing the gliders
  this.GliderDiv = document.createElement("div");
  this.GliderDiv.id = "GliderDiv";
  this.GliderDiv.style.position = "absolute";
  this.GliderDiv.style.height = this.ParentDiv.style.height;
  this.GliderDiv.style.width = this.ParentDiv.style.width;
  this.GliderDiv.style.left = "0px";
  this.GliderDiv.style.top = "0px";
  this.GliderDiv.style.visibility = "visible";
  this.GliderDiv.zIndex = 2;
  this.GliderDiv.onmousedown = this.OnMouseDown.bindEventListener(this);
  this.GliderDiv.onmouseup = this.OnMouseUp.bindEventListener(this);
  this.GliderDiv.onmousemove = this.OnMouseMove.bindEventListener(this);
  this.ParentDiv.appendChild(this.GliderDiv);

  // Create glider layer
  this.GliderLayer = new GliderLayerObj(this.GliderDiv.id, this.ServerID);

  // Generate a new map
  this.BuildMap(this.BuildMapURL("glider-extents"));

  // Start timer to get glider updates every 10 seconds
  setInterval(this.GliderLayer.RefreshData.bind(this.GliderLayer), 10000);
}

// ============================================================================
SWMap.prototype.BuildMapURL = function (UpdateType, ZoomValue)
{
  var LayerStr = "";
  if (this.LayerTuples.length != 0)
  {
    for (var i = 0; i < this.LayerTuples.length; i++)
    {
      LayerStr += this.LayerTuples[i] + "%";
    }
    LayerStr = LayerStr.substring(0, LayerStr.length - 1);
  }

  if (!ZoomValue)
  {
    ZoomValue = 1;
  }

//  var URL = "gen_map.php?MapHeight="+TestVar+"&MapWidth=800 \
  var URL = "gen_map.php?MapHeight="+this.ParentDiv.clientHeight+"&MapWidth="+this.ParentDiv.clientWidth+" \
        &MapExtentEast="+this.ExtentEast+"&MapExtentWest="+this.ExtentWest+" \
        &MapExtentNorth="+this.ExtentNorth+"&MapExtentSouth="+this.ExtentSouth+" \
        &MapCenterX="+this.NewCenterX+"&MapCenterY="+this.NewCenterY+" \
        &MapZoom="+ZoomValue+"&LayerString="+LayerStr+"&UpdateType="+UpdateType+"&ServerID="+this.ServerID;
 
//  alert("Map URL:" + URL + "\n");
  return URL;
}

// ============================================================================
SWMap.prototype.BuildMap = function (URL)
{
  // branch for native XMLHttpRequest object
  if (window.XMLHttpRequest)
  {
    this.MapRequest = new XMLHttpRequest();
    this.MapRequest.onreadystatechange = this.ProcessMapReqChange.bindEventListener(this);
    this.MapRequest.open("GET", URL, true);
    this.MapRequest.send(null);
  }
  else  // branch for IE/Windows ActiveX version
  {
    if (window.ActiveXObject)
    {
      this.MapRequest = new ActiveXObject("Microsoft.XMLHTTP");
      if (this.MapRequest)
      {
        this.MapRequest.onreadystatechange = this.ProcessMapReqChange.bindEventListener(this);
        this.MapRequest.open("GET", URL, true);
        this.MapRequest.send(null);
      }
    }
  }
}

// ============================================================================
SWMap.prototype.ProcessMapReqChange = function ()
{
  // readyState 4 = complete
  if (this.MapRequest.readyState == 4)
  {
    // HTTP result status 200 = OK
    if (this.MapRequest.status == 200)
    {
      var Response = this.MapRequest.responseXML.documentElement;
      this.ImageURL = Response.getElementsByTagName('map_url')[0].firstChild.data;
      var TempLayerString = Response.getElementsByTagName('legend_string')[0].firstChild.data;
      this.LayerTuples = TempLayerString.split('%');
      this.ExtentEast = parseFloat(Response.getElementsByTagName('map_extent_east')[0].firstChild.data);
      this.ExtentWest = parseFloat(Response.getElementsByTagName('map_extent_west')[0].firstChild.data);
      this.ExtentNorth = parseFloat(Response.getElementsByTagName('map_extent_north')[0].firstChild.data);
      this.ExtentSouth = parseFloat(Response.getElementsByTagName('map_extent_south')[0].firstChild.data);

      // Add layers to menubarframe the first time a map is created
      if (! this.LegendLayersInitialized)
      {
        var TempArr = new Array();
        for (var i = 0; i < this.LayerTuples.length; i++)
        {
          TempArr = (this.LayerTuples[i]).split('*');
          parent.AddLayerItem(TempArr[0], TempArr[1], TempArr[2]);
        }

        this.LegendLayersInitialized = true;
      }

      // Display new map and hide the busy icon
      this.MapDiv.style.left = "0px";
      this.MapDiv.style.top = "0px";
      this.MapDiv.innerHTML =  "<img src='"+this.ImageURL+"'>";
      this.BusyDiv.style.visibility = "hidden";

      // Reposition glider layer and update it's extents
      this.GliderDiv.style.left = "0px";
      this.GliderDiv.style.top = "0px";
      this.GliderLayer.UpdateExtents(this.ExtentEast, this.ExtentWest, this.ExtentNorth, this.ExtentSouth);

      // Get new data the first time
      if (!this.InitialGliderData)
      {
        this.InitialGliderData = true;
        this.GliderLayer.RefreshData();
      }
    }
    else
    {
      alert("There was a problem retrieving the map XML data:\n" + this.MapRequest.statusText);
    }
  }
}

// ============================================================================

SWMap.prototype.OnMouseDown = function (event)
{
//    alert("Drag\n");
  // Store current map location
  this.MapLeft = parseInt(this.MapDiv.style.left);
  this.MapTop = parseInt(this.MapDiv.style.top);

  // Store mouse down position
  this.StartX = event.clientX;
  this.StartY = event.clientY;

  if (this.MapButtonDown == "pan")
  {
    this.IsDragging = true;
  }

  return false;
}


// ============================================================================
SWMap.prototype.OnMouseUp = function (event)
{
  // Cancel dragging event if it was just a mouse click and there was no movement
  if (this.IsDragging && (event.clientX - this.StartX == 0) && (event.clientY - this.StartY == 0))
  {
    this.IsDragging = false;
  }

  // Don't update if there was no actual dragging
  if (this.IsDragging)
  {
    // Get new map center in pixels
    this.NewCenterX = parseInt((this.ParentDiv.clientWidth / 2) - parseInt(this.MapDiv.style.left));
    this.NewCenterY = parseInt((this.ParentDiv.clientHeight / 2) - parseInt(this.MapDiv.style.top));

    // Show busy icon
    this.BusyDiv.style.visibility = "visible";

    // Build a new map
    this.BuildMap(this.BuildMapURL("pan-zoom",1));
    this.IsDragging = false;
  }

  if (this.MapButtonDown == "zoom-in")
  {
    this.NewCenterX = event.clientX - SwGetElementLeft(this.MapDiv);
    this.NewCenterY = event.clientY - SwGetElementTop(this.MapDiv);;

    // Show busy icon
    this.BusyDiv.style.visibility = "visible";

    this.BuildMap(this.BuildMapURL("pan-zoom",2));
  }
  if (this.MapButtonDown == "zoom-out")
  {
    this.NewCenterX = event.clientX - SwGetElementLeft(this.MapDiv);
    this.NewCenterY = event.clientY - SwGetElementTop(this.MapDiv);;

    // Show busy icon
    this.BusyDiv.style.visibility = "visible";

    this.BuildMap(this.BuildMapURL("pan-zoom",-2));
  }

  return false;
}

// ============================================================================
SWMap.prototype.OnMouseMove = function (event)
{

  if (this.IsDragging)
  {
    this.MapDiv.style.left = this.MapLeft + (event.clientX - this.StartX) + "px";
    this.MapDiv.style.top = this.MapTop + (event.clientY - this.StartY) + "px";
    this.GliderDiv.style.left = this.MapDiv.style.left;
    this.GliderDiv.style.top = this.MapDiv.style.top;
  }

  return false;
}

// ============================================================================
// This function gets fired from the menu bar frame when a navigation
// button changes state
// ============================================================================
SWMap.prototype.NavigateButtonChanged = function (ButtonID)
{
  this.MapButtonDown = ButtonID;
}

// ============================================================================
// This function gets fired from menubarframe
// ============================================================================
SWMap.prototype.LayerUpdate = function (LayerStr)
{
  // Rewrite the legend tuples and update the layer status for the matching layer
  var MapTempArr = new Array();
  var IncomingLayerTuples = new Array();
  var IncomingTempArr = new Array();
  IncomingLayerTuples = LayerStr.split('%');

  for (var i = 0; i < this.LayerTuples.length; i++)
  {
    MapTempArr = this.LayerTuples[i].split('*');

    for (var j = 0; j < IncomingLayerTuples.length; j++)
    {
      IncomingTempArr = IncomingLayerTuples[j].split('*');

      if (MapTempArr[0] == IncomingTempArr[0])
      {
        MapTempArr[2] = IncomingTempArr[1];
      }
      this.LayerTuples[i] = MapTempArr[0]+"*"+MapTempArr[1]+"*"+MapTempArr[2];
    }
  }

  // We need to recenter the map zoom point otherwise we'll get a pan operation
  // We still have to pass the current map extents and a zoom factor of 1 so that
  // we don't snap back to the default map extents set in the *.map file
  this.NewCenterX = parseInt(this.ParentDiv.clientWidth / 2);
  this.NewCenterY = parseInt(this.ParentDiv.clientHeight / 2);

  // Show busy icon
  this.BusyDiv.style.visibility = "visible";

  // Build a new map
  this.BuildMap(this.BuildMapURL("layer"));
}

// ============================================================================
// This function gets fired from menubarframe
// ============================================================================
SWMap.prototype.ZoomGliderExtents = function ()
{
  // Show busy icon
  this.BusyDiv.style.visibility = "visible";

  this.BuildMap(this.BuildMapURL("glider-extents"));
}


// ============================================================================

function SwGetElementTop(eElement)
{
   if (!eElement && this)                    // if argument is invalid
   {                                         // (not specified, is null or is 0)
      eElement = this;                       // and function is a method
   }                                         // identify the element as the method owner

   var DL_bIE = document.all ? true : false; // initialize var to identify IE

   var nTopPos = eElement.offsetTop;         // initialize var to store calculations
   var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement != null)
   {                                         // move up through element hierarchy
      if(DL_bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent a table cell, then...
            nTopPos += eParElement.clientTop; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame != null)         // if frame has ANY value, then...
               {
                  nTopPos += 1;              // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nTopPos += nParBorder;        // append the border width to counter
            }
         }
         // sm 20051010
         if(eParElement.tagName == "DIV")
         {
           var bord = parseInt(eParElement.style.border);
           if ( bord > 0 ) { nTopPos += bord; }
         }
      }
      nTopPos += eParElement.offsetTop;      // append top offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   return nTopPos;                           // return the number calculated
}

// ============================================================================

function SwGetElementLeft(eElement)
{
   if (!eElement && this)                    // if argument is invalid
   {                                         // (not specified, is null or is 0)
      eElement = this;                       // and function is a method
   }                                         // identify the element as the method owner

   var DL_bIE = document.all ? true : false; // initialize var to identify IE

   var nLeftPos = eElement.offsetLeft;       // initialize var to store calculations
   var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement != null)
   {                                         // move up through element hierarchy
      if(DL_bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent is not a table or the body, then...
            nLeftPos += eParElement.clientLeft; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame != null)         // if frame has ANY value, then...
               {
                  nLeftPos += 1;             // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nLeftPos += nParBorder;       // append the border width to counter
            }
         }
         // sm 20051010
         if(eParElement.tagName == "DIV")
         {
           var bord = parseInt(eParElement.style.border);
           if ( bord > 0 ) { nLeftPos += bord; }
         }
      }
      nLeftPos += eParElement.offsetLeft;    // append left offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   return nLeftPos;                          // return the number calculated
}

// ============================================================================

