﻿map_editor = function (map_el, bReadOnly, bCluster, bHideMarkerDesc, background_url, warning_el) {
      this.initialZoomSpecified = false;
      this.map_el = map_el;
      this.bReadOnly = bReadOnly;
      this.bHideMarkerDesc = bHideMarkerDesc;
      if (!bReadOnly && !bCluster) {
            this.warning_el = warning_el;
      }
      this.bCluster = bCluster;
      this.background_url = background_url;
      this.nPopup = 0;
      this.markerCluster = null;
      this.addedMarkers = [];
      this.bounds = new google.maps.LatLngBounds();
      this.map = this.buildmap();
      this.infowindow = new google.maps.InfoWindow();

      // suppress any overflows on the infowindow
      google.maps.event.addListener(this.infowindow, 'domready', function () {
            document.getElementById('info-content').parentNode.style.overflow = '';
            document.getElementById('info-content').parentNode.parentNode.style.overflow = '';
      });

      this.geocoder = new google.maps.Geocoder();
      this.geocoderBounds = this.map.getBounds();
      //this.blueMarker = new google.maps.MarkerImage('http://future.swirlingworld.com/Content/markers/bluemarker.png');

      if (this.map !== null) {

            if (this.bCluster) {
                  this.markerCluster = new Fluster2(this.map, false);
                  // These are the same styles as default, assignment is only for demonstration ...
                  this.markerCluster.styles = {
                        // This style will be used for clusters with more than 0 markers
                        0: {
                              image: 'http://future.swirlingworld.com/Content/markers/m1.png',
                              textColor: '#FFFFFF',
                              width: 53,
                              height: 52
                        },

                        // This style will be used for clusters with more than 10 markers
                        10: {
                              image: 'http://future.swirlingworld.com/Content/markers/m2.png',
                              textColor: '#FFFFFF',
                              width: 56,
                              height: 55
                        },
                        20: {
                              image: 'http://future.swirlingworld.com/Content/markers/m3.png',
                              textColor: '#FFFFFF',
                              width: 66,
                              height: 65
                        }
                  };
            }

            this.loadBackground();
      }
};

map_editor.prototype.dispose = function () {
      //GUnload();     
      clearInstanceListeners(this.infoWindow);
      clearInstanceListeners(this.map);
};

map_editor.prototype.buildmap = function () {

      //if (GBrowserIsCompatible()) {

      var options = {
            zoom: 4,
            center: new google.maps.LatLng(-42, 172),
            mapTypeId: google.maps.MapTypeId.HYBRID
      }

      if (this.bReadOnly) {
            options = {
                  zoom: 4,
                  center: new google.maps.LatLng(-42, 172),
                  mapTypeId: google.maps.MapTypeId.HYBRID,
                  mapTypeControl: true,
                  mapTypeControlOptions: { style: google.maps.MapTypeControlStyle.DROPDOWN_MENU }
            }
      }

      var gmap = new google.maps.Map(this.map_el, options);

      var self = this;
      google.maps.event.addListener(gmap, 'zoom_changed', function () { self.handleZoomChanged(); });

      if (this.warning_el) {
            google.maps.event.addListener(gmap, 'bounds_changed', function () { self.handleBoundsChanged(); });
      }

      return gmap;

      //    } else {
      //        alert('Sorry. Your browser is not Google Maps compatible.');
      //        return null;
      //    }

};

map_editor.prototype.handleBoundsChanged = function () {

      var b = this.map.getBounds();
      for (var m in this.addedMarkers) {
            if (!b.contains(this.addedMarkers[m].getPosition())) {
                  this.warning_el.show();
                  return;
            }
      }
      this.warning_el.hide();
};

map_editor.prototype.handleZoomChanged = function () {
      if (this.map.getZoom() > 17) { this.map.setZoom(17); }
};

map_editor.prototype.find = function (address) {
      var self = this;

      this.geocoder.geocode({ address: address, language: 'en', region: 'nz', bounds: this.geocoderBounds }, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                  self.map.panTo(results[0].geometry.location);
                  self.map.fitBounds(results[0].geometry.viewport);
                  //self.map.setZoom(10);
            } else {
                  alert("Geocode was not successful for the following reason: " + status);
            }
      }
    );
};

