/********************************************
* Map Feature Functions                     *
*********************************************/
function getFeatFIPS(feature) {
  return feature.attributes.FIPS.value;
}

function getFeatPlaceName(feature) {
  var sPlaceName = feature.attributes.PLACE_NAME.value;
  var sFIPS = getFeatFIPS(feature);
  if(sFIPS.length > 2) {
    sPlaceName += ", " + feature.attributes.STATE_ABBR.value;
  }
  return sPlaceName;
}

function getFeatCtrPosition(feature) {
  return _oMap.getPixelFromLonLat(feature.geometry.getBounds().getCenterLonLat());
}

function onOLPopupClose() {
  _oCtrlHoverSelectFeat_Imp.unselectAll();
  _oCtrlHoverSelectFeat_Rep.unselectAll();
}

function placeNamePopup(feature) {
  var sPopupContent = getFeatPlaceName(feature);

  popup = new OpenLayers.Popup.FramedCloud("pophover", 
    feature.geometry.getBounds().getCenterLonLat(),
    new OpenLayers.Size(50,50),
    sPopupContent,
    null, false, onOLPopupClose
  );
  
  feature.popup = popup;
  _oMap.addPopup(popup, true);
}

function onFeatHoverSelect(event) {
  var feature = event.feature;
  placeNamePopup(feature);
}

function onFeatHoverUnselect(event) {
  var feature = event.feature;
  if(feature.popup) {
    _oMap.removePopup(feature.popup);
    feature.popup.destroy();
    delete feature.popup;
  }
}

function onFeatSelect_Imp(event) {
  onFeatHoverUnselect(event);
  queryCountsDetails_Imp(event.feature);
}

function onFeatSelect_Rep(event) {
  onFeatHoverUnselect(event);
  queryCountsDetails_Rep(event.feature);
}

function onFeatUnselect(event) {
  showDlgFeatCounts(false);
  onFeatHoverUnselect(event);
}

/********************************************
* Map Classification Functions              *
*********************************************/
function createClasses(iMinVal, iMaxVal) {
  var oiaMapClasses = [];
  var iNumClasses;
  var iNewMinVal = iMinVal>0?iMinVal:1;
  
  if((iMaxVal - iNewMinVal + 1) < _iMaxNumClasses) {
    iNumClasses = (iMaxVal - iNewMinVal + 1);
  }
  else {
    iNumClasses = _iMaxNumClasses;
  }
  
  var iInterval = Math.floor((iMaxVal - iNewMinVal + 1) / iNumClasses);
  var iMod = (iMaxVal - iNewMinVal + 1) % iNumClasses;
  
  var iLowerBound, iUpperBound;
  oiaMapClasses[0] = [0, 0];
  if(iNumClasses > 0) {
    for(iClass = 1; iClass <= iNumClasses; iClass++) {
      if(iClass == 1) {
        iLowerBound = iNewMinVal;
      }
      else {
        iLowerBound = oiaMapClasses[iClass-1][1] + 1;
      }
      if(iClass <= iMod) {
        iUpperBound = iLowerBound + iInterval;
      }
      else {
        iUpperBound = iLowerBound + iInterval - 1;
      }
      oiaMapClasses[iClass] = [iLowerBound, iUpperBound];
    }
  }
  return oiaMapClasses;
}

function classify(iQuerySubject, feature) {
  var aiPlaceCounts;
  var oiaMapClasses;
  var iTotalCount = 0;
  var iStatewideCount = 0;
  var iClassVal = 0;
  
  var oFeatAtrbts = feature.attributes;
  var sFIPS = oFeatAtrbts.FIPS.value;
  
  switch(iQuerySubject) {
    case _oQuerySubjects.Impacts:
      iStatewideCount = _iStatewideCount_Imp;
      aiPlaceCounts = _osiPlaceCounts_Imp;
      oiaMapClasses = _oiaMapClasses_Imp;
      break;
    case _oQuerySubjects.Reports:
      iStatewideCount = _iStatewideCount_Rep;
      aiPlaceCounts = _osiPlaceCounts_Rep;
      oiaMapClasses = _oiaMapClasses_Rep;
      break;
    case _oQuerySubjects.Reports_SrcLoc:
      iStatewideCount = _iStatewideCount_Rep;
      aiPlaceCounts = _osiPlaceCounts_Rep;
      oiaMapClasses = _oiaMapClasses_Rep;
      break;
    default:
      break;
  }

  if(aiPlaceCounts != null && aiPlaceCounts[sFIPS] != null) {
    iTotalCount = aiPlaceCounts[sFIPS];
  }
  else {
    if(sFIPS != null && iQuerySubject != _oQuerySubjects.Reports_SrcLoc) {
      iTotalCount = sFIPS.length>2?iStatewideCount:0;
    }
  }
  
  for(var i in oiaMapClasses) {
    if(iTotalCount >= oiaMapClasses[i][0] && iTotalCount <= oiaMapClasses[i][1]) {
      iClassVal = i;
      break;
    }
  }
  oFeatAtrbts.CLASS = iClassVal;
}

