/* ========================================================================= */
/* = Lifemapper map wrapper                                                = */
/* = @author: CJ Grady                                                     = */
/* = @email: cjgrady@ku.edu                                                = */
/* = @date: January 28, 2009                                               = */
/* =                                                                       = */
/* = @summary: Wrapper for OpenLayers so that there are no OL specific     = */
/* =    function calls, this will make it easier to switch to Google Maps  = */
/* ========================================================================= */

function importJS()
   /*
   @summary: Imports an external JavaScript library for use in this script
   */
{
   var jsfiles=new Array("/javascript/OpenLayers/OpenLayers.js");
   
   var agent=navigator.userAgent;
   var docWrite=(agent.match("MSIE")||agent.match("Safari"));
   if(docWrite)
   {
      var allScriptTags=new Array(jsfiles.length);
   }

   var host = "http://lifemapper.org/";

   for(var i=0,len=jsfiles.length;i<len;i++)
   {
      if(docWrite)
      {
         allScriptTags[i]="<script src='"+host+jsfiles[i]+"'></script>";
      }
      else
      {
         var s=document.createElement("script");
         s.src=host+jsfiles[i];
         var h=document.getElementsByTagName("head"
               ).length?document.getElementsByTagName("head")[0]:document.body;
         h.appendChild(s);
      }
   }
   if(docWrite)
   {
      document.write(allScriptTags.join(""));
   }
}

importJS();
/* ------------------------------------------------------------------------- */

function _LM_Projection(id, prjUrl, prjScnTitle, prjTxt, prjKmlUrl, modUrl, 
                                                                        modTxt)
   /*
   @summary: Creates a projection "object"
   @param id: The projection id number
   @param prjUrl: The projection url
   @param prjScnTitle: The projection scenario title
   @param prjTxt: The text to use for the projection link
   @param prjKmlUrl: The url for the projection kml interface
   @param modUrl: The url for the model
   @param modTxt: The text for the model link
   @return: The projection object created
   @note: This should not be called directly, instead create a LmMap and use
             the addProjection function
   */
{
   this.id = id;
   this.projectionUrl = prjUrl;
   this.projectionScenarioTitle = prjScnTitle;
   this.projectionText = prjTxt;
   this.modelUrl = modUrl;
   this.modelText = modTxt;
   this.projectionKmlUrl = prjKmlUrl;
   this.projectionLayer = null;
   return this;
}

/* ------------------------------------------------------------------------- */
function _LM_OccurrenceSet(id, count, color, url, kmlUrl)
   /*
   @summary: Creates an occurrence set "object"
   @param id: The occurrence set id number
   @param count: The number of occurrences for the occurrence set
   @param color: The color to use when creating the occurrence set image
   @param url: The occurrence set url
   @param kmlUrl: The url for the occurrence set kml interface
   @return: The occurrence set object created
   @note: This should not be called directly, instead create a LmMap and use
             the addPointLayer function
   */
{
   this.id = id;
   this.count = count;
   this.color = color;
   this.url = url;
   this.kmlUrl = kmlUrl;
   this.pointLayer = null;
   return this;
}

/* ------------------------------------------------------------------------- */
function LmMap(species)
   /*
   @summary: Creates a LmMap "object"
   @param species: The species name to associate with the LmMap
   @return: The LmMap object created
   */
{
   this.species = species;
   this.lat = 0;
   this.lon = 0;
   this.map = null;
   this.occurrences = new Array();
   this.projections = new Array();
   this.addPointLayer = LM_addPointLayer;
   this.addProjection = LM_addProjection;
   this.init = LM_init;
   this.registerBackgroundEvents = LM_registerBackgroundEvents;
   this.registerPointEvents = LM_registerPointEvents;
   this.registerProjectionEvents = LM_registerProjectionEvents;
   this.selectOneProjection = LM_selectOneProjection;
   this.displayPointLayer = LM_displayPointLayer;
   this.getProjectionIds = 
      function()
      {
         var ret = "";
         for (var i = 0; i < this.projections.length; i++)
         {
            ret += this.projections[i].id + ", ";
         }
      };
   this.zoom = 1;
   return this;
}

/* ------------------------------------------------------------------------- */
function LM_addProjection(id, prjUrl, prjScnTitle, prjTxt, prjKmlUrl, 
                                                                modUrl, modTxt)
   /*
   @summary: Adds a projection to the projections array in a LmMap object
   @param id: The projection id
   @param prjUrl: The projection url
   @param prjScnTitle: The projection scenario title
   @param prjTxt: The projection link text
   @param prjKmlUrl: The url for the projection kml link
   @param modUrl: The model url
   @param modTxt: The model link text
   */
{
   this.projections[this.projections.length] = 
         new _LM_Projection(id, prjUrl, prjScnTitle, prjTxt, prjKmlUrl, 
                                                               modUrl, modTxt);
}

