﻿if (!MapData) var MapData = {};

var StatusDiv = {
  setContent: function (content) {
    $("#divMapStatus").html(content);
    $(document).trigger("status-div-updated");
  }
};

var MapUseContext = {
  none: String.empty,
  trip: "Trip",
  journal: "Journal"
};

var MapState = {
  context: MapUseContext.none,
  currentLatLng: null,
  map: null,
  selectedMarker: null,
  MarkerCollection: []
};

var MapController = (function () {
  var statusDiv = $("#divMapStatus");

  var previousMarker;
  var selectedMarkerPreviousIcon;
  var selectedMarkerPreviousShadow;
  var trafficLayer = new google.maps.TrafficLayer();

  var init = function () {
    if (settings.useFakes) {
      $("#map").html("<div id='fake-map' style='width: 100%; height: 100%; background:url(/images/fakes/map.jpg) no-repeat 0 0 transparent;'></div>");
    }
    initGoogleMap();
    delegateSetMapPreferences();
    bindMapEvents();
    delegatePopulateMarkers();
    Location.watch();
  };

  var initGoogleMap = function () {
    var latLng = new google.maps.LatLng(settings.defaultLatitude, settings.defaultLongitude);
    var mapOptions = {
      zoom: settings.defaultZoom,
      center: latLng,
      mapTypeId: CurrentBrowser.mobile ? mapSettings.mobileMapType : mapSettings.mapType
    };
    MapState.map = new google.maps.Map(document.getElementById("map"), mapOptions);
    MapState.currentLatLng = latLng;
  };

  var delegateSetMapPreferences = function () {
    if (MapData.MarkerCollection && MapData.MarkerCollection.length > 0) MapState.MarkerCollection = MapData.MarkerCollection;

    if (UIState.mapLatitude != String.empty &&
      UIState.mapLongitude != String.empty &&
      UIState.mapZoomLevel != String.empty &&
      !$.isNaN(UIState.mapZoomLevel)) {

      setLocationStatus(UIState.mapLatitude, UIState.mapLongitude);
      MapState.map.setZoom(UIState.mapZoomLevel);
      setCurrentMarkerData(UIState.mapLatitude, UIState.mapLongitude);
      centerMapToCurrentLocation();
      return;
    }

    setDefaultLocation();
    setDefaultZoom();
    setLocationStatus(MapState.currentLatLng.lat(), MapState.currentLatLng.lng());
    setCurrentMarkerData(UIState.mapLatitude, UIState.mapLongitude);
    centerMapToCurrentLocation();
  };

  var bindMapEvents = function () {
    google.maps.event.addListener(MapState.map, "zoom_changed", function () {
      UIState.update();
    });
  };

  var delegatePopulateMarkers = function () {
    if (MapData.populateMarkers) {
      MapData.populateMarkers();
      createMarkersFromCollection();
      setSelectedMarker(getMarkerByLatLng(MapState.currentLatLng.lat(), MapState.currentLatLng.lng()));
    } else {
      if (!Session.authenticated)
        MarkerController.createNewMarker(0, null, false);
    }
  };

  var bindMarkerEvents = function (marker) {
    google.maps.event.addListener(marker, 'click', function (event) { handleMarkerClick(event, this); });
    google.maps.event.addListener(marker, 'dragstart', function (event) { handleDragStart(event, this); });
    google.maps.event.addListener(marker, 'dragend', function (event) { handleDragEnd(event, this); });
  };

  var handleLocationResults = function (result, status, excludeSearch) {
    if (status == "OK") {
      StatusDiv.setContent(result[0].formatted_address + "<br />" +
				Math.precision(MapState.currentLatLng.lat(), 4) + ", " + Math.precision(MapState.currentLatLng.lng(), 4));

      if (settings.imageSearchEnabled && !excludeSearch) {
        var locality = "";
        for (var i = 0; i < result[0].address_components.length; i++) {
          var componentTypes = result[0].address_components[i].types;
          if (componentTypes.length > 0 &&
          (componentTypes[0] == "administrative_area_level_1" || componentTypes[0] == "locality")) {
            locality = result[0].address_components[i].long_name;
            break;
          }
        }

        ImageSearchController.searchByLocation(MapState.currentLatLng.lat(), MapState.currentLatLng.lng(), locality);
        UIDisplay.showTab("#places-asset-grid", false);
      }
    } else {
      StatusDiv.setContent(Math.precision(MapState.currentLatLng.lat(), 4) + ", " + Math.precision(MapState.currentLatLng.lng(), 4));
    };
  };

  var findAddress = function (addess) {
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({ address: addess }, handleFindLocationResults);
  };

  var handleFindLocationResults = function (results, status) {
    if (results.length > 0) {
      var latLng = results[0].geometry.location;
      MapState.currentLatLng = latLng;
      MarkerController.setMarker(latLng.lat(), latLng.lng());
    }
    else {
      Modal.setContent("<p class='modal-alert'>Location not found.</p>");
      Modal.show(UIConstants.speed);
    }
  };

  var handlePlacesResult = function (result, status) {
    if (status == "OK") {
      var place = null;
      var priorAbsDiff = 100000;
      for (var i = 0; i < result.length; i++) {
        var thisPlace = result[i];
        if (place == null) {
          place = thisPlace;
          continue;
        }
        var latDiff = thisPlace.geometry.location.lat() - place.geometry.location.lat();
        var lngDiff = thisPlace.geometry.location.lng() - place.geometry.location.lng();
        var absDiff = Math.abs(latDiff) + Math.abs(lngDiff);
        if (absDiff < priorAbsDiff) {
          priorAbsDiff = absDiff;
          place = thisPlace;
        }
      }
      StatusDiv.setContent(place.name + "<br />" + Math.precision(MapState.currentLatLng.lat(), 4) + ", " + Math.precision(MapState.currentLatLng.lng(), 4));
    }
  };

  var getPlaces = function () {
    var request = {
      location: MapState.currentLatLng,
      radius: '50',
      types: ['point_of_interest', 'natural_feature', 'stadium', 'establishment', 'amusement_park']
    };

    if (google.maps.places != undefined) {
      var service = new google.maps.places.PlacesService(MapState.map);
      service.search(request, handlePlacesResult);
    }
  };

  var setLocationStatus = function (lat, lng, excludeSearch) {
    if (parseInt(lat) != "NaN" && parseInt(lng) != "NaN") {
      var geocoder = new google.maps.Geocoder();
      var latLng = new google.maps.LatLng(lat, lng);
      geocoder.geocode({ latLng: latLng }, function (result, status) { handleLocationResults(result, status, excludeSearch); });
    } else {
      StatusDiv.setContent(Resources.Global_Location + " " + Resources.Marker_NoneSelected);
    }
  };

  var getMarkerByLatLng = function (latitude, longitude) {
    for (var i = 0; i < MapState.MarkerCollection.length; i++) {
      if (MapState.MarkerCollection[i].position.lat() == latitude && MapState.MarkerCollection[i].position.lng() == longitude)
        return MapState.MarkerCollection[i];
    }
    return null;
  };

  var getMarkerById = function (markerId) {
    for (var i = 0; i < MapState.MarkerCollection.length; i++) {
      if (MapState.MarkerCollection[i].id == markerId)
        return MapState.MarkerCollection[i];
    }
    return null;
  };

  var setCurrentMarkerData = function (lat, lng, marker, markerType) {
    /* set new values */
    if (lat && lng) {
      var latlng = new google.maps.LatLng(lat, lng);
      MapState.currentLatLng = latlng;
    }

    if (marker) MarkerController.selectedMarkerId = marker.id;
    if (markerType) MarkerController.selectedMarkerType = markerType.toString();
    UIState.update();
  };

  var createMarkersFromCollection = function () {
    if (MapData.MarkerCollection) {
      for (var i = 0; i < MapData.MarkerCollection.length; i++) {
        var marker = new google.maps.Marker({
          position: MapData.MarkerCollection[i].position,
          map: MapData.MarkerCollection[i].map,
          draggable: MapData.MarkerCollection[i].markerType == MarkerType.Standard,
          id: MapData.MarkerCollection[i].id,
          markerType: MapData.MarkerCollection[i].markerType
        });

        if (marker.markerType) {
          marker.setIcon(marker.markerType.MarkerImage);
          marker.setShadow(marker.markerType.MarkerShadow);
        }

        bindMarkerEvents(marker);
        MapState.MarkerCollection[i] = marker;
      }
    }
  };

  var handleMarkerClick = function (event, marker) {
    setSelectedMarker(marker);
  };

  var handleCreateMarker = function (point) {
    MarkerController.setMarker(point.latLng.lat(), point.latLng.lng());
  };

  var setSelectedMarker = function (marker, persist, excludeSearch, drag) {
    if (marker == null)
      return;
    if (persist == null)
      persist = true;

    setSelectedMarkerIcon(marker);

    var latlng = marker.getPosition();
    MapState.currentLatLng = latlng;

    var markerType = marker.markerType ? marker.markerType : MarkerType.Standard;

    if (persist)
      setCurrentMarkerData(latlng.lat(), latlng.lng(), marker, markerType);

    if (!drag)
      setLocationStatus(latlng.lat(), latlng.lng(), excludeSearch);

    if (settings.imageSearchEnabled)
      getPlaces();

    $(document).trigger("marker-selected", [marker.id]);
  };

  var setSelectedMarkerIcon = function (marker) {
    if (MapState.selectedMarker) {
      if (selectedMarkerPreviousIcon) {
        MapState.selectedMarker.setIcon(selectedMarkerPreviousIcon);
        MapState.selectedMarker.setShadow(selectedMarkerPreviousShadow);
      } else {
        MapState.selectedMarker.setIcon(MarkerType.Standard.MarkerImage);
        MapState.selectedMarker.setShadow(MarkerType.Standard.MarkerShadow);
      }
      previousMarker = MapState.selectedMarker;
    }
    if (marker) {
      MapState.selectedMarker = marker;
      selectedMarkerPreviousIcon = MapState.selectedMarker.getIcon();
      selectedMarkerPreviousShadow = MapState.selectedMarker.getShadow();
      if (marker.markerType != MarkerType.Blip) {
        MapState.selectedMarker.setIcon(MarkerType.Selected.MarkerImage);
        MapState.selectedMarker.setShadow(MarkerType.Selected.MarkerShadow);
      }
    }
  };

  var centerMapToCurrentLocation = function () {
    setCurrentMarkerData();
    MapState.map.setCenter(MapState.currentLatLng);
  };

  var handleDragStart = function () {
    StatusDiv.setContent("<div class=\"loading\" style=\"display: block; width: 32px; height: 32px;\"></div>");
  };

  var handleDragEnd = function (event, marker) {
    statusDiv.css("color", "#000066");
    setSelectedMarker(marker);
    MarkerController.updateMarker(marker);
  };

  var removeMarker = function (marker) {
    for (var i = 0; i < MapState.MarkerCollection.length; i++) {
      if (marker.id == MapState.MarkerCollection[i].id)
        MapState.MarkerCollection.splice(i);
    }
  };

  var attachNoteToMarker = function () {
    if ($("#notesContainer").is(":visible")) {
      $("#notesContainer").hide();
      return;
    }
    document.forms["frmMarkerNote"]["markerId"].value = MapState.selectedMarker.id;
    MarkerController.getMarkerNotes();
  };

  var setDefaultLocation = function () {
    setCurrentMarkerData(settings.defaultLatitude, settings.defaultLongitude);
  };

  var setDefaultZoom = function () {
    UIState.mapZoomLevel = settings.defaultZoom;
  };

  var toggleTraffic = function () {
    if (trafficLayer.getMap() == null) {
      trafficLayer.setMap(MapState.map);
      $("#toggle-traffic").attr("selected", "true");
    } else {
      $("#toggle-traffic").attr("selected", "false");
      trafficLayer.setMap(null);
    }
  };

  return {
    attachNoteToMarker: function () {
      return attachNoteToMarker();
    },
    bindMarkerEvents: function (marker) {
      return bindMarkerEvents(marker);
    },
    centerMapToCurrentLocation: function () {
      return centerMapToCurrentLocation();
    },
    findAddress: function (address) {
      return findAddress(address);
    },
    getMarkerById: function (markerId) {
      return getMarkerById(markerId);
    },
    handleCreateMarker: handleCreateMarker,
    removeMarker: function (marker) {
      return removeMarker(marker);
    },
    setCurrentMarkerData: function (lat, lng, marker, markerType) {
      return setCurrentMarkerData(lat, lng, marker, markerType);
    },
    setDefaultLocation: function () {
      return setDefaultLocation();
    },
    setDefaultZoom: function () {
      return setDefaultZoom();
    },
    setSelectedMarker: function (marker, persist) {
      return setSelectedMarker(marker, persist);
    },
    statusDiv: statusDiv,
    setLocationStatus: function (lat, lng) {
      setLocationStatus(lat, lng, true);
    },
    toggleTraffic: function () {
      toggleTraffic();
    },
    init: function () {
      return init();
    }
  };
})();

