/* sflorida_layerlist.js: Modified from LayerSwitcher.js for South Florida application */

/** 
 * @requires OpenLayers/Control.js
 */

OpenLayers.Control.NewLayerSwitcher = 
  OpenLayers.Class(OpenLayers.Control, {
    doRedraw: true,
    layerStates: null,
    dataLayers: null,
    dataLayerDivs: {},
    epmTables: {},
    ascending: true,
    groups: [],
    groupDivs: {},
    legendWindows: {},
    initialize: function(options) {
      OpenLayers.Control.prototype.initialize.apply(this, arguments);
      this.layerStates = [];
    },
    
    destroy: function() {
      OpenLayers.Event.stopObservingElement(this.div);

      // clear out layers info and unregister their events 
      this.clearLayersArray();
        
      this.map.events.un({
        addlayer: this.redraw,
        changelayer: this.redraw,
        removelayer: this.redraw,
        changebaselayer: this.redraw,
        scope: this
      });
      
      OpenLayers.Control.prototype.destroy.apply(this, arguments);
    },
    setMap: function(map) {
      OpenLayers.Control.prototype.setMap.apply(this, arguments);

      this.map.events.on({
        addlayer: this.redraw,
        changelayer: this.redraw,
        removelayer: this.redraw,
        changebaselayer: this.redraw,
        scope: this
      });
    },
    draw: function() {
      OpenLayers.Control.prototype.draw.apply(this);

      // create layout divs
      this.loadContents();

      // populate div with current info
      this.redraw();    

      return this.div;
    },

    // Clear all the corresponding listeners, the div, and reinitialize a new array
    clearLayersArray: function() {
      var layers = this.dataLayers;
      if (layers) {
        for (var i=0, len=layers.length; i<len ; i++) {
          var layer = layers[i];
          OpenLayers.Event.stopObservingElement(layer.inputElem);
          OpenLayers.Event.stopObservingElement(layer.labelSpan);
        }
      }
      this.dataLayers = [];
      for (var div in this.dataLayerDivs) {
        this.dataLayerDivs[div].parentNode.removeChild(this.dataLayerDivs[div]);
      }
      this.dataLayerDivs = {};
      for (var table in this.epmTables) {
        this.epmTables[table].parentNode.removeChild(this.epmTables[table]);
      }
      this.epmTables = {};
    },

    // Checks if the layer state has changed since the last redraw() call
    checkRedraw: function() {
      var redraw = false;
      if (this.doRedraw) {
        if ( !this.layerStates.length || (this.map.layers.length != this.layerStates.length) ) {
          redraw = true;
        } 
        else {
          for (var i=0, len=this.layerStates.length; i<len; i++) {
            var layerState = this.layerStates[i];
            var layer = this.map.layers[i];
            if ( (layerState.name != layer.name) || 
                 (layerState.id != layer.id) || 
                 (layerState.visibility != layer.visibility) ) {
              redraw = true;
              break;
            }    
          }
        }
      }
      return redraw;
    },
    
    // redraw: Goes through and takes the current state of the Map and rebuilds the control to display that state
    redraw: function() {
      //if the state hasn't changed since last redraw, no need to do anything. Just return the existing div.
      if (!this.checkRedraw()) { 
        return this.div; 
      } 

      //clear out previous layers 
      this.clearLayersArray();
      
      var containsOverlays = false;
      var containsBaseLayers = false;
      
      for (var i = 0; i < this.groups.length; i++) {
        var groupName = this.groups[i][0];
        if (!this.groupDivs[groupName]) {
          var newGroupDiv = this.createGroupDiv(this.groups[i]);
          this.groupDivs[groupName] = newGroupDiv;
          this.div.appendChild(newGroupDiv);
        }
      }
      // Save state -- for checking layer if the map state changed.
      // We save this before redrawing, because in the process of redrawing
      // we will trigger more visibility changes, and we want to not redraw
      // and enter an infinite loop.
      var len = this.map.layers.length;
      this.layerStates = new Array(len);
      for (var i=0; i <len; i++) {
        var layer = this.map.layers[i];
        this.layerStates[i] = {
            name: layer.name, 
            visibility: layer.visibility,
            id: layer.id
        };
      }    
      
      var layers = this.map.layers.slice();
      if (!this.ascending) { layers.reverse(); }
      var numLayers = layers.length;
      for (var i = 0; i < numLayers; i++) {
        var layer = layers[i];
        if (layer.displayInLayerSwitcher) {
          if (layer.group == "epmresults") {
            // Do EPM Results differently
            if (layer.name.substr(0,5) == "main_") {
              var runNameRegex = new RegExp(layer.name.substr(4) + "$");    // save _ + run name for later use
              var epmTable = document.createElement("table");
              epmTable.style.display = 
                (document.getElementById("img_" + layer.group).src.indexOf("Closed") > -1) ? "none" : "block";
              var epmTr = document.createElement("tr");
              
              // create main radio button and label
              var mainTd = document.createElement("td");
              var mainDiv = document.createElement("div");
              mainDiv.className = "olLayerDiv";
              
              var mainInputElem = document.createElement("input");
              mainInputElem.value = layer.name;
              mainInputElem.type = "radio";
              mainInputElem.name = layer.group;
              mainInputElem.id = "rdo_" + layer.name;
              mainInputElem.defaultChecked = mainInputElem.checked = layer.getVisibility();
              // the following is needed to fix an IE bug
              if (mainInputElem.checked) {
                if (document.getElementById("rdo_" + layer.group + "_none")) {
                  document.getElementById("rdo_" + layer.group + "_none").checked = false;
                }
              }
              var mainInputContext = { inputElem: mainInputElem, layer: layer, layerSwitcher: this };
              OpenLayers.Event.observe(mainInputElem, "mouseup",
                                       OpenLayers.Function.bindAsEventListener(this.onInputClick, mainInputContext));
              var mainLabelSpan = document.createElement("span");
              mainLabelSpan.id = "lbl_" + layer.name;
              mainLabelSpan.innerHTML = layer.title;
              mainLabelSpan.className = "olLayerLabel";
              mainLabelSpan.style.cursor = "pointer";
              mainLabelSpan.title = "Click here to see layer legend";
              var mainLegendContext = { layer: layer, legendWindows: this.legendWindows };
              OpenLayers.Event.observe(mainLabelSpan, "mouseup", 
                                       OpenLayers.Function.bindAsEventListener(this.openLegendWindow, mainLegendContext));
              // add to layer array
              this.dataLayers.push( { layer: layer, inputElem: mainInputElem, labelSpan: mainLabelSpan });
              this.dataLayerDivs[layer.name] = mainDiv;
              
              mainDiv.appendChild(mainInputElem);
              mainDiv.appendChild(mainLabelSpan);
              mainTd.appendChild(mainDiv);
              epmTr.appendChild(mainTd);
              
              var criteriaTd = document.createElement("td");
              criteriaTd.style.paddingLeft = "10px";
            
              for (var j = i + 1; layers[j].name.match(runNameRegex); j++) {
                if (j == i + 4) {  
                  criteriaTd.appendChild(document.createElement("br"));
                }
                var criteriaLayer = layers[j];
                var criteriaSpan = document.createElement("span");
                var critInputElem = document.createElement("input");
                critInputElem.value = criteriaLayer.name;
                critInputElem.type = "radio";
                critInputElem.name = criteriaLayer.group;
                critInputElem.id = "rdo_" + criteriaLayer.name;
                critInputElem.defaultChecked = critInputElem.checked = criteriaLayer.getVisibility();
                // the following is needed to fix an IE bug
                if (critInputElem.checked) {
                  if (document.getElementById("rdo_" + criteriaLayer.group + "_none")) {
                    document.getElementById("rdo_" + criteriaLayer.group + "_none").checked = false;
                  }
                }
                var critInputContext = { inputElem: critInputElem, layer: criteriaLayer, layerSwitcher: this };
                OpenLayers.Event.observe(critInputElem, "mouseup",
                                         OpenLayers.Function.bindAsEventListener(this.onInputClick, critInputContext));
                var critLabelSpan = document.createElement("span");
                critLabelSpan.id = "lbl_" + criteriaLayer.name;
                critLabelSpan.innerHTML = criteriaLayer.title;
                critLabelSpan.className = "olLayerLabel";
                critLabelSpan.style.cursor = "pointer";
                critLabelSpan.style.paddingRight = "10px";
                critLabelSpan.title = "Click here to see layer legend";
                var critLegendContext = { layer: criteriaLayer, legendWindows: this.legendWindows };
                OpenLayers.Event.observe(critLabelSpan, "mouseup", 
                                         OpenLayers.Function.bindAsEventListener(this.openLegendWindow, critLegendContext));
                criteriaSpan.appendChild(critInputElem);
                criteriaSpan.appendChild(critLabelSpan);
                criteriaTd.appendChild(criteriaSpan);
                // add to layer array
                this.dataLayers.push( { layer: criteriaLayer, inputElem: critInputElem, labelSpan: critLabelSpan });
                this.dataLayerDivs[criteriaLayer.name] = criteriaSpan;
              }
              epmTr.appendChild(criteriaTd); 
              epmTable.appendChild(epmTr);
              
              this.groupDivs[layer.group].appendChild(epmTable);
              this.epmTables[layer.name.substr(5)] = epmTable;
            }
          }
          else {
            // only check a baselayer if it is *the* baselayer, check data layers if they are visible
            var checked = layer.getVisibility();
            // create div
            var layerDiv = document.createElement("div");
            layerDiv.className = "olLayerDiv";
  
            // make sure open/collapse group works properly
            if (layer.group) {
              if (layer.group == "existing" || layer.group == "ks" || layer.group == "user") {
                var parentDiv = this.groupDivs[layer.group];
                parentDiv.style.display = (!document.getElementById("rdo_" + layer.group).checked) ? "none" : "block";
              }
              else {
                layerDiv.style.display = (document.getElementById("img_" + layer.group).src.indexOf("Closed") > -1) ? "none" : "block";
              }
            }
  
            // create input element
            var inputElem = document.createElement("input");
            inputElem.value = layer.name;
            if (layer.group && document.getElementById("rdo_" + layer.group + "_none")) {
              inputElem.type = "radio";
              inputElem.name = layer.group;
              inputElem.id = "rdo_" + layer.name;
            }
            // LULC
            else if (layer.group == "existing" || layer.group == "ks" || layer.group == "user") {
              inputElem.type = "radio";
              inputElem.name = "lulc";
              inputElem.id = "rdo_" + layer.name;
            }
            else {
              inputElem.type = "checkbox";
              inputElem.name = layer.name;
              inputElem.id = "cbo_" + layer.name;
            }
            inputElem.checked = checked;
            inputElem.defaultChecked = checked;
            // the following is needed to fix an IE bug
            if (checked && inputElem.type == "radio") {
              if (document.getElementById("rdo_" + layer.group + "_none")) {
                document.getElementById("rdo_" + layer.group + "_none").checked = false;
              }
            }
  
            var context = { inputElem: inputElem, layer: layer, layerSwitcher: this };
            OpenLayers.Event.observe(inputElem, "mouseup", OpenLayers.Function.bindAsEventListener(this.onInputClick, context));
                
            var labelSpan = document.createElement("span");
            labelSpan.id = "lbl_" + layer.name;
            labelSpan.innerHTML = layer.title;
            labelSpan.className = "olLayerLabel";
            if (layer.legendURL) {
              labelSpan.style.cursor = "pointer";
              labelSpan.title = "Click here to see layer legend";
              var legendContext = { layer: layer, legendWindows: this.legendWindows };
              OpenLayers.Event.observe(labelSpan, "mouseup", 
                                       OpenLayers.Function.bindAsEventListener(this.openLegendWindow, legendContext));
            }
                
            // append input and layer lables
            layerDiv.appendChild(inputElem);
            layerDiv.appendChild(labelSpan);
  
            // add to layer array
            this.dataLayers.push( { layer: layer, inputElem: inputElem, labelSpan: labelSpan });
            this.dataLayerDivs[layer.name] = layerDiv;
            
            // select parent DIV for layer
            var parentDiv = layer.group ? this.groupDivs[layer.group] : this.div;
            parentDiv.appendChild(layerDiv);
          }
        }
      }

      return this.div;
    },

    onInputClick: function(e) {
      if (!this.inputElem.disabled) {
        if (this.inputElem.type != "radio" || !this.inputElem.checked) {   // don't do anything if the radio button is already checked
          this.inputElem.checked = !this.inputElem.checked;
          var redraw = false;
          if (this.inputElem.id == "rdo_existing") {
            this.layerSwitcher.groupDivs["existing"].getElementsByTagName("input")[0].checked = true;
            redraw = true;
          }
          else if (this.inputElem.id == "rdo_ks") {
            this.layerSwitcher.groupDivs["ks"].getElementsByTagName("input")[0].checked = true;
            redraw = true;
          }
          else if (this.inputElem.id == "rdo_user" && this.layerSwitcher.groupDivs["user"].getElementsByTagName("input").length > 0) {
            this.layerSwitcher.groupDivs["user"].getElementsByTagName("input")[0].checked = true;
            redraw = true;
          }
          else if (this.inputElem.id == "rdo_user" || this.inputElem.id == "rdo_lulc_none") {
            redraw = true;
            // Turn off radio buttons/layers in other subgroups
            var off = false;
            var existingInputs = this.layerSwitcher.groupDivs["existing"].getElementsByTagName("input");
            for (var i = 0; i < existingInputs.length; i++) {
              if (existingInputs[i].checked) {
                existingInputs[i].checked = false;
                off = true;
                break;
              }
            }
            if (!off) {
              var ksInputs = this.layerSwitcher.groupDivs["ks"].getElementsByTagName("input");
              for (var i = 0; i < ksInputs.length; i++) {
                if (ksInputs[i].checked) {
                  ksInputs[i].checked = false;
                  off = true;
                  break;
                }
              }
            }
            if (!off) {
              var userInputs = this.layerSwitcher.groupDivs["user"].getElementsByTagName("input");
              for (var i = 0; i < userInputs.length; i++) {
                if (userInputs[i].checked) {
                  userInputs[i].checked = false;
                  off = true;
                  break;
                }
              }
            }
          }
          this.layerSwitcher.updateMap(redraw);
        }
      }
      OpenLayers.Event.stop(e);
    },
    
    // this separate function allows openOrCollapse to be called directly without clicking the arrow
    openOrCollapse: function(group, close) {
      var groupImg = document.getElementById("img_" + group);
      groupImg.src = close ? "/images_shared/CollapsableClosed.gif" : "/images_shared/CollapsableOpen.gif";
      var layerRow = groupImg.nextSibling.nextSibling;  // skip over olGroupName
      while (layerRow) {
        layerRow.style.display = close ? "none" : "block";
        layerRow = layerRow.nextSibling;
      }
    },
    
    openCollapseGroup: function(e) {
      var close = (document.getElementById("img_" + this.groupName).src.indexOf("Open") > -1);
      this.layerSwitcher.openOrCollapse(this.groupName, close);
      OpenLayers.Event.stop(e);
    },

    openLegendWindow: function(e) {
      var layerName = this.layer.name;
      var subtitle = null;
      var title = this.layer.title.replace(/ \(.*\)/g, "").replace(/=.*$/, "");
      if (layerName.substr(0,11) == "sflAcreGrid") {
        title = subtitle = "Price Per Acre";
      }
      else if (layerName.substr(0,13) == "sflParcelGrid") {
        title = "Price Per Sq Ft";
        subtitle = "Price Per Square Foot";
      }
      else if (layerName.substr(0,10) == "sflParcels") {
        title = "Vacant Parcels";
        subtitle = "Price Per Acre (Square Foot)";
      }
      else if (layerName == "ffwcc_habitat") {
        title = "FFWCC";
      }
      
      var openNewWindow = this.legendWindows[layerName] ? this.legendWindows[layerName].closed : true;
      if (!openNewWindow && navigator.appName == "Netscape") {  // To get around Firefox Bug 355482 (if Raise & Lower Windows not on)
        this.legendWindows[this.layer.name].close();
        openNewWindow = true;
      }
      if (openNewWindow) {
        var legendWindow = window.open("", layerName, "scrollbars,dependent,height=200,width=200", false);
        // Dynamically create the legend window
        var legendHTML = "<html>\n<head>\n<title>";
        legendHTML += layerName + " Legend</title>\n<link rel='StyleSheet' type='text/css' href='/css_shared/common.css'/>\n";
        legendHTML += "<link rel='stylesheet' type='text/css' href='/css_shared/openlayers.css' />\n";
        legendHTML += "<link rel='stylesheet' type='text/css' href='sflorida_custom.css' />\n";
        legendHTML += "</head>\n";
        legendHTML += "<body>\n";
        legendHTML += "<h4 style='font-size:13px;text-align:center";
        legendHTML += subtitle ? ";margin-bottom:0px" : ";margin-bottom:7px";
        legendHTML += "'>" + title + " Legend</h4>\n";
        if (subtitle) {
          legendHTML += "<h5 style='font-size:10px;text-align:center;margin-top:0px;margin-bottom:7px'>" + subtitle + "</h5>\n";
        }
        legendHTML += "<img src='" + this.layer.legendURL + "' alt='Legend'";
        legendHTML += "onload='resizeTo(document.images[0].width+80,document.images[0].height<590?document.images[0].height+150:740);";
        legendHTML += "moveTo(0,0);'/>\n";
        legendHTML += "</body>\n</html>";
        legendWindow.document.write(legendHTML);
        legendWindow.document.close();
        legendWindow.focus();
        this.legendWindows[layerName] = legendWindow;
      }
      else
        // NOTE: This doesn't work in Firefox (Bug 355482)
        this.legendWindows[layerName].focus();    // focus on existing open window
      OpenLayers.Event.stop(e);
    },
    
    // Cycles through the loaded data and base layer input arrays and makes the necessary calls to the Map object so the map's 
    //   visual state corresponds to what the user has selected in the control.
    updateMap: function(redraw) {
      // set the correct visibilities for the overlays
      this.doRedraw = false;  
      for (var i = 0, len = this.dataLayers.length; i < len; i++) {
        var layerEntry = this.dataLayers[i];
        layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
      }
      if (redraw) {  // for checkboxes
        this.doRedraw = true;
        this.redraw();  // Only do redraw at the end: This was necessary to get the radio buttons working correctly  
      }
    },

    loadContents: function() {
      //configure main div
      OpenLayers.Event.observe(this.div, "mouseup", OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
      OpenLayers.Event.observe(this.div, "mousedown", OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
      OpenLayers.Event.observe(this.div, "click", this.ignoreEvent);
      OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
    },
    
    ignoreEvent: function(evt) {
      OpenLayers.Event.stop(evt);
    },

    // Register a local mouseDown flag so that we'll know whether or not to ignore a mouseUp event
    mouseDown: function(evt) {
      this.isMouseDown = true;
      this.ignoreEvent(evt);
    },

    // If the isMouseDown flag has been set, that means that the drag was started from within the LayerSwitcher control,
    // and thus we can ignore the mouseup. Otherwise, let the Event continue.
    mouseUp: function(evt) {
      if (this.isMouseDown) {
        this.isMouseDown = false;
        this.ignoreEvent(evt);
      }
    },

    createGroupDiv: function(layergroup) {
      var groupName = layergroup[0];
      var groupLabel = layergroup[1];
      var groupRadio = layergroup[2];
      var groupDiv =  document.createElement("div");
      groupDiv.id = "grp_" + groupName;
      groupDiv.className = "olLayerGroup";
      var img = document.createElement("img");
      img.id = "img_" + groupName;
      img.src = "/images_shared/collapsableClosed.gif";    // start out closed
      img.title = "Click to open or collapse this group";
      img.style.paddingRight = "5px";
      img.style.cursor = "pointer";
      OpenLayers.Event.observe(img, "mouseup", OpenLayers.Function.bindAsEventListener(
                                                 this.openCollapseGroup, { groupName: groupName, layerSwitcher: this }));
              
      nameSpan = document.createElement("span");
      nameSpan.className = "olGroupName";
      nameSpan.innerHTML = groupLabel;
      groupDiv.appendChild(img);
      groupDiv.appendChild(nameSpan);
      if (groupName == "lulc") {
        var lulcDiv = document.createElement("div");
        lulcDiv.className = "olLayerDiv";
        lulcDiv.style.display = "none";     // start out closed
        // go through LULC subgroups
        var subgroups = layergroup[3];
        for (var i = 0; i < subgroups.length; i++) {
          var subSpan = document.createElement("span");
          var subInputElem = document.createElement("input");
          var subgroupName = subgroups[i][0];
          subInputElem.value = subgroupName;
          subInputElem.type = "radio";
          subInputElem.name = "lulcsel";
          subInputElem.id = "rdo_" + subgroupName;
          subInputElem.checked = false;
          var context = { inputElem: subInputElem, layerSwitcher: this };
          OpenLayers.Event.observe(subInputElem, "mouseup", OpenLayers.Function.bindAsEventListener(this.onInputClick, context));
          var subLabelSpan = document.createElement("span");    
          subLabelSpan.id = "lbl_" + subgroupName + "_none";
          subLabelSpan.innerHTML = subgroups[i][1];
          subLabelSpan.className = "olLayerLabel";
          subLabelSpan.style.paddingRight = "7px";
          subSpan.appendChild(subInputElem);
          subSpan.appendChild(subLabelSpan);
          lulcDiv.appendChild(subSpan);
        }
        var noneSpan = document.createElement("span");
        var noneInputElem = document.createElement("input");
        noneInputElem.value = "none";
        noneInputElem.type = "radio";
        noneInputElem.name = "lulcsel";
        noneInputElem.id = "rdo_" + groupName + "_none";
        noneInputElem.checked = true;
        var context = { inputElem: noneInputElem, layerSwitcher: this };
        OpenLayers.Event.observe(noneInputElem, "mouseup", OpenLayers.Function.bindAsEventListener(this.onInputClick, context));
        var noneLabelSpan = document.createElement("span");    
        noneLabelSpan.id = "lbl_" + groupName + "_none";
        noneLabelSpan.innerHTML = "None";
        noneLabelSpan.className = "olLayerLabel";
        noneSpan.appendChild(noneInputElem);
        noneSpan.appendChild(noneLabelSpan);
        lulcDiv.appendChild(noneSpan);
        // create subgroup divs for adding layers to
        for (var j = 0; j < subgroups.length; j++) {
          var subgroupName = subgroups[j][0];
          var newSubgroupDiv =  document.createElement("div");
          newSubgroupDiv.id = "grp_" + subgroupName;
          newSubgroupDiv.className = "olLayerSubgroup";
          newSubgroupDiv.style.display = "none";     // start out closed
          this.groupDivs[subgroupName] = newSubgroupDiv;
          lulcDiv.appendChild(newSubgroupDiv);
        }
        groupDiv.appendChild(lulcDiv);
      }
      else if (groupRadio) {    // Add None radio button
        var noneDiv = document.createElement("div");
        noneDiv.className = "olLayerDiv";
        noneDiv.style.display = "none";     // start out closed
        var inputElem = document.createElement("input");
        inputElem.value = "none";
        inputElem.type = "radio";
        inputElem.name = groupName;
        inputElem.id = "rdo_" + groupName + "_none";
        inputElem.checked = true;
        var context = { inputElem: inputElem, layerSwitcher: this };
        OpenLayers.Event.observe(inputElem, "mouseup", OpenLayers.Function.bindAsEventListener(this.onInputClick, context));
        var labelSpan = document.createElement("span");    
        labelSpan.id = "lbl_" + groupName + "_none";
        labelSpan.innerHTML = "None";
        labelSpan.className = "olLayerLabel";
        noneDiv.appendChild(inputElem);
        noneDiv.appendChild(labelSpan);
        groupDiv.appendChild(noneDiv);
      }
      return groupDiv;
    },

    CLASS_NAME: "OpenLayers.Control.NewLayerSwitcher"
});