/* ------------------------------------------------------------------------- */
function LM_addPointLayer(id, count, color, url, kmlUrl)
   /*
   @summary: Adds a point layer to the occurrences array in a LmMap object
   @param id: The occurrence set id
   @param count: The number of points for the occurrence set
   @param color: The color to use when generating the occurrence set image
   @param url: The Lifemapper occurrences service url
   @param kmlUrl: The Lifemapper occurrences service url (kml interface)
   */
{
   this.occurrences[this.occurrences.length] = 
         new _LM_OccurrenceSet(id, count, color, url, kmlUrl);
}

/* ------------------------------------------------------------------------- */
function LM_init(mapserverRoot)
   /*
   @summary: Initializes a LmMap object after all of the point sets and 
                projections have been added
   @param mapserverRoot: The guid root for mapserver
   */
{
   var options = {
                    projection: "EPSG:4326",
                    units: 'm',
                    maxZoomLevel: 8,
                    maxExtent: new OpenLayers.Bounds(-180, -90, 180, 90),
                    maxResolution: 'auto',
                    ratio: 1,
                    numZoomLevels: 5,
                    singleTile: true,
                    'controls':[]
                 };

   this.map = new OpenLayers.Map('map', options);
   
   var nc = new OpenLayers.Control.Navigation();
   nc.activate = function ()
                 {
                    this.zoomBox.activate();
                    this.dragPan.activate();
                    return OpenLayers.Control.prototype.activate.apply(this, arguments);
                 }
   this.map.addControl(nc);
   this.map.addControl(new OpenLayers.Control.PanZoom());
               
   var urlBase = mapserverRoot + "/ogc?";
   var ol_wms = new OpenLayers.Layer.WMS("NASA Blue Marble", 
                                         urlBase,
                                         {
                                            layers: 'bmnglowres',
                                            map: 'nasalocal.map',
                                            service: 'WMS',
                                            version: '1.0.0',
                                            format: 'image/gif'
                                         },
                                         options);

   this.registerBackgroundEvents(ol_wms);

   var projUrlRoot = mapserverRoot + "/ogc?sdlsvc=MAL";
   for (var x = 0; x < this.projections.length; x++)
   {
      try
      {
         this.projections[x].projectionLayer = new OpenLayers.Layer.WMS(
                     this.species + " projection",
                     projUrlRoot,
                     {
                        layers: "mal",
                        sdllyr: this.projections[x].id,
                        service: "WMS",
                        version: "1.0.0",
                        transparent: "true",
                        format: "image/gif"
                     },
                     {
                        opacity: 1.0,
                        maxResolution: 'auto',
                        isBaseLayer: false,
                        ratio: 1,
                        singleTile: true
                     });
         this.registerProjectionEvents(this.projections[x].projectionLayer);
         var prjLyrs = document.getElementById("projLayers");
         
         var checked = "";
         if (x == 0)
         {
            checked = "checked";
         }
         
         var temp = "<span class='prjLyrItem'>" +
                              "<input type='radio' name='projs' " +
                              "value='" + this.projections[x].id + "' " +
                              "onclick='selectOneProjection(\"" + 
                              this.projections[x].id + "\");' " + checked + 
                              " /> <a class='spProjLink'" + " href='" + 
                              this.projections[x].projectionUrl +
                              "' " + "title='" + 
                              this.projections[x].projectionScenarioTitle + 
                              "'>" + this.projections[x].projectionText +
                              "</a> | <a class='spProjLink' " + 
                              "href='" + this.projections[x].modelUrl + "'>" +
                              this.projections[x].modelText + "</a> | " + 
                              "<a class='spProjLink' href='" + 
                              this.projections[x].projectionKmlUrl + 
                              "'>Google Earth</a>" +
                              "</span>";
         prjLyrs.innerHTML += temp;
      }
      catch(e)
      {
    	 alert("Error: " + e);
         document.getElementById('map').innerHTML = "An error occurred when trying to get the projection overlay" + e;
      }
   }
   
   var occUrlRoot = mapserverRoot + "/ogc?sdlsvc=pbj";
   for (var x = 0; x < this.occurrences.length; x++)
   {
      if (this.occurrences[x].count > 0)
      {
         try
         {
            this.occurrences[x].pointLayer = new OpenLayers.Layer.WMS(
                                    this.species + " points",
                                    occUrlRoot,
                                    {
                                       layers: "pbj",
                                       sdllyr: this.occurrences[x].id,
                                       service: "WMS",
                                       version: "1.0.0",
                                       transparent: "true",
                                       format: "image/gif",
                                       color: this.occurrences[x].color
                                    },
                                    {
                                       opacity: 1.0,
                                       maxResolution: 'auto',
                                       isBaseLayer: false,
                                       ratio: 1,
                                       singleTile: true
                                    });
            this.registerPointEvents(this.occurrences[x].pointLayer);
            
            var pointLyrs = document.getElementById("pointLayers");
            pointLyrs.setAttribute("align", "left");
            
            var giSearch = "http://images.google.com/images?hl=en&q=" +
                           this.species + "&btnG=Search+Images&gbv=2";
                                     
            var tbl = "<table class='pointsCheckTable'><tr>" + 
                      "<td class='pntLyrItem'>" +
                      "<input type='checkbox' " + 
                      "onclick='displayPointLayer(\"" + 
                      this.occurrences[x].id + "\", this.checked);' " +
                      "checked />&nbsp;" +
                      "<img src='/images/pointMarkerBack.png' " +
                      "style='background-color: #" + 
                      this.occurrences[x].color + ";' />&nbsp;" +
                      "<a class='spOccLink' href='" + this.occurrences[x].url +
                      "'>" + this.species + " (" + this.occurrences[x].count +
                      " distribution points)</a> | <a class='spOccLink' " + 
                      "href='" + this.occurrences[x].kmlUrl +
                      "'>Google Earth</a> | " +
                      "<a class='giSearchLink' href='" + giSearch +
                      "' target='_blank'>Google Images" + 
                      "</a></td></tr></table>";
            
            pointLyrs.innerHTML += tbl;

         }
         catch(e)
         {
            document.getElementById('map').innerHTML = "An error occurred when trying to get the point overlay " + e;
         }
      }
      else
      {
         //document.getElementById('pointLayers').innerHTML = "This species does not have any points in the Lifemapper database ... yet.";
      }
   }
   
   this.map.zoomToMaxExtent();
}