map_editor.prototype.importGeoJSONMarkers = function (s) {

      if (s !== undefined && s.length > 0) {
            var featureCollection = JSON.parse(s);
            var features = featureCollection.features;
            for (var i in features) {
                  var feature = features[i];
                  var latlng = new google.maps.LatLng(feature.geometry.coordinates[0], feature.geometry.coordinates[1]);
                  this.bounds.extend(latlng);
                  marker = new google.maps.Marker({ position: latlng, map: this.map, draggable: true, icon: "http://maps.google.com/mapfiles/marker.png", title: feature.properties.label });
                  marker.text = feature.properties.text;
                  marker.label = feature.properties.label;
                  marker.postUrl = feature.properties.postUrl;
                  marker.postTitle = feature.properties.postTitle;
                  this.addedMarkers.push(marker);

                  this.addForegroundMarkerClickHandler(marker);

            }
      }
};

map_editor.prototype.addForegroundMarkerClickHandler = function (marker) {
      var self = this;
      google.maps.event.addListener(marker, 'click', function () { self.handleForegroundMarkerClick(marker); });
};

map_editor.prototype.handleForegroundMarkerClick = function (marker) {

      if (this.bReadOnly) {
            this.showInfoWindow('display', marker);
      } else {
            this.showInfoWindow('edit', marker);
      }
};

// mode = 'display' | 'create' | 'edit'
map_editor.prototype.showInfoWindow = function (mode, marker) {
      if (mode == 'display') {
            this.infowindow.setContent(this.formatMarkerInfo(marker.label, marker.text, marker.postUrl, marker.postTitle));
            this.infowindow.open(this.map, marker);

      } else {

            var infowindow = this.infowindow;

            var content = "<div id='info-content' class='info-content'><div class='strong'>Please provide a name for this map marker</div>" +
                              "<div class='small-pale'>This is what people will see next to the marker on the map.</div>" +
                              "<input type='text' class='markerlabel' id='label' value='" + marker.label + "' />" +
                              "<div class='strong'>Please provide a description</div>" +
                              "<div class='small-pale'>This is what people will see when they click on your marker.</div>" +
                              "<textarea class='markertext' rows=2 cols=40 id='text' >" +
                              marker.text +
                              "</textarea>" +
                              "<div class='align-right'>";

            if (mode == 'edit') {
                  content += "<input type='button' id='infoDelete' value='Delete Marker' /></div>";
            } else {
                  content += "<input type='button' id='infoCancel' value='Cancel' />";
            }


            content += "<input type='button' id='infoSave' value='Save Marker' /></div></div>";

            infowindow.setContent(content);

            var editor = this;

            google.maps.event.addListener(infowindow, 'domready',
            function () {
                  $('#infoSave').click(function (event) {
                        // save changes
                        marker.label = $('.markerlabel,#label')[0].value;
                        marker.text = $('.markertext,#text')[0].value;

                        // cleanup
                        $('#infoSave').unbind('click');
                        $('#infoCancel').unbind('click');
                        if (mode == 'edit') { $('#infoDelete').unbind('click'); }
                        google.maps.event.clearListeners(infowindow);
                        infowindow.close();
                        return false;
                  });

                  if (mode == 'edit') {
                        $('#infoDelete').click(function (event) {
                              google.maps.event.clearListeners(marker);

                              for (var i = editor.addedMarkers.length - 1; i >= 0; i--) {
                                    if (editor.addedMarkers[i] === marker) {
                                          editor.addedMarkers.splice(i, 1);
                                    }
                              }

                              marker.setMap(null);
                              marker = null;

                              // cleanup
                              $('#infoSave').unbind('click');
                              $('#infoCancel').unbind('click');
                              $('#infoDelete').unbind('click');
                              google.maps.event.clearListeners(infowindow);
                              infowindow.close();
                              return false;
                        });
                  }

                  $('#infoCancel').click(function (event) {
                        // if we were adding new marker then remove it
                        if (mode == 'create') {
                              google.maps.event.clearListeners(marker);
                              editor.addedMarkers.pop(marker);
                              marker.setMap(null);
                              marker = null;
                        }
                        // cleanup
                        $('#infoSave').unbind('click');
                        $('#infoCancel').unbind('click');
                        if (mode == 'edit') { $('#infoDelete').unbind('click'); }
                        google.maps.event.clearListeners(infowindow);
                        infowindow.close();
                        return false;
                  });

            });

            infowindow.open(this.map, marker);

      }
};


