// Author: Thomas Høi - it-arkitekterne.dk

/*
 * resizeMap resizes the element used to hold the google map.
 * Parameters:
 *    mapElement - The element holding the google map.
 *    usedWidth - Number of pixel used for left and right bar elements.
 *    usedHeight - Number of pixels used for header and footer elements
 */
function resizeMap(mapElement, usedWidth, usedHeight, sideBarElement) {
   var width = 0, height = 0;
   if (typeof(window.innerWidth) == 'number') {
      //Non-IE
      width = window.innerWidth;
      height = window.innerHeight;
   } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
      //IE 6+ in 'standards compliant mode'
      width = document.documentElement.clientWidth;
      height = document.documentElement.clientHeight;
   } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
      //IE 4 compatible
      width = document.body.clientWidth;
      height = document.body.clientHeight;
   }

   var sidebarWidth = sideBarElement.clientWidth > 0 ? sideBarElement.clientWidth + 0 : usedWidth;

   //mapElement.style.width = (width - (sidebarWidth + 16)) + "px"; // 2 margin a 5px body, margin 2 x 2px
   mapElement.style.height = (height - (usedHeight + 10)) + "px";
}

function debugMapViewPort(map) {
   //noinspection JSUnresolvedFunction
   var latLngBounds = map.getBounds();
   //noinspection JSUnresolvedFunction
   alert("sw=" + latLngBounds.getSouthWest() + " ne=" + latLngBounds.getNorthEast() + " zoom=" + map.getZoom());
}

// Should we debug? 
var debugMap = false;

// Maps marker ID to Marker for the selected markers.
var selectedMarkerMap = {};

// Administrator? - gives an edit marker in info window.
var administrator;

// The base URL for the portal must be se by clients.
var tpUrlBase = null;

// -------------------------------------------------------------------------------------------
function ItaAnchorManager(url) {
   if (url != null) {
      this.checkboxElements = [];
      for (var i = 1; i < ItaAnchorManager.arguments.length; i++) {
         this.checkboxElements.push(ItaAnchorManager.arguments[i]);
      }
      if (url.length > 0) {
         // Parse the anchor.
         var urlParts = url.split("#");
         // ...#lat=123;lng=qwe;zoom=qwe;....
         if (urlParts.length > 1) {
            var valueMap = {};
            var tupples = urlParts[1].split(";");
            for (var i = 0; i < tupples.length; i++) {
               var pair = tupples[i].split("=");
               valueMap[pair[0]] = pair.length > 1 ? pair[1] : null;
            }

            // Control zoom
            if (valueMap["lat"] && valueMap["lng"] && valueMap["zoom"]) {
               var center = new GLatLng(Number(valueMap["lat"]), Number(valueMap["lng"]));
               manager.map.setCenter(center, Number(valueMap["zoom"]));
            }
            
            for (var i = 0; i < this.checkboxElements.length; i++) {
               var element = this.checkboxElements[i];
               element.checked = valueMap[element.id];
            }

            // Refresh filters
            manager.refreshFilters();
         }
      }
   }
}

ItaAnchorManager.prototype = new ItaAnchorManager();

ItaAnchorManager.prototype.onchange = function() {
   var center = manager.map.getCenter();
   var zoom = manager.map.getZoom();
   var anchor = "lat=" + center.lat() + ";lng=" + center.lng() + ";zoom=" + zoom;
   for (var i = 0; i < this.checkboxElements.length; i++) {
      var element = this.checkboxElements[i];
      if (element.checked) {
         anchor += ";" + element.id + "=true";
      }
   }

   var base = location.href.split("#")[0];
   location.href = base + "#" + anchor;
}