/* ------------------------------------------------------------------------- */
function LM_registerBackgroundEvents(layer)
   /*
   @summary: Registers events for the background image of the map
   @param layer: The layer to register events for
   */
{
   layer.updateDiv = 
         function(event) 
         {
            document.getElementById("loadingBkgrd").innerHTML = event;
         }
         
   layer.events.register("loadstart", layer, 
                         function() 
                         {
                            this.updateDiv("Loading background");
                         });
                         
   layer.events.register("tileloaded", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   layer.events.register("loadend", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   this.map.addLayer(layer);
}

/* ------------------------------------------------------------------------- */
function LM_registerProjectionEvents(layer)
   /*
   @summary: Registers loading events for a projection image
   @param layer: The layer to register events before
   */
{
   layer.updateDiv = 
         function(event) 
         {
            document.getElementById("loadingLayers").innerHTML = event;
         }
         
   layer.events.register("loadstart", layer, 
                         function() 
                         {
                            this.updateDiv("Loading projection");
                         });
                         
   layer.events.register("tileloaded", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   layer.events.register("loadend", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   this.map.addLayer(layer);
}

/* ------------------------------------------------------------------------- */
function LM_registerPointEvents(layer)
   /*
   @summary: Registers loading events for a point layer image
   @param layer: The layer to register events before
   */
{
   layer.updateDiv = 
         function(event) 
         {
            document.getElementById("loadingPoints").innerHTML = event;
         }
         
   layer.events.register("loadstart", layer, 
                         function() 
                         {
                           this.updateDiv("Loading points");
                         });
                         
   layer.events.register("tileloaded", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   layer.events.register("loadend", layer, 
                         function() 
                         {
                            this.updateDiv("");
                         });
                         
   this.map.addLayer(layer);
}

/* ------------------------------------------------------------------------- */
function LM_selectOneProjection(id)
   /*
   @summary: Selects one projection from the projections array of a LmMap,
                the rest of the projections will be hidden
   @param id: The id of the projection that should be visible
   */
{
   for (var x = 0; x < this.projections.length; x = x + 1)
   {
      vis = false;
      if (id == this.projections[x].id)
      {
         vis = true;
      }
      this.projections[x].projectionLayer.setVisibility(vis);
   }
}
/* ------------------------------------------------------------------------- */
function LM_displayPointLayer(id, displayMe)
   /*
   @summary: Turns on or off a point layer depending on the displayMe value
   @param id: The occurrence set id
   @param displayMe: true or false, display occcurrence set layer
   */
{
   for (var x = 0; x < this.occurrences.length; x = x+1)
   {
      if (id == this.occurrences[x].id)
      {
         this.occurrences[x].pointLayer.display(displayMe);
      }
   }
}

/* ------------------------------------------------------------------------- */