map_editor.prototype.zoomToExtent = function () {

      if (!this.bReadOnly) {
            if (this.addedMarkers.length == 0) {
                  return;
            }

            if (this.addedMarkers.length == 1) {
                  this.map.panTo(this.addedMarkers[0].getPosition());
                  return;
            }
      }

      this.map.fitBounds(this.bounds);
};

map_editor.prototype.zoomToBounds = function (zoomdetails) {
      var newbounds = new google.maps.LatLngBounds(new google.maps.LatLng(zoomdetails.coordinates[0][0][1], zoomdetails.coordinates[0][0][0]), new google.maps.LatLng(zoomdetails.coordinates[4][0][1], zoomdetails.coordinates[4][0][0]));
      this.map.fitBounds(newbounds);
};


map_editor.prototype.importJSONMapState = function (s) {
      if (s !== undefined && s.length > 0) {
            this.initialZoomSpecified = true;
            var zoomdetails = JSON.parse(s);
            //            if (this.bReadOnly && zoomdetails.bounds) {
            //                  var sw = new google.maps.LatLng(zoomdetails.bounds.sw.lat, zoomdetails.bounds.sw.lng);
            //                  var ne = new google.maps.LatLng(zoomdetails.bounds.ne.lat, zoomdetails.bounds.ne.lng);
            //                  var bnds = new google.maps.LatLngBounds(sw, ne);
            //                  this.map.fitBounds(bnds);
            //            }
            //            else
            {
                  this.map.setCenter(new google.maps.LatLng(zoomdetails.center.lat, zoomdetails.center.lng, true));
                  this.map.setZoom(zoomdetails.zoom);
            }

            if (zoomdetails.mapTypeId) {
                  this.map.setMapTypeId(zoomdetails.mapTypeId);
            }
      }
};


map_editor.prototype.exportGeoJSONMarkers = function () {
      //this.map.closeInfoWindow(); // ensure info window is closed so marker text is set.
      var result = { type: "FeatureCollection", features: [] };
      for (var i in this.addedMarkers) {
            var marker = this.addedMarkers[i];
            var latlon = marker.getPosition();
            result.features.push({ type: "Feature", geometry: { type: "Point", coordinates: [latlon.lat(), latlon.lng()] }, properties: { label: marker.label, text: marker.text} });
      }
      return JSON.stringify(result);
};

map_editor.prototype.exportJSONMapState = function () {
      var bnds = this.map.getBounds();
      var center = bnds.getCenter();
      var sw = bnds.getSouthWest();
      var ne = bnds.getNorthEast();
      var mapstate = { bounds: { sw: { lat: sw.lat(), lng: sw.lng() }, ne: { lat: ne.lat(), lng: ne.lng()} }, center: { lat: center.lat(), lng: center.lng() }, zoom: this.map.getZoom(), mapTypeId: this.map.getMapTypeId() };
      return JSON.stringify(mapstate);
};