function classify_Imp(feature) {
  classify(_oQuerySubjects.Impacts, feature);
}

function classify_Rep(feature) {
  classify(_oQuerySubjects.Reports, feature);
}

function classify_RepSrcLoc(feature) {
  classify(_oQuerySubjects.Reports_SrcLoc, feature);
}

/********************************************
* Map Control Functions                     *
*********************************************/
function updateLegend(iQuerySubject) {
  var oiaMapClasses;
  var oStyleLookup;
  switch(iQuerySubject) {
    case _oQuerySubjects.Impacts:
      oiaMapClasses = _oiaMapClasses_Imp;
      oStyleLookup = _oStyleLookup_Imp;
      break;
    case _oQuerySubjects.Reports:
    case _oQuerySubjects.Reports_SrcLoc:
      oiaMapClasses = _oiaMapClasses_Rep;
      oStyleLookup = _oStyleLookup_Rep;
      break;
    default:
      break;
  }

  var sTblName = "tblLegend" + getQuerySubjectName(iQuerySubject);
  var oTblLegend = document.getElementById(sTblName);
  if((oTblLegend != null) && (oiaMapClasses != null) && (oStyleLookup != null)) {
    while(oTblLegend.rows.length > 0) {
      oTblLegend.deleteRow(0);
    }
    
    var oRowTitle = oTblLegend.insertRow(0);
    var oCellTitle = oRowTitle.insertCell(0);
    oCellTitle.innerHTML = "<strong>Legend</strong>";
    
    for(var iClass in oiaMapClasses) {
      if(iClass == 0 && iQuerySubject == _oQuerySubjects.Reports_SrcLoc) {
        continue;
      }
      var oRowLegend = oTblLegend.insertRow(oTblLegend.rows.length);
      var oCellSymbol = oRowLegend.insertCell(0);
      oCellSymbol.align = "center";
      var oCellRange = oRowLegend.insertCell(1);
      switch(iQuerySubject) {
        case _oQuerySubjects.Impacts:
        case _oQuerySubjects.Reports:
          oCellSymbol.bgColor = oStyleLookup[iClass].fillColor;
          break;
        case _oQuerySubjects.Reports_SrcLoc:
          oCellSymbol.innerHTML = "<img src=\"images/circle" + iClass + ".png\">";
          break;
        default:
          break;
      }
      
      var iLowerBound = oiaMapClasses[iClass][0];
      var iUpperBound = oiaMapClasses[iClass][1];
      oCellRange.align = "left";
      oCellRange.innerHTML = iLowerBound;
      if(iLowerBound != iUpperBound) {
        oCellRange.innerHTML += " - " + iUpperBound;
      }
    } // for iClass loop
  } // if found legend table
}

function selectDDLStates(sStateFIPS) {
  var found = false;
  var oDDLStates = document.getElementById(_sDDLNameState);
  if(oDDLStates != null) {
    for(var i = 0; i < oDDLStates.options.length; i++) {
      if(oDDLStates.options[i].value == sStateFIPS) {
        oDDLStates.options[i].selected = true;
        found = true;
        break;
      }
    }
    updateDDLCounties();
  }
  return found;
}