var anchorManager = null;
// new anchorManager(window.location.href); // TODO [tho]: Wait until every thing boot strapped
// -------------------------------------------------------------------------------------------
// ItaFilter filters the different institutions
function ItaHelpInfo(infoElement) {
   if (infoElement != null) {
      this.infoElement = infoElement;
      var helpInfo = this;
      // Make sure the object is in scope for anonymous use.
      var map = manager.map;
      // Listen to zoom changes
      //noinspection JSUnresolvedFunction,JSUnresolvedVariable

      GEvent.addListener(map, "zoomend", function(oldLevel, newLevel) {
         helpInfo.update(newLevel);
      });
   }
}

ItaHelpInfo.prototype = new ItaHelpInfo();

ItaHelpInfo.prototype.update = function(zoom) {
   //noinspection JSUnresolvedFunction
   zoom = zoom ? zoom : manager.map.getZoom();

   var html = "";
   if (zoom >= 12) {
      html = "Få vist en eller flere typer af leverandører ved at markere ovenstående tilbudstyper. Klik på den ønskede leverandør, for at få vist detaljer.";
   } else {
      html = "Klik på kortet for at forstørre det. Der vises kun institutioner på detaljeret visning.";
   }
   this.infoElement.innerHTML = html;
}


// -------------------------------------------------------------------------------------------
// ItaFilter filters the different institutions
function ItaFilter(typeManager, nursingHomeElement, ambulantElement, dayOfferYouthElement, dayOfferAdultElement, dayAndNightOfferYouthElement, dayAndNightOfferAdultElement) {
   if (typeManager != null) {
      this.typeManager = typeManager;
      this.nursingHomeElement = nursingHomeElement;
      this.ambulantElement = ambulantElement;
      this.dayOfferYouthElement = dayOfferYouthElement;
      this.dayOfferAdultElement = dayOfferAdultElement;
      this.dayAndNightOfferYouthElement = dayAndNightOfferYouthElement;
      this.dayAndNightOfferAdultElement = dayAndNightOfferAdultElement;
      this.updateState();
      this.typeManager.filter = this;
   }
}

ItaFilter.prototype = new ItaFilter();

// updateState reads the filter state from the form.
ItaFilter.prototype.updateState = function(marker) {
   if (debugMap) { //noinspection JSUnresolvedVariable
      GLog.write("ItaFilter.prototype.updateState(): ");
   }
   this.nursingHome = this.nursingHomeElement.checked;
   this.ambulant = this.ambulantElement.checked;
   this.dayOfferYouth = this.dayOfferYouthElement.checked;
   this.dayOfferAdult = this.dayOfferAdultElement.checked;
   this.dayAndNightOfferYouth = this.dayAndNightOfferYouthElement.checked;
   this.dayAndNightOfferAdult = this.dayAndNightOfferAdultElement.checked;

   if (anchorManager) {
      // write the change to the url.
      anchorManager.onchange();
   }
}


// isVisible - Is the marker visible according to filter?
ItaFilter.prototype.isVisible = function(marker) {
   return (this.nursingHome && marker.nursingHome)
           || (this.ambulant && marker.ambulant)
           || (this.dayOfferYouth && marker.dayOfferYouth)
           || (this.dayOfferAdult && marker.dayOfferAdult)
           || (this.dayAndNightOfferYouth && marker.dayAndNightOfferYouth)
           || (this.dayAndNightOfferAdult && marker.dayAndNightOfferAdult);
}

ItaFilter.prototype.refresh = function() {
   if (debugMap) { //noinspection JSUnresolvedVariable
      GLog.write("ItaFilter.prototype.refresh");
   }
   this.updateState()
   this.typeManager.updateAll();
}

// -------------------------------------------------------------------------------------------
// The manager is a singleton
var manager = null;

