var mapVE = null;
var __mapVEPinCount = 0;
var MAX_PINS_BEFORE_RELOAD = 1000;

var __obj;
var _lat;
var _lon;

/* Shared by main map object and also print view */
function getTileSourceSpec(layerName, tileServerName)
{
    var url = "http://" + tileServerName + "/dpd/Apps/Map_Layers/" + layerName + "/Layer_NewLayer/%4.png";
    var opacity = 0.25;
    if (layerName == "HouseNumbers" || layerName == "Parcels" || layerName == "Contours" || layerName == "PavementEdge")
        opacity = 1.0;
    var tileSource = new VETileSourceSpecification(layerName,url);
    tileSource.MinZoomLevel = 8;
    tileSource.MaxZoomLevel = 19;
    tileSource.NumServers = 1;
    tileSource.Opacity = opacity;
    tileSource.ZIndex = 100;
    return tileSource;
}

var Map = {
  init : function(center, zoom, tileServer) {
    this.IE = navigator.appName.indexOf('Microsoft')>-1?1:0;
    this.FF = navigator.appName.indexOf('Microsoft')>-1?0:1;
    
    mapVE = new VEMap('map');
    mapVE.SetClientToken(document.getElementById("hVEToken").value);
    mapVE.AttachEvent('ontokenexpire', OnVETokenExpire);
    mapVE.AttachEvent('ontokenerror', OnVETokenError);   
    try 
    { 
        var options = new VEMapOptions();
        options.EnableBirdseye = false; //Not allowed for government use
        mapVE.LoadMap(center, zoom, VEMapStyle.Road, false, VEMapMode.Mode2D, true, 0, options) 
    } 
    catch (e) 
    { 
        logError('Error loading map in browser [' + navigator.appName + ', ' + navigator.userAgent + ']: ' + e.message); 
        alert("There was an error loading the Virtual Earth map - some application features may not function properly in your browser.");
    }
    this.currentZoom = mapVE.GetZoomLevel();
    this.imgLayer = new Image();
    this.imgLayer.src = 'images/btn_layer' + (this.IE?'IE':'FF') + '.gif';
    this.imgLayerOver = new Image();
    this.imgLayerOver.src = 'images/btn_layer_over' + (this.IE?'IE':'FF') + '.gif';
    this.imgLayerClick = new Image();
    this.imgLayerClick.src = 'images/btn_layer_click' + (this.IE?'IE':'FF') + '.gif';
    this.tileServer = tileServer;
    this.parcelPinLayer = new VEShapeLayer();
    mapVE.AddShapeLayer(this.parcelPinLayer);
    
    var divMapLayerButton = document.getElementById('divMapLayerButton');
    if (divMapLayerButton) {
      divMapLayerButton.style.height = this.IE?26:28;
      divMapLayerButton.style.left = (88 + (this.IE?0:2)) + 'px';
      if (this.IE) {
        divMapLayerButton.innerHTML = "<a href='#'><img src='images/btn_layerIE.gif' width='76' height='26' border='0' onmouseover='this.src=Map.imgLayerOver.src' onmouseout='this.src=Map.imgLayer.src' onmousedown='return Map.onLayerButtonClicked(this);'></a>";
      } else {
        divMapLayerButton.innerHTML = "<a href='#'><img src='images/btn_layerFF.gif' width='76' height='28' border='0' onmouseover='this.src=Map.imgLayerOver.src' onmouseout='this.src=Map.imgLayer.src' onmousedown='return Map.onLayerButtonClicked(this);'></a>";
      }
      divMapLayerButton.style.display = 'block';
    
      var divMapLayerContainer = document.getElementById('divMapLayerContainer');
      if (divMapLayerContainer) {
        divMapLayerContainer.style.top = (divMapLayerButton.offsetTop + divMapLayerButton.offsetHeight - 1) + 'px';
        divMapLayerContainer.style.left = divMapLayerButton.offsetLeft + 'px';
      }
      divMapLayerContainer.style.display = 'none';
    }
    
    var chkParcels = document.getElementById('chkParcels');
    if (chkParcels) chkParcels.checked = false;
    var chkZoning = document.getElementById('chkZoning');
    if (chkZoning) chkZoning.checked = false;
    
    this.searchCriteria = null;
    this.resetQueryData = null;
    this.gridUpdateInProcess = null;
    this.isQuerying = false;
    this.retryCount = 0;
    this.showVisibleOnly = true;

    mapVE.AttachEvent("onendpan", function(e) { Map.redraw(true); });
    mapVE.AttachEvent("onendzoom", function(e) { Map.redraw(false); });
    mapVE.AttachEvent("oninitmode", function() { Map.initMode(); });
    mapVE.AttachEvent("onmouseup", function(e) { if (e.rightMouseButton) Map.onContextMenu(e); });
    mapVE.AttachEvent("onmodenotavailable", function() { UI.messageBox(200,200,450,"Not Available","We are sorry, that feature is not available on this browser.", "<img src='images/icn_info.gif' width='16' height='16'>", 10000); });
    
    var MSVE_obliqueNotification = document.getElementById('MSVE_obliqueNotification');
    if (MSVE_obliqueNotification) MSVE_obliqueNotification.style.visibility = 'hidden';
    var MSVE_threeDNotification = document.getElementById('MSVE_threeDNotification');
    if (MSVE_threeDNotification) MSVE_threeDNotification.style.visibility = 'hidden';
  },
  initMode : function() {
    if (mapVE.GetMapMode() == VEMapMode.Mode3D) {
    } else {
    }
  },
  addTileLayer : function(layerName, tileServerName)
  {
    try
    {
      if (mapVE) {
        mapVE.AddTileLayer(getTileSourceSpec(layerName, tileServerName), true);
      }
    }
    catch (e)
    {
      alert('Error communicating with tile server.\nMessage:' + e.message);
      logError('Error communicating with tile server ' + tileSource + ' in function addTileLayer. ' + e.message);
    }
  },
  deleteTileLayer : function(id)
  {
    try
    {
      if (mapVE)
        mapVE.DeleteTileLayer(id);
    }
    catch (e)
    {
      alert('Error communicating with tile server.\nMessage:' + e.message);
      logError('Error communicating with tile server ' + tileSource + ' in function deleteTileLayer. ' + e.message);
    }
  },
  addShim : function(id) {
    if (this.IE) {
      var el = document.getElementById(id);
      if (el) {
        var shim = document.createElement("iframe");
        shim.id = id + 'Shim';
        shim.frameBorder = "0";
        shim.style.position = "absolute";
        shim.style.zIndex = "1";
        shim.style.top = el.offsetTop;
        shim.style.left = el.offsetLeft;
        shim.width = el.offsetWidth;
        shim.height = el.offsetHeight;  
        el.shimElement = shim;
        el.parentNode.insertBefore(shim, el);
      }
    }
  },
  removeShim : function(id) {
    var shim = document.getElementById(id + 'Shim');
    if (shim) 
      shim.parentNode.removeChild(shim);
    shim = null;
  },
  dispose : function() {
    this.imgLayer = null;
    this.imgLayerOver = null;
    this.imgLayerClick = null;
    this.searchCriteria = null;
    mapVE = null;
  },
  onLayerItemClicked : function(chkbox) {
    if (Map.layerItemClickedTimerID > -1)
      clearTimeout(Map.layerItemClickedTimerID);
    var layerName = chkbox.value;
    switch (chkbox.checked) {
      case true :
        SelectedLayersInfo.push(new LayerInfo(layerName, chkbox.text));
        this.addTileLayer(layerName, Map.tileServer);
        break;
      default :
        for (var i=SelectedLayersInfo.length-1; i>=0; i--)
        {
            if (SelectedLayersInfo[i].LayerKey == layerName) 
                SelectedLayersInfo.splice(i,1);
        }
        this.deleteTileLayer(layerName);
        break;
    }
    Map.layerItemClickedTimerID = setTimeout("Map.onLayerContainerTimeout()", 5000);
  },
  onLayerContainerTimeout : function() {
    this.displayLayerContainer(false);
    Map.layerItemClickedTimerID = -1;
  },
  onLayerButtonClicked : function(btn) {
    btn.src=Map.imgLayerClick.src;
    return this.displayLayerContainer(true);
  },
  displayLayerContainer : function(visible) {
    if (this.IE) {
      var shim = document.getElementById("divMapLayerContainerShim");
      if (shim) {
        shim.style.display = visible?'block':'none';
        shim.style.top = divMapLayerContainer.offsetTop;
        shim.style.left = divMapLayerContainer.offsetLeft;
        shim.width = divMapLayerContainer.offsetWidth;
        shim.height = divMapLayerContainer.offsetHeight;  
      }
    }
    return true;
  },
  clearPushPins : function() {
    __mapVEPinCount = 0;
    mapVE.DeleteAllPushpins();
  },
  panToLatLong : function(objVELatLong) {
    mapVE.PanToLatLong(objVELatLong);
    Map.redraw(true);
  },
  initializeForQuery : function(showResultGrid) {
    if (showResultGrid && !Layout.isResultsVisible) 
      Layout.toggleView(document.getElementById('resizePaneVert'));
    this.clearPushPins();
    var mapStyle = mapVE.GetMapStyle();
    if (mapStyle == VEMapStyle.Birdseye)
      mapVE.SetMapStyle(VEMapStyle.Hybrid);
  },
  redraw : function(forceQuery) {
    this.displayLayerContainer(false);
    if (this.searchCriteria && this.searchCriteria.isValid)
    {
      if (__mapVEPinCount > MAX_PINS_BEFORE_RELOAD)
        SearchWhat.submit();
      else 
        this.query(this.searchCriteria, false);
    }
  },
  hideAllGrids : function() {
    ConstructionActivity.hide();
  },
  query : function(searchCriteria, resetQueryData) {
    // if search criteria has been passed to us, use it
    if (searchCriteria && searchCriteria.isValid)
      this.searchCriteria = searchCriteria;

    if (this.searchCriteria && this.searchCriteria.isValid)
    {
      if (!Map.isQuerying)
      {
        if (resetQueryData)
          Map.resetQueryData = resetQueryData;
        else
          Map.resetQueryData = false;
          
        if (Map.resetQueryData)
          Layout.hasQueryDataBeenResetFlag = true;
      
        var mapStyle = mapVE.GetMapStyle();
        if (mapStyle != VEMapStyle.Birdseye && mapStyle != VEMapStyle.BirdseyeHybrid)
        {
          UI.showBusy('Querying...');
          if (Layout.isResultsVisible) 
            SearchWhat.hideAllResultDataGrids();
          this.currentZoom = mapVE.GetZoomLevel();
          
          var mapBounds = mapVE.GetMapView();
          var mapCenter = mapVE.GetCenter();
          
          var lon0 = mapBounds.TopLeftLatLong.Longitude;
          var lat0 = mapBounds.TopLeftLatLong.Latitude;
          var lon2 = mapCenter.Longitude - (lon0 - mapCenter.Longitude); //  mapBounds.BottomRightLatLong.Longitude;
          var lat2 = mapCenter.Latitude - (lat0 - mapCenter.Latitude); // mapBounds.BottomRightLatLong.Latitude;
          
          var lon1 = mapBounds.TopRightLatLong?mapBounds.TopRightLatLong.Longitude:lon2;
          var lat1 = mapBounds.TopRightLatLong?mapBounds.TopRightLatLong.Latitude:lat0;
          var lon3 = mapBounds.BottomLeftLatLong?mapBounds.BottomLeftLatLong.Longitude:lon0;
          var lat3 = mapBounds.BottomLeftLatLong?mapBounds.BottomLeftLatLong.Latitude:lat2;
          
          Map.isQuerying = true;
          Map.showPerformQueryFirstMessage(false);
          
          switch (this.searchCriteria.searchMode) {
            case "0" : // Construction
              SearchWhat.showConstructionActivityDataGrid();
              ActivityLocator.MapService.GetConstructionActivity(
                lon0, lat0, lon1, lat1, lon2, lat2, lon3, lat3,
                searchCriteria.singleFamilyDuplex, searchCriteria.multiFamily, searchCriteria.commercialFixedOther,
                searchCriteria.activityType,
                searchCriteria.permitStatus,
                searchCriteria.startDate, searchCriteria.endDate, Map.resetQueryData, 
                Map.queryCompleteCallback, Map.queryErrorCallback);
              break;
            case "1" : // Land Use
              SearchWhat.showLandUseActivityDataGrid();
              ActivityLocator.MapService.GetLandUseActivity(
                lon0, lat0, lon1, lat1, lon2, lat2, lon3, lat3,
                searchCriteria.conditionalUse, searchCriteria.designReview, searchCriteria.councilAction, searchCriteria.plat,
                searchCriteria.sepa, searchCriteria.shoreline, searchCriteria.variance, searchCriteria.other,
                searchCriteria.permitStatus,
                searchCriteria.startDate, searchCriteria.endDate, Map.resetQueryData,
                Map.queryCompleteCallback, Map.queryErrorCallback);
              break;
            case "2" : // Land Use Notices
              SearchWhat.showLandUseNoticeDataGrid();
              ActivityLocator.MapService.GetLandUseNoticeActivity(
                lon0, lat0, lon1, lat1, lon2, lat2, lon3, lat3,
                searchCriteria.noticeOfApplication, searchCriteria.noticeOfDecisions, searchCriteria.appealHearingNotices, searchCriteria.otherLandUseNotices,
                searchCriteria.startDate, searchCriteria.endDate, Map.resetQueryData,
                Map.queryCompleteCallback, Map.queryErrorCallback);
              break;
            case "3" : // Demolition
              SearchWhat.showDemolitionDataGrid();
              ActivityLocator.MapService.GetDemolitionActivity(
                lon0, lat0, lon1, lat1, lon2, lat2, lon3, lat3,
                searchCriteria.permitStatus,
                searchCriteria.startDate, searchCriteria.endDate, Map.resetQueryData,
                Map.queryCompleteCallback, Map.queryErrorCallback);
              break;
            case "4" : // Billboard
              SearchWhat.showBillboardDataGrid();
              ActivityLocator.MapService.GetBillboardActivity(
                lon0, lat0, lon1, lat1, lon2, lat2, lon3, lat3,
                searchCriteria.singleFacePole, searchCriteria.doubleFacePole, searchCriteria.paintedWall, 
                searchCriteria.vInstallation, searchCriteria.other, Map.resetQueryData,
                Map.queryCompleteCallback, Map.queryErrorCallback);
              break;
            default :
              alert('Unknown activity requested (value:' + this.searchMode + ')');
          }
        }
      }
      else
      {
        if (Layout.isResultsVisible && Layout.hasQueryDataBeenResetFlag) {
          Map.retryCount++;
          if (Map.retryCount < 100)
            setTimeout("Map.populateGrid()", 500);
          else
            alert('Retry count exceed 50 seconds.');
        }
      }
    }
  },
  queryCompleteCallback : function(obj, xml, txt)
  {
    Map.isQuerying = false;
    Map.retryCount = 0;
    UI.showBusy('Rendering...');
    __obj = obj;
    if (Layout.isResultsVisible && (Layout.hasQueryDataBeenResetFlag || Map.showVisibleOnly)) 
      Map.populateGrid();
    Map.resetQueryData = false;
    setTimeout("Map.render()", 10);
  },
  populateGrid : function()
  {
    if (!Map.gridUpdateInProcess) // skip if we are in the process of updating the grid
    {
      if (!Map.isQuerying) // skip if we are still querying the database
      {
        if (Map.searchCriteria)
        {
          Layout.hasQueryDataBeenResetFlag = false;
          Map.gridUpdateInProcess = true;
          switch (Map.searchCriteria.searchMode) 
          {
            case "0" : // Construction
              updateConstructionActivityGrid();
              break;
            case "1" : // Land Use
              updateLandUseActivityGrid();
              break;
            case "2" : // Land Use Notices
              updateLandUseNoticeActivityGrid();
              break;
            case "3" : // Demolition
              updateDemolitionActivityGrid();
              break;
            case "4" : // Billboards
              updateBillboardActivityGrid();
              break;
          }
        }
      }
      else
      {
        if (Layout.isResultsVisible && Layout.hasQueryDataBeenResetFlag) 
          setTimeout("Map.populateGrid()", 500);
      }
    }
  },
  render : function()
  {
    var obj = __obj;
    try 
    {
      if (obj && obj.tables && obj.tables.length > 0) {
        var table = obj.tables[0];
        if (!table.rows) 
        {
            UI.hideBusy();
            return; //Nothing to do
        }
        
        var title = new Array();
        var pinImg = new Array();
        var text = new Array();
               
        for (var i=0;i<table.rows.length;i++)
        {
          var row = table.rows[i];
          var loc = new VELatLong(row['LAT'], row['LON']);
          var pinID = row["ID"];
          var nativeNumber = row["APN"];
          var activityDate = (new Date(row["DAT"])).format('ddd MMM dd, yyyy');
          var displayAddr = row["ADR"].replace(/,/g, ' ');
           
          pinImg.push('images/pin');
          switch (String(row["TYP"]))
          {
            case "0" : // Construction
              title.push("<span class='po'>Permit #: <a href='http://web1.seattle.gov/DPD/permitstatus/Project.aspx?id=");
              title.push(nativeNumber);
              title.push("' target='_blank' title='View activity details'>");
              title.push(nativeNumber);
              title.push("</a></span>");
              text.push("<span class='po'><ul><li><a href='http://web1.seattle.gov/DPD/permitStatus/default.aspx?a=");
              text.push(row["ADR"]);
              text.push("' target='_blank' title='View activity at address'>");
              text.push(displayAddr);
              text.push("</a></li><li>");
              switch (String(row["ACT"]))
              {
                case "NEW" :
                  text.push("New");
                  break;
                case "ADD/ALT" :
                  text.push("Addition/Alteration");
                  break;
                case "TEMP" :
                  text.push("Temporary");
                  break;
                case "NONE" :
                  text.push("No construction");
                  break;
              }
              
              text.push("</li><li>");
              switch (String(row["DPT"]))
              {
                case "SF/D" :
                  pinImg.push("0");
                  text.push("Single Family/Duplex");
                  break;
                case "MF" :
                  pinImg.push("1");
                  text.push("Multi-Family");
                  break;
                default :
                  pinImg.push("2");
                  text.push("Commercial/Mixed/Other");
                  break;
              }
              text.push("</li><li>");
              switch (String(row["STT"]))
              {
                case "O" :
                  text.push("Open");
                  break;
                case "C" : 
                  text.push("Closed");
                  break;
                case "S" : 
                  text.push("Stop Work");
                  break;
              }
              text.push(": ");
              text.push(row["STD"]);
              text.push("</li><li>");
              switch (String(row["STA"]))
              {
                case "0" :
                  text.push("Applied for ");
                  text.push(activityDate);
                  break;
                case "1" :
                  text.push("Issued on ");
                  text.push(activityDate);
                  break;
                case "2" :
                  text.push("Finaled on ");
                  text.push(activityDate);
                  break;
              }
              text.push("</li></ul></span>");
              break;
            case "1" : // Land Use
              title.push("<span class='po'>Permit #: <a href='http://web1.seattle.gov/DPD/permitstatus/Project.aspx?id=");
              title.push(nativeNumber);
              title.push("' target='_blank' title='View activity details'>");
              title.push(nativeNumber);
              title.push("</a></span>");
              text.push("<span class='po'><ul><li><a href='http://web1.seattle.gov/DPD/permitStatus/default.aspx?a=");
              text.push(row["ADR"]);
              text.push("' target='_blank' title='View activity at address'>");
              text.push(displayAddr);
              text.push("</a></li><li>");
              switch (String(row["CMP"]))
              {
                case "COND USE" :
                  pinImg.push("0");
                  text.push("Conditional Use");
                  break;
                case "DESIGN ADM" :
                case "DESIGN RVW" :
                  pinImg.push("1");
                  text.push("Design");
                  break;
                case "COUNCIL" :
                  pinImg.push("2");
                  text.push("Council Action");
                  break;
                case "PLAT LBA" :
                case "PLAT SHORT" :
                case "PLAT SUB" :
                  pinImg.push("3");
                  text.push("Plat");
                  break;
                case "SEPA" :
                  pinImg.push("4");
                  text.push("Sepa");
                  break;
                case "SHORE CU" :
                case "SHORE DEV" :
                case "SHORE VAR" :
                   pinImg.push("5");
                   text.push("Shoreline");
                   break;
                case "VARIANCE" :
                   pinImg.push("6");
                   text.push("Variance");
                   break;
                case "OTHER" :
                   pinImg.push("7");
                   text.push("Other");
                   break;
              }
              text.push("</li><li>");
              switch (String(row["STT"]))
              {
                case "O" :
                  text.push("Open");
                  break;
                case "C" : 
                  text.push("Closed");
                  break;
                case "S" : 
                  text.push("Stop Work");
                  break;
              }
              text.push(": ");
              text.push(row["STD"]);
              text.push("</li><li>");
              switch (String(row["STA"]))
              {
                case "0" :
                  text.push("Applied for ");
                  text.push(activityDate);
                  break;
                case "1" :
                  text.push("Issued on ");
                  text.push(activityDate);
                  break;
                case "2" :
                  text.push("Finaled on ");
                  text.push(activityDate);
                  break;
              }
              text.push("</li></ul></span>");
              break;
            case "2" : // Land Use Notice (LUIB)
              title.push("<span class='po'>Project #: <a href='http://web1.seattle.gov/DPD/permitstatus/Project.aspx?id=");
              title.push(nativeNumber);
              title.push("' target='_blank' title='View activity details'>");
              title.push(nativeNumber);
              title.push("</a></span>");
              text.push("<span class='po'><ul><li>");
              switch (String(row["NTP"]))
              {
                case "1" :
                case "2" :
                  pinImg.push("0");
                  break;
                case "3" :
                  pinImg.push("1");
                  break;
                case "4" :
                  pinImg.push("2");
                  break;
                case "5" :
                  pinImg.push("3");
                  break;
              }
              text.push("<a href='http://web1.seattle.gov/dpd/luib/Notice.aspx?id=");
              text.push(pinID);
              text.push("' target='_blank' title='View Notice Details'>");
              text.push(row["DES"]);
              text.push("</a></li><li>Bulletin ");
              text.push(activityDate);
              text.push("</li><li>Located in ");
              text.push(row["REA"]);
              text.push("</li><li>");
              text.push(row["ZNE"]);
              text.push(" zone</li></ul></span>");
              break;
            case "3" : // Demolition
              title.push("<span class='po'>Permit #: <a href='http://web1.seattle.gov/DPD/permitstatus/Project.aspx?id=");
              title.push(nativeNumber);
              title.push("' target='_blank' title='View activity details'>");
              title.push(nativeNumber);
              title.push("</a></span>");
              text.push("<span class='po'><ul><li><a href='http://web1.seattle.gov/DPD/permitStatus/default.aspx?a=");
              text.push(row["ADR"]);
              text.push("' target='_blank' title='View activity at address'>");
              text.push(displayAddr);
              text.push("</a></li><li>");
              pinImg.push("0");
              switch (String(row["STA"]))
              {
                case "0" :
                  text.push("Applied for ");
                  text.push(activityDate);
                  break;
                case "1" :
                  text.push("Issued on ");
                  text.push(activityDate);
                  break;
                case "2" :
                  text.push("Finaled on ");
                  text.push(activityDate);
                  break;
              }
              text.push("</li><li>");
              switch (String(row["STT"]))
              {
                case "O" :
                  text.push("Open");
                  break;
                case "C" : 
                  text.push("Closed");
                  break;
                case "S" : 
                  text.push("Stop Work");
                  break;
              }
              text.push(": ");
              text.push(row["STD"]);
              text.push("</li></ul></span>");
              break;
            case "4" : // Billboard
              title.push("<span class='po'><a href='http://web1.seattle.gov/DPD/BillboardViewer/detail.aspx?id=");
              title.push(pinID);
              title.push("' target='_blank' title='View billboard details'>");
              title.push(displayAddr);
              title.push("</a></span>");
              text.push("<span class='po'><ul><li>Owned by ");
              text.push(row["OWN"]);
              text.push("</li><li>");
              switch (String(row["SIG"]))
              {
                case "1" :
                case "12" :
                  text.push("Single Face Pole");
                  pinImg.push("0");
                  break;
                case "10" :
                  text.push("Double Face Pole");
                  pinImg.push("1");
                  break;
                case "3" :
                case "4" :
                case "6" :
                case "13" :
                  text.push("Painted Wall");
                  pinImg.push("2");
                  break;
                case "14" :
                case "15" :
                  text.push("V Installation");
                  pinImg.push("3");
                  break;
                default :
                  text.push("Other (");
                  text.push(row["SYP"]);
                  text.push(")");
                  pinImg.push("4");
                  break;
              }
              text.push("</li><li>Installed ");
              text.push(activityDate);
              text.push("</li><li>Size ");
              text.push(row["SIZ"]);
              text.push(" sq. ft.</li></ul></span>");
              break;
            case "5" : // Historical
              break;
          }
          pinImg.push(".gif");
          var pin = new VEPushpin(pinID, loc, pinImg.join(""), title.join(""), text.join(""));
          mapVE.AddPushpin(pin);
          pinImg.length = 0;
          title.length = 0;
          text.length = 0;
          __mapVEPinCount++;
        }
      }
      else
        alert('There was a problem querying the database. The details of the issue have been recorded into a log and will be reviewed.\nWe are sorry for the inconvience.');
    } catch (e) {
      var txt = e.message;
      switch (e.name)
      {
        case "err_invalidpushpinid" :
          SearchWhat.submit();
          break;
        default :
          txt += "\nPress OK to retry or cancel to continue";
          if (confirm(txt))
            SearchWhat.submit();  
      }
    }
    UI.hideBusy();
  },
  queryErrorCallback : function(error)
  {
    Map.retryCount = 0;
    var err = error.get_exceptionType() + '\r\n' + error.get_message();
    alert(err);
    UI.hideBusy();
    logError(err + "\r\n" + error.get_stackTrace());
  },
  locate : function (location)
  {
    mapVE.Find('', location, null, null, 0, 1, true, true, false, true, Map.locateCallback);
  },
  locateCallback : function()
  {
    Map.redraw(true);
  },
  onContextMenu : function(e) {
    Map.parcelPinLayer.DeleteAllShapes();
    var ll = null;
    if (e.mapX)
      ll = mapVE.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
    else
      ll = e.latLong;

    if (null != ll.Latitude && null != ll.Longitude)
    {
      UI.showBusy('Fetching...');
      ActivityLocator.MapService.GetParcelData(ll.Latitude, ll.Longitude,
            Map.contextMenuCallback, Map.contextMenuErrorCallback);
    }
  },
  contextMenuCallback : function(obj) {
    UI.hideBusy();
    mapVE.DeleteAllPolylines();
    try 
	{
      if (obj && obj.tables.length > 1) {
        var title = new Array();
        var text = new Array();
        var dtState = obj.tables[0];
        var dtStateRow = dtState.rows[0];
        
          var dtAdr = obj.tables[1];
          var dtInfoRow = obj.tables[2].rows[0];
          var dtPoints = obj.tables[3];
          
          title.push('Parcel #: ');
          title.push(dtInfoRow["PID"]);
          
          text.push("<table width='100%' cellpadding='3' cellspacing='0' border='0'>");
          text.push("<tr><td colspan='2' class='pinParcelTextHeader'>Addresses in Parcel</td></tr>");
          if (dtAdr.rows)
          {
              for (var i=0;i<dtAdr.rows.length;i++) {
                text.push("<tr><td colspan='2' class='po'><a href='");
                text.push(dtAdr.rows[i]["URL"]);
                text.push("' target='_blank' title='Click to view permits and complaints'>");
                text.push(dtAdr.rows[i]["ADRD"]);
                text.push("</a></td></tr>");
              }
          }
          
          text.push("<tr><td colspan='2' class='pinParcelTextHeader'>Zoning</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>Base Zone:</td><td title=''>");
          text.push(dtInfoRow["ZONE"]);
          text.push("</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>Shoreline Zone:</td><td title=''>");
          text.push(dtInfoRow["SHORELINE"]);
          text.push("</td></tr>");
          text.push("<tr><td colspan='2' class='pinParcelTextHeader'>ECA</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>40% Steep Slope:</td><td>");
          text.push(dtInfoRow["STEEPSLOPE"]);
          text.push("</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>Floodprone:</td><td>");
          text.push(dtInfoRow["FLOODPRONE"]);
          text.push("</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>Potential Slide:</td><td>");
          text.push(dtInfoRow["PSLIDE"]);
          text.push("</td></tr>");
          text.push("<tr><td class='pinParcelLabel'>Wetlands:</td><td>");
          text.push(dtInfoRow["WETLAND"]);
          text.push("</td></tr></table>");
          text.push("</br><span class='po'><a href='");
          text.push(dtInfoRow["URL"]);
          text.push("' target='_blank' title='Click to view parcel data sheet'>More...</a></span>");

          var pin = new VEShape(VEShapeType.Pushpin, [new VELatLong(dtStateRow['LAT'], dtStateRow['LON'])]);
          pin.SetTitle(title.join(""));
          pin.SetDescription(text.join(""));
          pin.SetCustomIcon('images/pinParcel.gif');
          Map.parcelPinLayer.AddShape(pin);
          
          if (dtPoints.rows)
          {
              var polyPoints = new Array();
              for (var i=0;i<dtPoints.rows.length;i++)
                polyPoints.push(new VELatLong(dtPoints.rows[i]["LAT"], dtPoints.rows[i]["LON"]));
              var poly = new VEPolyline(dtInfoRow["PID"], polyPoints, new VEColor(0, 250, 150, 1.0), 2);
              mapVE.AddPolyline(poly);
          }
        }
        else
          alert('No parcel found at that location.');
      }
	  catch(e)
	  {
	    alert('There was a problem rendering the result. The details of the issue have been recorded into a log and will be reviewed by technical support. We are sorry for the inconvenience.');
  	  logError('Problem occurred in Map.contextMenuCallback. ' + e.message);
	  } 
  },
  contextMenuErrorCallback : function(error) { 
    var err = error.get_exceptionType() + '\r\n' + error.get_message();
    alert(err);
    logError(err);
    UI.hideBusy();
  },
  showPerformQueryFirstMessage : function(show) {
    var divPerformQueryMessage = document.getElementById('divPerformQueryMessage');
    if (divPerformQueryMessage) divPerformQueryMessage.style.display = show?'block':'none';
  }
  
};