function updateDDLCounties() {
  showRefreshWarning(true);

  var oRowCounties = document.getElementById("rowDDLCounty");
  
  var oDDLCounties = document.getElementById("ddlCounties");
  while(oDDLCounties.options.length > 1) {
    oDDLCounties.remove(oDDLCounties.options.length-1);
  }

  var oDDLStates = document.getElementById(_sDDLNameState);
  var sStateFIPS = oDDLStates.options[oDDLStates.selectedIndex].value;
  
  if(sStateFIPS == "00") {
    oRowCounties.style.display = 'none';
  }
  else {
    var oRequest = { StateFIPS: sStateFIPS };
    
    var svcURL = document.location.pathname;
    if (/\/$/.test(svcURL)) {
      svcURL += "map.aspx";
    }
    svcURL += "/getCounties";
    
    var jsonText = JSON.stringify(oRequest);
  
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        url: svcURL,
        data: jsonText,
        error: function (err_msg) {
            alert('Error\n' + err_msg.status + '\n' + err_msg.statusText);
        },
        success: function (data) {
            var oCounties = data.d;
            for(var i = 0; i < oCounties.length; i++) {
                var oCounty = document.createElement("option");
                oCounty.text = oCounties[i].Name;
                oCounty.value = oCounties[i].FIPS;
                oDDLCounties.options.add(oCounty);
            }
        }
    });
    
    oRowCounties.style.display = '';
  }
}

function mapQuery() {
  showDlgFeatCounts(false);
  showRefreshWarning(false);
  while(_oMap.popups.length > 0) {
    _oMap.removePopup(_oMap.popups[0]);
  }
  
  if(getQueryOptions()) {
    if(_oQueryReq_Common.FIPSs.length > 0) {
      var sStateFIPS = (_oQueryReq_Common.FIPSs)[0];
      var sStateAbbr = getStateAbbr(sStateFIPS);
      _sKMLAreas = "spatial/County_"+sStateAbbr+".kml";
    }
    else {
      _sKMLAreas = "spatial/US_States.kml";
    }

    updateHLQueryOptions();
    queryHLCounts_Imp();
    queryCounts_Imp();
    
    queryHLCounts_Rep();
    queryCounts_Rep();
    
    queryHLCaseList_Imp(0);
    queryHLCaseList_Rep(0);
  }
}

function drawSrcLocs() {
  var iNumPnts = _osoSrcLocs_Rep.length;
  var aPntFeats = [];
  
  for(var sFIPS in _osoSrcLocs_Rep) {
    aPntFeats.push(new OpenLayers.Feature.Vector(
      OpenLayers.Projection.transform(new OpenLayers.Geometry.Point(_osoSrcLocs_Rep[sFIPS].Longitude, _osoSrcLocs_Rep[sFIPS].Latitude), _oProjGeo, _oProjMercator)
    ));
    aPntFeats[aPntFeats.length-1].attributes = {};
    aPntFeats[aPntFeats.length-1].attributes.FIPS = {value: sFIPS};
    aPntFeats[aPntFeats.length-1].attributes.PLACE_NAME = {value: _osoSrcLocs_Rep[sFIPS].PlaceName};
    aPntFeats[aPntFeats.length-1].attributes.STATE_ABBR = {value: _osoSrcLocs_Rep[sFIPS].StateAbbr};
  }
  
  _osoLyrs["Reports"].removeAllFeatures({silent: true});
  _osoLyrs["Reports"].styleMap = _oStyleMap_Rep_SrcLoc;
  _osoLyrs["Reports"].addFeatures(aPntFeats);
}

function refreshLayer(iQuerySubject) {
  var sLyrID = getQuerySubjectName(iQuerySubject);
  
  _osoLyrs[sLyrID].loaded = false;
  _osoLyrs[sLyrID].setVisibility(true);
  _osoLyrs[sLyrID].protocol.destroy();
  
  if(iQuerySubject == _oQuerySubjects.Reports_SrcLoc) {
    drawSrcLocs();
  }
  else {
    if(iQuerySubject == _oQuerySubjects.Reports) {
      _osoLyrs[sLyrID].styleMap = _oStyleMap_Rep;
    }
    
    _osoLyrs[sLyrID].protocol = new OpenLayers.Protocol.HTTP({
      url: _sKMLAreas,
      format: _oFrmtKML
    });
    _osoLyrs[sLyrID].refresh({force: true});
  }
  
  showLayers();
  updateLegend(iQuerySubject);
}

function goToCountyView(sStateFIPS) {  
  if(selectDDLStates(sStateFIPS)) {
    mapQuery();
  }
}

function goToAllStatesView() {
  if(selectDDLStates('00')) {
    mapQuery();
  }
}

function showLayers() {
  for(var sLyrID in _osoLyrs) {
    var oChkbox = document.getElementById("chk"+sLyrID);
    _osoLyrs[sLyrID].setVisibility(oChkbox.checked);
  }
}