// ItaMarkerManager is responsible for handling different types of markers and the zoom handling.
// Its supports dynamic loading of the marker soruces.
function ItaMarkerManager(googleMap) {
   if (googleMap) {
      this.map = googleMap;

      var onMapChangeHandler = function() {
         manager.onMapChange();
      }
      //noinspection JSUnresolvedFunction,JSUnresolvedVariable
      GEvent.addListener(this.map, "zoomend", onMapChangeHandler);

      //noinspection JSUnresolvedFunction,JSUnresolvedVariable
      GEvent.addListener(this.map, "moveend", onMapChangeHandler);


      //noinspection JSUnresolvedFunction,JSUnresolvedVariable
      GEvent.addListener(this.map, "click", function(overlay, point) {
         var map = manager.map;
         //noinspection JSUnresolvedFunction
         if (map.getZoom() < 12) {
            //noinspection JSUnresolvedFunction
            map.setCenter(point, 12);
         }
      });

      //noinspection JSUnresolvedFunction
      this.typeManagers = [];
      manager = this;
   }
}

ItaMarkerManager.prototype = new ItaMarkerManager();

/*
 * Adds a new Type manager.
 */
ItaMarkerManager.prototype.add = function(typeid, minZoom, maxZoom, url, iconUrl, name) {
   var typeManager = new ItaTypeManager(typeid, minZoom, maxZoom, url, iconUrl, name);
   this.typeManagers.push(typeManager);
   return typeManager;
}

// displays the type.
// display - used to show/hide
// typeid - specify what type to show hide
// filter - specify a subset of marker
ItaMarkerManager.prototype.display = function(typeid, display) {
   var typeManager = this.getTypeManager(typeid);
   if (typeManager) {
      if (display) {
         typeManager.show();
      } else {
         typeManager.hide();
      }
   }
}

ItaMarkerManager.prototype.onMapChange = function() {
   //noinspection JSUnresolvedFunction
   var latLngBounds = manager.map.getBounds();
   var startTime = new Date().getTime();
   for (var i = 0; i < this.typeManagers.length; i++) {
      var typeManager = this.typeManagers[i];
      typeManager.updateAll();
   }
   var endTime = new Date().getTime();
   if (anchorManager) {
      anchorManager.onchange();
   }
}

ItaMarkerManager.prototype.getTypeManager = function(typeid) {
   for (var i = 0; i < this.typeManagers.length; i++) {
      var typeManager = this.typeManagers[i];
      if (typeManager.typeid == typeid) {
         return typeManager
      }
   }
   return null;
}

ItaMarkerManager.prototype.refreshFilters = function() {
   for (var i = 0; i < this.typeManagers.length; i++) {
      if (this.typeManagers[i].filter) {
         this.typeManagers[i].filter.refresh();
      }
   }
}

// -----------------------------------------------------------------------------------------------------
// Manages a single type x zoomInterval).
function ItaTypeManager(typeid, minZoom, maxZoom, url, iconUrl, name) {
   if (typeid != null) {
      this.typeid = typeid;
      this.minZoom = minZoom;
      this.maxZoom = maxZoom;
      this.url = url;
      this.iconUrl = iconUrl;
      this.name = name;
      this.markers = [];
      this.loaded = false;
      this.visible = false;
      this.filter = null;
      //noinspection JSUnresolvedFunction
      var markerIcon = new GIcon();
      markerIcon.image = this.iconUrl;
      //noinspection JSUnresolvedFunction
      markerIcon.iconSize = new GSize(20, 34)
      //noinspection JSUnresolvedFunction
      markerIcon.iconAnchor = new GPoint(10, 34);
      //noinspection JSUnresolvedFunction
      markerIcon.infoWindowAnchor = new GPoint(10, 1);

      this.gMarkerOptions = { draggable: false, icon: markerIcon, title: name };
   }
}

ItaTypeManager.prototype = new ItaTypeManager();

// Shows
ItaTypeManager.prototype.show = function() {
   this.visible = true;
   if (! this.loaded) {
      this.load();
   } else {
      this.updateAll();
   }
}

ItaTypeManager.prototype.hide = function() {
   this.visible = false;
   for (var i = 0; i < this.markers.length; i++) {
      var marker = this.markers[i];
      if (marker.visible) {
         marker.hide();
      }
   }
}

