﻿
Type.registerNamespace("CK");

CK.VEMap = function(service, mapArgs, county_bounds, searchId) {
   /// <summary>
   ///   The VE Map.
   ///   Supports load on demand
   /// </summary>
   /// <param name="service">The webservice to call for the map data.</param>
   /// <param name="mapArgs">The map initalisation data.</param>

   this._service = service;
   this._mapArgs = mapArgs;
   this._county_bounds = county_bounds;
   this._searchId = searchId;

   this._progressDiv = null;

   this._map = null;
   this._pinID = 0;
   this._zoomlevel = 0;
   this._layer = null;
   this._findlayer = null;

   //popup specific
   this._PopupPrefix = "POPUP";
   this._currentpin = null;
   this._currentindex = 0;

   //Birdseye - fix due to not lat/long data available
   this._MapBEyeCentre;
   this._latoffset = 0.005;
   this._lonoffset = 0.01;

   this._lastfindresults = null;

   this.GetPinDataDelegate = null;
   this.PinHoverDelegate = null;

   this._max_zoom = 0;
   this._max_zoom_msg = 'Sorry, Map Layer not available at this close of a zoom level.';

   this._init();
}

CK.VEMap.prototype = {

   _init: function() {
      /// <summary>
      ///   Initialises the Map.
      /// </summary>       

      //setup map
      this._map = new VEMap(this._mapArgs.DivID);
      this._map.SetDashboardSize(this._mapArgs.Dashsize);
      this._map.LoadMap(this._mapArgs.Center, this._mapArgs.Zoomlevel, this._mapArgs.Style, this._mapArgs.Fixed, this._mapArgs.Mode);

      this._progressDiv = $get(this._mapArgs.ProgressDivID);
      this._layer = new VEShapeLayer();
      this._layer.SetTitle("MainLayer");
      this._map.AddShapeLayer(this._layer);
      this._findlayer = new VEShapeLayer();
      this._map.AddShapeLayer(this._findlayer);

      //setup the function to get new data whenever the map changes
      this.GetPinDataDelegate = Function.createDelegate(this, this._GetPinData);
      this._map.AttachEvent("onchangeview", this.GetPinDataDelegate);

      //turn off the standard popup and attach our custom handler
      this.PinHoverDelegate = Function.createDelegate(this, this._PinActivate);
      this._map.AttachEvent("onmouseover", this.PinHoverDelegate);
      this._map.AttachEvent("onclick", this.PinHoverDelegate);

      //Setup additional storage for shapes
      VEShape.prototype.Bounds = "";
      VEShape.prototype.Drawn = false;
      VEShape.prototype.Match = false;

      //get the data for the default view
      this._GetPinData();
   },

   ResetZoomAndCenter: function() {
      this._map.SetCenterAndZoom(new VELatLong(start_lat, start_lon), map_scale);
   },

   _GetPinData: function() {
      /// <summary>
      ///   Get the latest map data from the webservice.
      /// </summary>

      //encode the current map bounds
      var points = new Array();
      var zoom;

      if (this._map.GetMapStyle() == VEMapStyle.Birdseye) {
         //set zoomlevel      
         zoom = 19;
         points.push(new VELatLong(this._MapBEyeCentre.Latitude + this._latoffset, this._MapBEyeCentre.Longitude - this._lonoffset));
         points.push(new VELatLong(this._MapBEyeCentre.Latitude - this._latoffset, this._MapBEyeCentre.Longitude + this._lonoffset));
      } else {
         var view = this._map.GetMapView();
         points.push(view.TopLeftLatLong);
         points.push(view.BottomRightLatLong);

         //get zoomlevel
         zoom = this._map.GetZoomLevel();

         if (zoom != this._mapArgs.Zoomlevel) {
            $get("zoomtip").style.display = 'none';
         }

         //to try to support Birsdeye we store the centre as currently there is no way to get the lat/long in birdseye :(
         this._MapBEyeCentre = this._map.GetCenter();

      }
      var bounds = Utility.createEncodings(points);
      if (this._zoomlevel != zoom) {
         //clear existing pins
         this._layer.DeleteAllShapes();
         this._zoomlevel = zoom;
         //show progress bar
         this.showProgress();
      }

      if (this._max_zoom != 0) {
         if (zoom > this._max_zoom) {
            this.LegendMessage(this._max_zoom_msg);
         } else {
            this.LegendMessage(null);
         }
      }

      //call webservice and show progress bar
      this._service.GetClusteredMapData(bounds, zoom, this._county_bounds, this._searchId, Function.createDelegate(this, this._OnMapDataSucceeded), Utility.OnFailed);

   },

   _OnMapDataSucceeded: function(results) {
      /// <summary>
      ///   Receive data for map.
      /// </summary>  
      /// <param name="result">The webservice result object - Optomised CSV string</param>  

      //decode pins
      var result = results.split(",");
      var locs = Utility.decodeLine(result[0]);
      var linx = "";
      var linxCount = 0;
      var shpId;


      //hide progress bar
      this.endProgress();

      //k starts at 1 which contains encoded bounds and descriptions
      var k = 1;
      var shapes = new Array();

      //add new pins
      for (x = 0; x < locs.length; x++) {
         var loc = locs[x];

         var bounds = result[k];

         //decode property string
         var propertyString = Utility.decodeBase64(result[k + 1]);

         k += 2;

         var drawn = false;


         //see if it is in the current drawn pins
         for (i = 0; i < totalpins; i++) {
            var currentshape = this._layer.GetShapeByIndex(i);
            if (currentshape.Bounds == bounds) {
               drawn = true;
               currentshape.Match = true;
               shpId = currentshape.GetID();
               break; //shortcut loop
            }
         }

         if (!drawn) {
            var newShape = new VEShape(VEShapeType.Pushpin, loc);

            newShape.Bounds = bounds;
            newShape.Drawn = drawn;
            newShape.Match = true;
            //set custom pin. 
            //[IDEA FOR YOU TO EXPLORE]
            //If you were to pass the quantity or the type of pin in the csv string you could have different pins here!         
            newShape.SetCustomIcon("<img src='images/propertymarker.gif'/>");
            //newShape.IconUrl = "dot.gif" 

            this._layer.AddShape(newShape);

            shpId = newShape.GetID();

         }

         //need ID to synch with External List
         if (linxCount < 10) {
            var strings = propertyString.split(";;");
            //the string begins with a sortable string to get 
            //them in the right order to match clustered pins
            string = strings.sort();
            var listLink = "";

            for (j = 0; j < strings.length; j++) {

               var pieces = strings[j].split(",");


               listLink += '<li><a href=\"#map\" ';
               listLink += 'onclick=\"map.LinkOpenInfoWindow(\'';
               listLink += shpId + '\',' + j;
               listLink += ');\">' + pieces[1] + '</a><br />' + pieces[2] + ', ' + state_abbr + '</li>';

               linxCount++;
               if (linxCount == 10) break;
            }
            linx += listLink;

         }


      }
      //add properties to side links
      $get('sideresults').innerHTML = linx;

      //add Legend and hide until needed
      this.AddLegend();

      //remove all existing pins on matches from the screen
      var totalpins = this._layer.GetShapeCount();
      for (x = (totalpins - 1); x >= 0; x--) {
         var currentshape = this._layer.GetShapeByIndex(x);
         if (!currentshape.Match) {
            this._layer.DeleteShape(currentshape);
         }
         //set match back to false for next time we pan the map.
         currentshape.Match = false;
      }



   },

   _PinActivate: function(e) {
      /// <summary>
      ///   Receives any mouse of event from VE
      /// </summary>  
      /// <param name="e">The MapEvent object</param>  

      if (e.elementID) {

         var popupShape = this._map.GetShapeByID(e.elementID);

         if (popupShape.GetShapeLayer() == wrap_bound_layer) {
            return true;
         }

         if (popupShape) {
            var lyr = popupShape.GetShapeLayer();
            var lyrname = lyr.GetTitle();
            if (lyrname == "MainLayer") {
               //set current pin
               this._currentpin = popupShape;
               this._currentindex = 0;

               //get the content for the pin.
               this._getAJAXContent();
               this._currentpin.SetDescription("<div id='" + this._PopupPrefix + this._currentpin.GetID() + "'>Loading...<br /><br /><br /><br /></div>");
               this._currentpin.SetTitle("");

            } else {
               this._map.ShowInfoBox(popupShape);
            }

         }
         // (cba): force infobox open on click
         if (e.eventName == "onclick") { this._map.ShowInfoBox(popupShape) }
      }
   },


   ZoomCurrentPin: function() {
      /// <summary>
      ///   Zoom to current pushpin.
      /// </summary>  
      if (this._zoomlevel * 1 < 12) {
         var pts = this._currentpin.GetPoints();
         if (pts) {
            var pt = pts[0];
            this._map.SetCenterAndZoom(pt, 12);
         }
      } else {
         this._map.SetCenterAndZoom(new VELatLong(start_lat, start_lon), map_scale);
      }
   },

   _getAJAXContent: function() {
      /// <summary>
      ///   Request content for popup.
      /// </summary>  

      //call the web service
      this._service.GetPushPin(this._currentpin.Bounds, this._currentindex, this._county_bounds, this._searchId, Function.createDelegate(this, this._OnContentSucceeded), Utility.OnFailed, this._currentpin.GetID());
   },

   _OnContentSucceeded: function(result, ID) {
      /// <summary>
      ///   Receive content for popup.
      /// </summary>  
      /// <param name="result">The webservice result object - JSON PinData</param>  
      /// <param name="ID">The popup ID associated with this call</param>  

      //verify this is the data for the current popup.
      if (ID == this._currentpin.GetID()) {

         if (this._map.GetMapMode() == VEMapMode.Mode3D) {
            //3D mode fails to be able to retrieve the div we placed earlier so resort to setting the title and description only
            this._currentpin.SetTitle(result.Title);
            this._currentpin.SetDescription(result.Details);
         } else {
            //create the content element
            var el = document.createElement("div");
            var rec_nums = ""
            if (result.TotalRecords > 1) {
               rec_nums = (this._currentindex + 1) + " of " + result.TotalRecords + " Records <br />"
            }
            //build hyperlink
            var objectType = "";
            var link = "";

            var imgsrc;

            if (result.map_photo || !result.has_auth_photo) {
               imgsrc = '<div id="div_map_photo" style="position: relative; width: 300px; height: 220px;"></div>';
            }
            else {
               imgsrc = "<img style=\"margin:8px;\" src=\"ShowDBImg.aspx";
            }

            var zoomLink = "<a href=\"javascript:map.ZoomCurrentPin()\">"
            if (this._zoomlevel * 1 < 12) { zoomLink += "Zoom In" } else { zoomLink += "Full zoom out" }
            zoomLink += "</a>"

            if (result.PropertyTypeId == 'b') {
               objectType = "Building";
               link += "buildings_display.aspx?buildingsid=" + result.pId;
               if (!result.map_photo && result.has_auth_photo) {
                  imgsrc += "?proptype=building&fity=110&propid=" + result.pId + "\" />";
               }
               el.innerHTML = rec_nums + "<br /><strong>" + result.Title + "</strong><br />" + result.Details + "<br /><p>" + imgsrc + "</p><p style=\"font-size:0.9em;\"><a target=_blank href=\"" + link + "\">Details...</a> | " + zoomLink + "</p>";
            }
            if (result.PropertyTypeId == 's') {
               objectType = "Site";
               link += "sites_display.aspx?sitesid=" + result.pId;
               if (!result.map_photo && result.has_auth_photo) {
                  imgsrc += "?proptype=site&fity=110&propid=" + result.pId + "\" />";
               }
               el.innerHTML = rec_nums + "<br /><strong>" + result.Title + "</strong><br />" + result.Details + "<br /><p>" + imgsrc + "</p><p style=\"font-size:0.9em;\"><a target=_blank href=\"" + link + "\">Details...</a> | " + zoomLink + "</p>";
            }

            //clear loading and attach the content
            $get(this._PopupPrefix + ID).innerHTML = "";
            $get(this._PopupPrefix + ID).appendChild(el);


            if (result.TotalRecords > 1) {
               //prev / next functionlaity
               var prevButton = document.createElement("div");
               prevButton.innerHTML = "Previous";
               el.appendChild(prevButton);
               Sys.UI.DomElement.addCssClass(prevButton, "ActionButton");
               if (this._currentindex > 0) {
                  $addHandler(prevButton, "click", Function.createDelegate(this, this._PreviousRecord));
               } else {
                  Sys.UI.DomElement.addCssClass(prevButton, "ButtonDisabled");
               }
               var nextButton = document.createElement("div");
               nextButton.innerHTML = "Next";
               el.appendChild(nextButton);
               Sys.UI.DomElement.addCssClass(nextButton, "ActionButton");
               if (this._currentindex < (result.TotalRecords - 1)) {
                  $addHandler(nextButton, "click", Function.createDelegate(this, this._NextRecord));
               } else {
                  Sys.UI.DomElement.addCssClass(nextButton, "ButtonDisabled");
               }
            }

            if (result.map_photo || !result.has_auth_photo) {
               loadPhotoMap(result);
               $('.ero .ero-body').css('width', '324px');
            }
            else {
               $('.ero .ero-body').css('width', '200px');
            }
            
         }
      }
   },

   _PreviousRecord: function() {
      /// <summary>
      ///   Request the previous record.
      /// </summary>  
      this._currentindex--;
      $get(this._PopupPrefix + this._currentpin.GetID()).innerHTML = "Loading...";
      this._getAJAXContent();
   },

   _NextRecord: function() {
      /// <summary>
      ///   Request the next record.
      /// </summary>      
      this._currentindex++;
      $get(this._PopupPrefix + this._currentpin.GetID()).innerHTML = "Loading...";
      this._getAJAXContent();
   },

   LinkOpenInfoWindow: function(shpId, indexId) {


      this._map.HideInfoBox();

      var popupShape = this._map.GetShapeByID(shpId);


      if (popupShape) {
         //set current pin

         this._currentpin = popupShape;
         this._currentindex = indexId;

         //get the content for the pin.
         this._getAJAXContent();
         this._currentpin.SetDescription("<div id='" + this._PopupPrefix + this._currentpin.GetID() + "'>Loading...</div>");
         this._currentpin.SetTitle("");
         this._map.ShowInfoBox(popupShape);

      }

   },

   showProgress: function() {
      // get the update progress div
      var pnlPopup = this._progressDiv;

      //  get the map element        
      var mapdiv = $get(this._mapArgs.DivID);

      // make it visible
      pnlPopup.style.display = '';

      // get the bounds of both the map and the progress div
      var viewBounds = Sys.UI.DomElement.getBounds(mapdiv);
      var pnlPopupBounds = Sys.UI.DomElement.getBounds(pnlPopup);

      //  center of map
      var x = viewBounds.x + Math.round(viewBounds.width / 2) - Math.round(pnlPopupBounds.width / 2);
      var y = viewBounds.y + Math.round(viewBounds.height / 2) - Math.round(pnlPopupBounds.height / 2);

      //	set the progress element to this position
      Sys.UI.DomElement.setLocation(pnlPopup, x, y);
   },

   endProgress: function() {
      // get the update progress div
      var pnlPopup = this._progressDiv;
      // make it invisible
      pnlPopup.style.display = 'none';
   },

   FindNearby: function(what) {
      this._findlayer.DeleteAllShapes();
      var numberOfWordsInSearch = what.split(' ').length;
      var firstWordOfFindString = getWord(what, 1);
      var where = '';
      // If the first word is numeric and there are more than one word in the string, assume it is an address
      if (IsNumeric(firstWordOfFindString) && numberOfWordsInSearch > 1) {
         where = what;
         this._map.Find('address', where, null, this._findlayer, null, 20, true, true, true, true, this._OnFindAddressSuccess);
      }
      else {
         this._map.Find(what, null, null, this._findlayer, null, 20, true, true, true, false, this._OnFindSuccess);
      }
   },

   AddCustomLayer: function(what) {
      this._findlayer.DeleteAllShapes();
      var view = this._map.GetMapView();
      var topleft = view.TopLeftLatLong;
      var bottomright = view.BottomRightLatLong;
      var where = topleft.Latitude + ',' + topleft.Longitude + ',' + bottomright.Latitude + ',' + bottomright.Longitude;
      //$get("debug").innerHTML = where;
      var veLayerSpec;
      if (what == 'rail') {
         veLayerSpec = new VEShapeSourceSpecification(VEDataType.ImportXML, 'http://projects.c-ka.com/maps/kml/larail.kmz', this._findlayer);
         this._map.ImportShapeLayerData(veLayerSpec, this._OnFindSuccessNoIcon, false);

      } else {
         veLayerSpec = new VEShapeSourceSpecification(VEDataType.GeoRSS, 'ReturnGeoRSS.aspx?id=' + what + '&bounds=' + where, this._findlayer);
         this._map.ImportShapeLayerData(veLayerSpec, this._OnFindSuccess, false);
      }


   },

   AddCustomTiles: function(tilefolder, opac) {
      // only available at zoom levels 7 thru 13

      //var bounds = [new VELatLongRectangle(new VELatLong(32,-92),new VELatLong(28,-89))];
      var tileSourceSpec = new VETileSourceSpecification("custom", tilefolder);
      tileSourceSpec.NumServers = 1;
      //tileSourceSpec.Bounds = bounds;
      tileSourceSpec.MinZoomLevel = 7;
      tileSourceSpec.MaxZoomLevel = 13;
      tileSourceSpec.Opacity = opac;
      tileSourceSpec.ZIndex = 100;
      try {
         this._map.AddTileLayer(tileSourceSpec, true);
         if (this._map.GetZoomLevel() > 13) { this._map.SetZoomLevel(13) }
         if (this._map.GetZoomLevel() < 7) { this._map.SetZoomLevel(7) }
      } catch (e) {
         alert(e.message + '!');
      }
      $get("lyrmsg-tiles").innerHTML = 'Layer loaded.&nbsp;&nbsp;[<a href=\"#map\" onclick=\"DeleteTiles();return false;\">clear</a>]';
   },

   _OnFindSuccess: function(layer, resultsArray, places, hasMore, veErrorMessage) {
      _lastfindresults = resultsArray;
      if (layer) {
         var count = layer.GetShapeCount();

         if (count == 1) {
            //check to see if record is a fake, indicating empty dataset
            var chkshp = layer.GetShapeByIndex(0);
            var desc = chkshp.GetDescription();
            if (desc == 'IsEmpty') { count = 0; }
         }
         $get("lyrmsg-points").innerHTML = count + ' nearby results shown.&nbsp;&nbsp;[<a href=\"#map\" onclick=\"offAllButtons();map.DeleteFindResults();return false;\">clear</a>]';
         var shp;
         for (var i = 0; i < count; i++) {
            shp = layer.GetShapeByIndex(i);
            shp.SetCustomIcon("<img src='images/propertymarker2.gif'/>");
         }
      }
   },

   _OnFindAddressSuccess: function(layer, resultsArray, places, hasMore, veErrorMessage) {
      if (layer) {
         if (places.length > 0) {
            var location = places[0].LatLong;
            var desc = "Latitude: " + location.Latitude + "<br>Longitude:" + location.Longitude; ;
            var title = places[0].Name;

            var newShape = new VEShape(VEShapeType.Pushpin, location);
            newShape.Match = true;
            newShape.SetDescription(desc);
            newShape.SetTitle(title);
            newShape.SetCustomIcon("<img src='images/propertymarker2.gif'/>");
            layer.AddShape(newShape);
            var newShapeId = newShape.GetID();

            $get("lyrmsg-points").innerHTML = ' Found address.&nbsp;&nbsp;[<a href=\"#map\" onclick=\"offAllButtons();map.DeleteFindResults();return false;\">clear</a>]';
         }
         else
            $get("lyrmsg-points").innerHTML = ' Address not found.&nbsp;&nbsp;[<a href=\"#map\" onclick=\"offAllButtons();map.DeleteFindResults();return false;\">clear</a>]';

      }
   },
   _OnFindSuccessNoIcon: function(layer, resultsArray, places, hasMore, veErrorMessage) {
      if (layer) {
         var count = layer.GetShapeCount();
         $get("lyrmsg-points").innerHTML = 'Data found and loaded (' + count + ')';
         //$get("debug").innerHTML = count+' nearby results shown.&nbsp;&nbsp;[<a href=\"#\" onclick=\"map.DeleteFindResults();return false;\">clear</a>]';
         var shp;
         for (var i = 0; i < count; i++) {
            shp = layer.GetShapeByIndex(i);
            shp.HideIcon();

         }
         this._map.EnableShapeDisplayThreshold(false);
      }
   },


   DeleteFindResults: function() {
      $get("lyrmsg-points").innerHTML = "&nbsp;";
      if (this._findlayer) {
         this._findlayer.DeleteAllShapes();
      }

   },

   DeleteTiles: function() {
      $get("lyrmsg-tiles").innerHTML = "&nbsp;";
      this.HideLegend();
      try { this._map.DeleteTileLayer("custom") } catch (e) { }
   },

   AddLegend: function() {
      var el = document.createElement("div");
      el.id = "myLegend";
      el.style.top = "5px";
      el.style.left = "395px";
      el.style.width = "132px";
      el.style.height = "200px";
      el.style.border = "1px solid black";
      el.style.background = "White";
      el.innerHTML = el.id;
      this._map.AddControl(el);
      this.addShim(el);
      this._map.HideControl(el);
   },

   ShowLegend: function() {
      var leg = $get("myLegend");
      this._map.ShowControl(leg);
   },

   HideLegend: function() {
      var leg = $get("myLegend");
      this._map.HideControl(leg);
   },

   LegendMessage: function(str_msg) {
      var leg = $get('myLegend');
      if (!str_msg) {
         leg.style.height = '200px';
         if (document.getElementById('leg_msg'))
            leg.removeChild(document.getElementById('leg_msg'));
      }
      else {
         leg.style.height = '';
         var div_msg = document.createElement('div');
         div_msg.id = 'leg_msg';
         div_msg.innerHTML = str_msg;
         div_msg.style.backgroundColor = '#FF9B9B';
         div_msg.style.borderColor = '#FF1A1A';
         div_msg.style.borderStyle = 'solid';
         div_msg.style.borderWidth = '2px';
         div_msg.style.color = '#000000';
         div_msg.style.fontWeight = 'bold';
         div_msg.style.margin = '8px 2px 2px 2px';

         leg.appendChild(div_msg);
      }
   },

   addShim: function(el) {
      var shim = document.createElement("iframe");
      shim.id = "myShim";
      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);
   },

   Dispose: function() {
      /// <summary>
      ///   cleans up all objects. Detaches all events.
      /// </summary>
      if (this._map != null) {
         this._map.DetachEvent("onchangeview", this.GetPinDataDelegate);
         this._map.DetachEvent("onmouseover", this.PinHoverDelegate);
         this._map.DetachEvent("onclick", this.PinHoverDelegate);
         this._map.Dispose();
      }
      this._service = null;
      this._mapArgs = null;
      this._lastfindresults = null;

      this._map = null;
      this._pinID = null;
      this._zoomlevel = null;
      this._layer = null;

      //popup specific
      this._PopupPrefix = null;
      this._currentpin = null;
      this._currentindex = null;

      //Birdseye
      this._MapBEyeCentre = null;
      this._latoffset = null;
      this._lonoffset = null;

      this.GetPinDataDelegate = null;
      this.PinHoverDelegate = null;
   }
}

CK.VEMap.registerClass('CK.VEMap', null, Sys.IDisposable);

if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

// Calvin (High Power) - This function will extract the first word of a sentence
function getWord(str, pos) {
    var SplitString = str.split(" ");
    return SplitString[parseInt(pos) - 1];
}

// Calvin (High Power) - This function will determine if a word or string is all numeric
function IsNumeric(sText) {
    var ValidChars = "0123456789";
    var IsNumber = true;
    var Char;

    for (i = 0; i < sText.length && IsNumber == true; i++) {
        Char = sText.charAt(i);
        if (ValidChars.indexOf(Char) == -1) {
            IsNumber = false;
        }
    }
    return IsNumber;

}