function zoomTo() {
  var oDDLCounties = document.getElementById("ddlCounties");
  var sCntyFIPS = oDDLCounties.options[oDDLCounties.selectedIndex].value;
  if(sCntyFIPS != "00000") {
    for(var iFeature = 0; iFeature < _osoLyrs["Impacts"].features.length; iFeature++) {
      if(_osoLyrs["Impacts"].features[iFeature].attributes.FIPS.value == sCntyFIPS) {
        var oFeature = _osoLyrs["Impacts"].features[iFeature];
        _oMap.zoomToExtent(oFeature.geometry.getBounds());
        placeNamePopup(oFeature);
        break;
      }
    }
  }
  else {
    var oDDLStates = document.getElementById(_sDDLNameState);
    var sStateFIPS = oDDLStates.options[oDDLStates.selectedIndex].value;
    if(sStateFIPS == "00") {
      _oMap.zoomToExtent(_oExtentUS);
    }
    else {
      _oMap.zoomToExtent(_osoLyrs["Impacts"].getDataExtent());
    }
  }
}

function initializeImpRepLyrs() {
  _sKMLAreas = "spatial/US_States.kml";
  _oFrmtKML = new OpenLayers.Format.KML({
    extractAttributes: true,
    extractStyles: false
  });
  var oProtocol_Common = new OpenLayers.Protocol.HTTP({
      url: _sKMLAreas,
      format: _oFrmtKML
  });
  
  // Define impact layer
  _osoLyrs["Impacts"] = new OpenLayers.Layer.Vector('Impacts', {
    protocol: oProtocol_Common,
    styleMap: _oStyleMap_Imp,
    projection: _oProjGeo,
    strategies: [new OpenLayers.Strategy.Fixed()],
    //opacity: _iDefaultOpacity,
    preFeatureInsert: classify_Imp
  });
  
  _osoLyrs["Impacts"].events.register("loadstart", this, function() {
    showLoader(true);
  });
  
  _osoLyrs["Impacts"].events.register("loadend", this, function () {
    showLoader(false);
    _osoLyrs["Impacts"].setOpacity($("#sldrImpacts").slider("option", "value"));
    zoomTo();
  });
  
  // set up the hover popup control for impact layer
  _oCtrlHoverSelectFeat_Imp = new OpenLayers.Control.SelectFeature(_osoLyrs["Impacts"], {
    hover: true,
    highlightOnly: true,
    eventListeners: {
      featurehighlighted: onFeatHoverSelect,
      featureunhighlighted: onFeatHoverUnselect
    }
  });
  //_oMap.addControl(_oCtrlHoverSelectFeat_Imp);
  //_oCtrlHoverSelectFeat_Imp.activate();
  
  // set up the popup control for impact layer
  _oCtrlSelectFeat_Imp = new OpenLayers.Control.SelectFeature(_osoLyrs["Impacts"], {
    hover: false,
    eventListeners: {
      featurehighlighted: onFeatSelect_Imp,
      featureunhighlighted: onFeatUnselect
    }
  });
  _oMap.addControl(_oCtrlSelectFeat_Imp);
  _oCtrlSelectFeat_Imp.activate();

  // Define report layer
  _osoLyrs["Reports"] = new OpenLayers.Layer.Vector('Reports', {
    protocol: oProtocol_Common,
    styleMap: _oStyleMap_Rep,
    projection: _oProjGeo,
    strategies: [new OpenLayers.Strategy.Fixed()],
    //opacity: _iDefaultOpacity,
    preFeatureInsert: classify_Rep
  });

  _osoLyrs["Reports"].events.register("loadstart", this, function() {
    _osoLyrs["Reports"].setOpacity($("#sldrReports").slider("option", "value"));
    showLoader(true);
  });
  
  _osoLyrs["Reports"].events.register("loadend", this, function () {
    showLoader(false);
  });

  // set up the hover popup control for report layer
  _oCtrlHoverSelectFeat_Rep = new OpenLayers.Control.SelectFeature(_osoLyrs["Reports"], {
    hover: true,
    highlightOnly: true,
    eventListeners: {
      featurehighlighted: onFeatHoverSelect,
      featureunhighlighted: onFeatHoverUnselect
    }
  });
  //_oMap.addControl(_oCtrlHoverSelectFeat_Rep);
  //_oCtrlHoverSelectFeat_Rep.activate();
  
  // set up the popup control for report layer
  _oCtrlSelectFeat_Rep = new OpenLayers.Control.SelectFeature(_osoLyrs["Reports"], {
    hover: false,
    highlightOnly: true,
    eventListeners: {
      featurehighlighted: onFeatSelect_Rep,
      featureunhighlighted: onFeatUnselect
    }
  });
  _oMap.addControl(_oCtrlSelectFeat_Rep);
  _oCtrlSelectFeat_Rep.activate();
}