ItaTypeManager.prototype.createMarker = function(id, name, latitude, longitude, nursingHome, ambulant, dayOfferYouth, dayOfferAdult, dayAndNightOfferYouth, dayAndNightOfferAdult) {
   var marker = new ItaMarker(this, id, name, latitude, longitude, nursingHome, ambulant, dayOfferYouth, dayOfferAdult, dayAndNightOfferYouth, dayAndNightOfferAdult);
   this.markers.push(marker);
   return marker;
}

// insideZoomLimits: true if insize limits; otherwise false.
ItaTypeManager.prototype.insideZoomLimits = function() {
   //noinspection JSUnresolvedFunction
   var zoom = manager.map.getZoom();
   return zoom >= this.minZoom && zoom <= this.maxZoom;
}

// Method to add all all GMarkers to the GMarker manager.
ItaTypeManager.prototype.updateAll = function() {
   if (debugMap) { //noinspection JSUnresolvedVariable
      GLog.write("ItaTypeManager.prototype.updateAll");
   }

   //noinspection JSUnresolvedFunction
   var latLngBounds = manager.map.getBounds();
   var inZoom = this.insideZoomLimits();

   var before = new Date().getTime();
   for (var i = 0; i < this.markers.length; i++) {
      var marker = this.markers[i];

      var inFilter = this.filter ? this.filter.isVisible(marker) : true;
      marker.update(inZoom, latLngBounds, inFilter)
   }
   var after = new Date().getTime();
   //noinspection JSUnresolvedFunction
   //manager.gmarkerManager.addMarkers(gmarkers, 12);
}

ItaTypeManager.prototype.load = function() {

   //noinspection JSUnresolvedVariable,JSUnresolvedFunction
   var request = GXmlHttp.create();
   request.open("GET", this.url, true);
   request.onreadystatechange = function() {
      if (request.readyState == 4) {

         var xmlDoc = request.responseXML;
         try {
            var typeid = Number(xmlDoc.documentElement.getAttribute("typeid"));
            var typeManager = manager.getTypeManager(typeid);

            var markers = xmlDoc.getElementsByTagName("marker");
            for (var i = 0; i < markers.length; i++) {
               var element = markers[i];
               var id = element.getAttribute("id");
               if (selectedMarkerMap[id]) {
                  if (debugMap) { //noinspection JSUnresolvedVariable
                     GLog.write("skipping marker with " + id + " selected ");
                  }
                  continue;
               }
               var name = element.getAttribute("name");
               var lat = Number(element.getAttribute("latitude"));
               var lng = Number(element.getAttribute("longitude"));
               var nursingHome = "true" == element.getAttribute("nursinghome");
               var ambulant = "true" == element.getAttribute("ambulant");
               var dayOfferYouth = "true" == element.getAttribute("dayofferYouth");
               var dayOfferAdult = "true" == element.getAttribute("dayofferAdult");
               var dayAndNightOfferYouth = "true" == element.getAttribute("dayAndNightOfferYouth");
               var dayAndNightOfferAdult = "true" == element.getAttribute("dayAndNightOfferAdult");

               var marker = typeManager.createMarker(id, name, lat, lng, nursingHome, ambulant, dayOfferYouth, dayOfferAdult, dayAndNightOfferYouth, dayAndNightOfferAdult);
            }

            typeManager.updateAll();
         } catch (e) {
            alert(e);
         }
      }
   }
   request.send(null);
   this.loaded = true;
}