map_editor.prototype.follow = function () {
      var marker;
      var dog = true;
      var noMore = false;
      var editor = this;
      var markerClick;

      var clickHandler = function (mouseEvent) {
            dog = false;
            // 'mousemove' event listener is deleted to save resources
            google.maps.event.removeListener(mouseMove);
            google.maps.event.removeListener(mapClick);
            google.maps.event.removeListener(markerClick);

            editor.addedMarkers.push(marker);
            editor.bounds.extend(marker.getPosition());
            editor.addForegroundMarkerClickHandler(marker);

            // show info window
            editor.showInfoWindow('create', marker);
      };

      var mouseMove = google.maps.event.addListener(editor.map, 'mousemove', function (mouseEvent) {
            // 'this' is the map
            if (!noMore) {
                  noMore = true;
                  marker = new google.maps.Marker({ position: mouseEvent.latLng, draggable: true, map: editor.map, icon: "http://maps.google.com/mapfiles/marker.png" });
                  marker.text = "";
                  marker.label = "";
                  marker.postUrl = "";
                  marker.postTitle = "";
                  // This OLD function deletes the marker when dragged outside map
                  //                    GEvent.addListener(marker, 'drag', function (markerPoint) {
                  //                        if (!map.getBounds().containsLatLng(markerPoint)) {
                  //                            map.removeOverlay(marker);
                  //                        }
                  //                    });
                  markerClick = google.maps.event.addListener(marker, 'click', clickHandler);
            }
            if (dog) {
                  marker.setPosition(mouseEvent.latLng);
            }
      });
      var mapClick = google.maps.event.addListener(editor.map, 'click', clickHandler);
};


map_editor.prototype.loadBackground = function () {

      var self = this;

      var infoDisplay = function () {
            //this.infowindow.setContent("<div class='markertext'>" + marker.text + "</div>");

            self.infowindow.setContent(this.content);
            self.infowindow.open(self.map, this);
      };

      if (!this.background_url) { return; }
      $.ajax({
            type: "GET",
            url: this.background_url,
            dataType: "json",
            success: function (data) {

                  var markers = [];

                  for (var i in data.features) {
                        var latlng = new google.maps.LatLng(data.features[i].geometry.coordinates[0], data.features[i].geometry.coordinates[1]);
                        self.bounds.extend(latlng);

                        // Create a new marker. Don't add it to the map!
                        var marker = new google.maps.Marker({
                              position: latlng,
                              icon: "/Content/markers/bluemarker.png",
                              title: data.features[i].properties.label
                        });
                        marker.content = self.formatMarkerInfo(data.features[i].properties.label, data.features[i].properties.text, data.features[i].properties.postUrl, data.features[i].properties.postTitle); //data.features[i].properties.html;

                        google.maps.event.addListener(marker, 'click', infoDisplay);

                        if (self.bCluster) {
                              self.markerCluster.addMarker(marker);
                        }
                        else {
                              marker.setMap(self.map);
                        }
                        markers.push(marker);
                  }

                  if (markers.length > 0) {

                        // zoom to bounds
                        if (!self.initialZoomSpecified) {
                              self.zoomToExtent();
                        }

                        if (self.bCluster) {
                              // Initialize Fluster
                              // This will set event handlers on the map and calculate clusters the first time.
                              self.markerCluster.initialize();
                        }
                  }

            },
            error: function () { alert("An error occured loading background data for the map."); }
      });
};

map_editor.prototype.formatMarkerInfo = function (markerLabel, markerText, postUrl, postTitle) {
      var s = "<div id='info-content' class='info-content'><h6><a href='" + postUrl + "'>" + postTitle + "</a></h6><h6 class='markerlabel'>" + markerLabel + "</h6>";
      if (!this.bHideMarkerDesc) {
            s = s + "<div class='markertext'>" + markerText + "</div></div>";
      }
      return s;
}

//map_editor.prototype.closePopup = function (popup) {
//    popup.feat.attributes.text = document.getElementById(popup.fldname + "_t").value
//    popup.feat = null;
//    popup.map.removePopup(popup);
//    popup.destroy();
//}

//map_editor.prototype.closePopupIfOpen = function () {
//    while (this.map.popups.length > 0) {
//        this.closePopup(this.map.popups[0]);
//    }
//}

map_editor.prototype.clearMarkers = function () {
      //this.markerlayer.removeFeatures(this.markerlayer.features);
      for (var i in this.addedMarkers) {
            var marker = this.addedMarkers[i];
            marker.setMap(null);
      }
      this.addedMarkers = [];
}