function updateDrtMntrLyr() {
  var dateSelDate = $("#txtDMDate").datepicker("getDate");
  var dmLyrSuffix = dateSelDate.dmLyrSuffix();
  $("#cellDMDate").html("Drought Monitor Date: " + dateSelDate.dmDate().mm_dd_yyyy());
  
  var iOpacity = _osoLyrs["DrtMntr"].opacity;
  var iDMIndex = _oMap.getLayerIndex(_osoLyrs["DrtMntr"]);
  
  _osoLyrs["DrtMntr"].destroy();
  
   _osoLyrs["DrtMntr"] = new OpenLayers.Layer.WMS(
      _osoExtraLyrPrmtrs["DrtMntr"].name,
      _osoExtraLyrPrmtrs["DrtMntr"].url + dmLyrSuffix + "_wms.map",
      {
        layers:  _osoExtraLyrPrmtrs["DrtMntr"].layer + dmLyrSuffix,
        transparent: true
      },
      {
        isBaseLayer: false,
        opacity: iOpacity
      }
    );
    
    _osoLyrs["DrtMntr"].events.register("loadstart", this,
      function() {
        showLoader(true);
      }
    );
  
    _osoLyrs["DrtMntr"].events.register("loadend", this,
      function () {
        showLoader(false); 
      }
    );
    
    _oMap.addLayer(_osoLyrs["DrtMntr"]);
    _oMap.setLayerIndex(_osoLyrs["DrtMntr"], iDMIndex);
    _oMap.resetLayersZIndex();
    showLayers();
}

function initializeExtraLyrs() {
  var sMSLyrID, sLyrURL, sLyrName;
  var iLyrIdx = 3;
  for(var sLyrID in _osoExtraLyrPrmtrs) {
    if(sLyrID != "DrtMntr") {
      sMSLyrID = _osoExtraLyrPrmtrs[sLyrID].layer;
      sLyrURL = _osoExtraLyrPrmtrs[sLyrID].url;
    }
    else {
      var dateLatestDM = getLatestDMDate();
      sMSLyrID = _osoExtraLyrPrmtrs[sLyrID].layer + dateLatestDM.dmLyrSuffix();
      sLyrURL = _osoExtraLyrPrmtrs[sLyrID].url + dateLatestDM.dmLyrSuffix() + "_wms.map";
    }
    
    sLyrName = _osoExtraLyrPrmtrs[sLyrID].name;
    
    _osoLyrs[sLyrID] = new OpenLayers.Layer.WMS(
      sLyrName, sLyrURL,
      {
        layers: sMSLyrID,
        transparent: true
      },
      {
        isBaseLayer: false,
        opacity: _iDefaultOpacity,
        visibility: false
      }
    );
    
    _osoLyrs[sLyrID].events.register("loadstart", this,
      function() {
        showLoader(true);
      }
    );
  
    _osoLyrs[sLyrID].events.register("loadend", this,
      function () {
        showLoader(false); 
      }
    );
  } // for sLyrID
}

function initializeMap() {
  var oMapOptions = {
    projection: _oProjMercator,
    displayProjection: _oProjGeo,
    maxExtent: _oExtentUS,
    //restrictedExtent: _oExtentAllUS,
    maxResolution: 'auto'    
  };

  _oMap = new OpenLayers.Map('map_canvas', oMapOptions);
            
  // Define Google street layer
  _oLyrGoogleSt = new OpenLayers.Layer.Google(
    "Google Streets",
    { type: google.maps.MapTypeId.ROADMAP,
      sphericalMercator: true }
  );
  
  // add base layer to the Map
  _oMap.addLayer(_oLyrGoogleSt);
  //_oMap.zoomToExtent(_oExtentUS);
  _oMap.addControls([
    new OpenLayers.Control.MousePosition()
    //new OpenLayers.Control.LayerSwitcher()
  ]);
  
  // initialize impat, report, and extra layers
  initializeImpRepLyrs();
  initializeExtraLyrs();
  
  // add layers 
  for(var sLyrID in _osoLyrs) {
    _oMap.addLayer(_osoLyrs[sLyrID]);
  }
  
  // query
  mapQuery();
}

function showExtent() {
    var extent = _oMap.getExtent().transform(_oProjMercator,_oProjGeo);
    $("#spnExtent").html(extent.toString());
}