// -----------------------------------------------------------------------------------------------------
function ItaMarker(typeManager, id, name, latitude, longitude, nursingHome, ambulant, dayOfferYouth, dayOfferAdult, dayAndNightOfferYouth, dayAndNightOfferAdult) {
   if (latitude && longitude) {
      this.typeManager = typeManager;
      this.id = id;
      this.name = name;

      //noinspection JSUnresolvedFunction
      this.latLng = new GLatLng(latitude, longitude);
      this.latitude = latitude;
      this.longitude = longitude;
      this.nursingHome = nursingHome;
      this.ambulant = ambulant;
      this.dayOfferYouth = dayOfferYouth;
      this.dayOfferAdult = dayOfferAdult;
      this.dayAndNightOfferYouth = dayAndNightOfferYouth;
      this.dayAndNightOfferAdult = dayAndNightOfferAdult;
      this.visible = false;
      // Visible if marker is on the map; Otherwise false.
   }
}

// The default icon for selected.
//noinspection JSUnresolvedFunction
var itaSelectedIcon = new GIcon();
itaSelectedIcon.image = "/kortservice/icons/selectedmarker.png";
//noinspection JSUnresolvedFunction
itaSelectedIcon.iconSize = new GSize(20, 34)
//noinspection JSUnresolvedFunction
itaSelectedIcon.iconAnchor = new GPoint(10, 34);
//noinspection JSUnresolvedFunction
itaSelectedIcon.infoWindowAnchor = new GPoint(10, 1);

var itaDefaultMarkerOption = { draggable: false, icon: itaSelectedIcon, title: "Valgt leverandør" };
ItaMarker.prototype = new ItaMarker();

// Method to create the GMarker.
ItaMarker.prototype.createGMarker = function() {
   var specificOption = { draggable: false };
   if (this.typeManager) {
      specificOption.icon = this.typeManager.gMarkerOptions.icon;
      specificOption.title = this.typeManager.typeid == 1 ? this.name : this.typeManager.name + " - " + this.name;
   } else {
      specificOption.icon = itaDefaultMarkerOption.icon;
      specificOption.title = this.name;
   }
   //noinspection JSUnresolvedFunction
   //noinspection JSUnresolvedFunction
   this.gmarker = new GMarker(this.latLng, specificOption);
   this.gmarker.itaMarker = this;
   var itaMarker = this;
   //noinspection JSUnresolvedVariable,JSUnresolvedFunction
   GEvent.addListener(this.gmarker, "click", function() {
      itaMarker.openInfoWindowHtml();
   });

   return this.gmarker;
}

// Shows marker
ItaMarker.prototype.show = function() {
   if (this.gmarker == null) {
      this.createGMarker();
   }
   //noinspection JSUnresolvedFunction
   manager.map.addOverlay(this.gmarker);
   this.visible = true;
}

// Hides marker
ItaMarker.prototype.hide = function() {
   //noinspection JSUnresolvedFunction
   manager.map.removeOverlay(this.gmarker);
   this.visible = false;
}


ItaMarker.prototype.inside = function(latLngBounds) {
   return latLngBounds.contains(this.latLng);
}

ItaMarker.prototype.update = function(inZoom, latLngBounds, inFilter) {
   if (this.typeManager.visible) {
      if (inZoom && inFilter && this.inside(latLngBounds)) {
         if (! this.visible) {
            this.show();
         }
      } else {
         if (this.visible) {
            this.hide();
         }
      }
      // If the manager is visisble

   } else {
      if (this.visible) {
         this.hide();
      }
   }
}

ItaMarker.prototype.openInfoWindowHtml = function() {
   var itaMarker = this;
   var url = "/kortservice/rest/markerdetail?markerid=" + this.id;
   //noinspection JSUnresolvedVariable,JSUnresolvedFunction
   var request = GXmlHttp.create();
   request.open("GET", url, true);
   request.onreadystatechange = function() {
      if (request.readyState == 4) {
         var xmlDoc = request.responseXML;
         var element = xmlDoc.documentElement;
         var name = element.getAttribute("name");
         var pnr = element.getAttribute("pnr");
         var typeid = Number(element.getAttribute("typeid"));
         var road = element.getAttribute("road");
         var number = element.getAttribute("number");
         var zipcode = element.getAttribute("zipcode");
         var city = element.getAttribute("city");
         var telephone = element.getAttribute("telephone");
         var email = element.getAttribute("email");
         var homepage = element.getAttribute("homepage");
         var urlForThis = "kort.jsp?pnr=" + pnr;
         var tpUrlForThis = tpUrlBase + "?pnr=" + pnr;
         var content = element.getAttribute("details");
         var cvrImported = "true" == element.getAttribute("cvrImported");

         var html = "<div class='infowindow'><h3>" + name + "</h3>" +
                    "<p>" + road + " " + number +
                    "<br />" + zipcode + " " + city + "</p>" +
                    "<p>" +
                    (telephone ? "Telefon: " + telephone + "<br />" : "") +
                    (email ? "<a href='mailto:" + email + "'>" + email + "</a><br />" : "") +
                    (homepage ? "<a href='" + homepage + "' target='_blank'>Leverandørens hjemmeside</a><br />" : "") +
                    "</p>";
         if (typeid == 1) { // Institution
            var rejsePlanUrl = "http://www.rejseplanen.dk/bin/query.exe/mn?ZADR=1&timesel=arrive&Z=" + road + "+" + number + "%2C+" + zipcode + "+" + city;
            html += "<p>";
            html += "<b>Tilbudstype</b>:<br />";
            var m = "";
            m += (itaMarker.ambulant ? (m.length ==0 ? "": ", ") + "Ambulant" : "");
            m += (itaMarker.dayAndNightOfferYouth ? (m.length ==0 ? "": ", ") + "Døgntilbud til børn og unge" : "");
            m += (itaMarker.dayAndNightOfferAdult ? (m.length ==0 ? "": ", ") + "Døgntilbud til voksne" : "");
            m += (itaMarker.dayOfferYouth ? (m.length ==0 ? "": ", ") + "Dagtilbud til børn og unge" : "");
            m += (itaMarker.dayOfferAdult ?  (m.length ==0 ? "": ", ") + "Dagtilbud til voksne" : "");
            m += (itaMarker.nursingHome ? (m.length ==0 ? "": ", ") + "Plejehjem/Plejebolig" : "");
            html += m + "<br /><br />";

             html +=
                    (content != null ? content + "<br/>" : "") +
                    (cvrImported ? "Tilbuddet er endnu ikke indberettet, du kan derfor ikke læse mere om tilbuddet.<br />Det vil være indberettet senest 1. oktober.<br /><br />" : "<a href='" + tpUrlForThis + "')'>Læs mere her</a><br />") +
                    "<a href='" + urlForThis + "'>Vis kun denne</a>" +
                    "&nbsp;<a target='_blank' href='" + rejsePlanUrl + "'>Rejseplanen</a>" + 
                    "</p>"
         }
         if (administrator) {
            html += "<p><a href='admin/markeradmin.jsp?pnr=" + pnr + "'>Rediger placering</a></p>";
         }
         html += "</div>";

         if (isInfowindowSupportedByBrowser()) {
            itaMarker.gmarker.openInfoWindowHtml(html);
         } else {
            // Large infowindow does not work well in versions below 7.
            html = "<div class='infowindow'><h3>" + name + "</h3>" +
                   road + " " + number +
                   "<br />" + zipcode + " " + city +
                   "<br /><a href='detaljer.jsp?pnr=" + pnr + "' target='_blank'>Detaljer</a>";
            itaMarker.gmarker.openInfoWindowHtml(html);
         }

      }
   }
   request.send(null);
}

function isInfowindowSupportedByBrowser() {
   if (navigator.appName.indexOf("Microsoft") >= 0) {
      if (navigator.appVersion.indexOf("MSIE 7") >= 0) {
         return true;
      } else {
         return false;
      }
   } else {
      return true;
   }
}


// -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
