var MAP_MANAGER_ENABLE_GLOG_DEBUG = false;

function MapManager(idMapContainer)
{
  // ###########################################################################
  // Members
  // ###########################################################################
  this.idMapContainer = idMapContainer;
  this.zoomLevel = 13;
  this.map = null;
  this.markerManager = null;

  this.jsonMarkerContentUrl = "";
  this.jsonMarkerContentUrlParams = "";

  this.jsonPOIMarkerContentUrl = "";
  this.jsonPOIMarkerContentUrlParams = "";

  this.markerIconBaseUrl = "";
  
  this.gMapTypeControl = new GMapTypeControl();
  //this.gMapControl = new GLargeMapControl();
  //this.gMapControl = new GSmallZoomControl();
  this.gMapControl = new GLargeMapControl3D();
  
  this.lastBounds = null;
  
  this.G_ICONS_CACHE = [];
  this.POI_MARKER_MANAGERS = [];

  this.getMySelf = function()
  {
    return this;
  }
  // ###########################################################################
  // Manage Map
  // ###########################################################################
  this.getMap = function(){
    if( this.map != null )
      return this.map;
    if (GBrowserIsCompatible()) 
    {
      this.map = new GMap2($(this.idMapContainer));
      this.map.addControl(this.gMapTypeControl);
      this.map.addControl(this.gMapControl);
      return this.map;
    }
    else
    {
      alert("Sorry, the Google Maps API is not compatible with this browser");
      return  null;
    }
  }
  this.getIdMapContainer = function(){
    return this.idMapContainer;
  }
  //----------------------------------------------------------------
  this.getMarkerManager = function(){
    if( this.markerManager != null )
      return this.markerManager;
    var currentMap = this.getMap();
    if( currentMap != null )
      this.markerManager = new MarkerManager(currentMap);
    return this.markerManager;
  }
  
  //----------------------------------------------------------------
  this.show = function(latitude, longitude, zoomLevel){
    var currentMap = this.getMap();
    if( zoomLevel != null )
      this.zoomLevel = zoomLevel;
    currentMap.setCenter(new GLatLng(latitude, longitude), this.zoomLevel);
  }
  //----------------------------------------------------------------
  this.checkResize = function() {
    this.getMap().checkResize();
    if( this.lastBounds != null )
      this.show(this.lastBounds.getCenter().lat(), this.lastBounds.getCenter().lng(), this.getMap().getBoundsZoomLevel(this.lastBounds) );
  }
  //----------------------------------------------------------------
  this.addGMapControl = function(){
    var map = this.getMap();
    map.addControl(this.gMapControl);
  }
  this.removeGMapControl = function(){
    var map = this.getMap();
    map.removeControl(this.gMapControl);
  }
  this.addGMapTypeControl = function(){
    var map = this.getMap();
    map.addControl(this.gMapTypeControl);
  }
  this.removeGMapTypeControl = function(){
    var map = this.getMap();
    map.removeControl(this.gMapTypeControl);
  }
  this.removeAllGControl = function(){
    var map = this.getMap();
    map.removeControl(this.gMapTypeControl);
    map.removeControl(this.gMapControl);
  }


  // ###########################################################################
  // Show/hide map container
  // ###########################################################################
  this.hideMe = function(){
    $(this.idMapContainer).hide();
  }
  //----------------------------------------------------------------
  this.showMe = function(){
    $(this.idMapContainer).show();
    this.checkResize();
  }
  // 
  // ###########################################################################
  // Manage marker
  // ###########################################################################
  this.createMarker = function(latitude, longitude, html){
    var marker = new GMarker(new GLatLng(latitude, longitude));
    if( html != null )
    {
      GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(html);
      }
    );
    }
    return marker;
  }
  //----------------------------------------------------------------
  this.addNewMarker = function(latitude, longitude, html) {
    var marker = this.createMarker(latitude, longitude, html);
    this.addMarker(marker);
    return marker;
  }
  //----------------------------------------------------------------
  this.addMarker = function(marker) {
    var currentMap = this.getMap();
    try
    {
      currentMap.addOverlay(marker);
    }
    catch (e) { if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write(e.toString());};
  }
  //----------------------------------------------------------------
  this.setMarkerAjaxContent = function(marker, url, urlParams) {
    GEvent.addListener(marker, "click", function() {
      var options = {
        onSuccess:function(t){
          marker.openInfoWindowHtml(t.responseText);
        },
        parameters: urlParams,
        asynchronous:true
      };
      new Ajax.Request(url, options);
    }
  );
  }
  // ###########################################################################
  // Manage json marker
  // ###########################################################################
  this.setMarkerIconBaseUrl = function(val){
    this.markerIconBaseUrl = val != null ? val : "";
  }
  //----------------------------------------------------------------
  this.setJsonMarkerContentUrl = function(val){
    this.jsonMarkerContentUrl = val;
  }
  //----------------------------------------------------------------
  this.setJsonMarkerContentUrlParams = function(val){
    this.jsonMarkerContentUrlParams = val != null ? val : "";
  }
  //----------------------------------------------------------------
  this.setJsonPOIMarkerContentUrl = function(val){
    this.jsonPOIMarkerContentUrl = val;
  }
  //----------------------------------------------------------------
  this.setJsonPOIMarkerContentUrlParams = function(val){
    this.jsonPOIMarkerContentUrlParams = val != null ? val : "";
  }
  //----------------------------------------------------------------
  this.loadJsonHotelMarkers = function(hotels) {
    try
    {
      //GLog.write('loadJsonHotelMarkers start...');
      var currentMarkerManager;
      if( hotels == null )
      {
        if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write("Invalid json data");
        return 0;
      }
      var totPoi = hotels["places"].length;
      if( totPoi == 0 )
      {
        var returnValue;
        //GLog.write('No results!' + hotels["coords"][0] + '-' + hotels["coords"][1]);
        if( hotels["poiFilterApplied"] )
        {
          this.show(hotels["poiFilterApplied"].coords[0], hotels["poiFilterApplied"].coords[1], 15);
          returnValue = -1
        }
        else
        {
          this.show(hotels["coords"][0], hotels["coords"][1]);
          returnValue = 0;
        }
        currentMarkerManager = this.getMarkerManager();
        currentMarkerManager.clearMarkers();
        return returnValue;
      }
      this.lastBounds = new GLatLngBounds();
      if( hotels["poiFilterApplied"] )
      {
        var poiCoords = new GLatLng(hotels["poiFilterApplied"].coords[0], hotels["poiFilterApplied"].coords[1]);
        this.lastBounds.extend( poiCoords );      
      }
      var markers = [];
      for (var j=0; j < hotels["places"].length; j++) 
      {
        var place = hotels["places"][j];
        var marker = buildMarker(this.getMySelf(), place);
        markers.push(marker);
        var coords = new GLatLng(place["coords"][0], place["coords"][1]);
        this.lastBounds.extend( coords );
        //GLog.write(hotels["places"][j].id);
      }
      var zoomLevelToUse = totPoi > 1 ? this.getMap().getBoundsZoomLevel(this.lastBounds) : 13;
      this.show(this.lastBounds.getCenter().lat(), this.lastBounds.getCenter().lng(), zoomLevelToUse );

      currentMarkerManager = this.getMarkerManager();
      currentMarkerManager.clearMarkers();
      currentMarkerManager.addMarkers(markers, hotels["zoom"][0], hotels["zoom"][1]);
      currentMarkerManager.refresh();
      return totPoi;
    }
    catch (e) {
      if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write(e.toString());
      return 0;
    }
  }
  //----------------------------------------------------------------
  this.loadJsonPOIMarkers = function(idPoiType, poiData) {
    try
    {
      if( idPoiType == null || idPoiType == "" )
      {
        if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write("Invalid idPoiType");
        return 0;
      }
      if( poiData == null )
      {
        if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write("Invalid json data");
        return 0;
      }
      var totPoi = poiData["places"].length;
      if( totPoi == 0 )
      {
        return totPoi;
      }
      var markers = [];
      for (var j=0; j < poiData["places"].length; j++) 
      {
        var place = poiData["places"][j];
        //Build marker
        var marker = buildMarker(this.getMySelf(), place);
        markers.push(marker);
      }
 
      var currentPOIMarkerManager = null;
      if (this.POI_MARKER_MANAGERS[idPoiType] == null)
      {
        var currentMap = this.getMap();
        if( currentMap != null )
          currentPOIMarkerManager = new MarkerManager(currentMap);
        this.POI_MARKER_MANAGERS[idPoiType] = currentPOIMarkerManager;
      }
      currentPOIMarkerManager = this.POI_MARKER_MANAGERS[idPoiType];
      if( currentPOIMarkerManager == null )
      {
        if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write("Cannot create MarkerManager for POI type " + idPoiType);
        return 0;
      }
      currentPOIMarkerManager.clearMarkers();
      currentPOIMarkerManager.addMarkers(markers, poiData["zoom"][0], poiData["zoom"][1]);
      currentPOIMarkerManager.refresh();
      if( this.getMap().getZoom() < poiData["zoom"][0] )
        this.getMap().setZoom(poiData["zoom"][0]);
      else if( this.getMap().getZoom() > poiData["zoom"][1] )
        this.getMap().setZoom(poiData["zoom"][1]);
      return totPoi;
    }
    catch (e) { 
      if(MAP_MANAGER_ENABLE_GLOG_DEBUG) GLog.write(e.toString());
      return 0;
    }
  }
 
  //----------------------------------------------------------------
  this.clearPOIMarkers = function(idPoiType){
    if (this.POI_MARKER_MANAGERS[idPoiType] != null)
    {
      this.POI_MARKER_MANAGERS[idPoiType].clearMarkers();
    }
  }
  //----------------------------------------------------------------
  this.clearAllPOIMarkers = function(){
    this.POI_MARKER_MANAGERS.each(function(item) {
        if( item != null)
            item.clearMarkers();
      });
    var tooltipId = this.idMapContainer + '_tooltip';
    if( $(tooltipId) != null )
       $(tooltipId).hide();
  }
  //----------------------------------------------------------------
  

  // ###########################################################################
  // Internal use methods
  // ###########################################################################
  
  function buildMarker(mySelf, place )
  {
    var coords = new GLatLng(place["coords"][0], place["coords"][1]);
    var markerIcon = getIcon(mySelf, place["icon"]);
    var opts = {icon: markerIcon};
    if( place["tooltip"] )
      opts.title = place["tooltip"];
    var marker = new GMarker(coords, opts);
    if( place["mouseOver"] )
    {
      var mouseOver = place["mouseOver"];
      if( mouseOver["useExtInfoWindow"] == true )
      {
        GEvent.addListener(marker, "mouseover", function(){ 
          marker.openExtInfoWindow(
            mySelf.getMap(),
            mouseOver["extInfoWindowCssId"],
            mouseOver["content"],
            {beakOffset: 3}
          ); 
          if( mouseOver["mouseOverImageName"] )
            marker.setImage(mySelf.markerIconBaseUrl + mouseOver["mouseOverImageName"] + ".png")
        });
        GEvent.addListener(marker,"mouseout", function() {
          mySelf.getMap().closeExtInfoWindow();
          if( mouseOver["mouseOutImageName"] )
            marker.setImage(mySelf.markerIconBaseUrl + mouseOver["mouseOutImageName"] + ".png")
        });          
      }
      else
      {
        GEvent.addListener(marker, "mouseover", function(){ 
          marker.openInfoWindowHtml(mouseOver["content"]); 
        });
        GEvent.addListener(marker,"mouseout", function() {
          mySelf.getMap().closeInfoWindow();
        });          
      }
    }
    else if ( place["extTooltip"] )
    {
      var extTooltip = place["extTooltip"];
      var tooltipId = mySelf.getMap().getContainer().id + '_tooltip';
      GEvent.addListener(marker, "mouseover", function(){
        var tooltip = $(tooltipId);
        if( tooltip == null )
        {
          var mapManagerTooltipDiv = '<div id="' + tooltipId + '"></div>';
          Element.insert( mySelf.getMap().getContainer(), {'top':mapManagerTooltipDiv});
          //new Insertion.Top(mySelf.getMap().getContainer(), mapManagerTooltipDiv)
          tooltip = $(tooltipId);
        }
        $w(tooltip.className).each(function(currentClassName){
          tooltip.removeClassName(currentClassName);
          });
        tooltip.addClassName('mapManagerTooltip');
        if( extTooltip["cssClassName"] )
           tooltip.addClassName(extTooltip["cssClassName"]);
  	tooltip.innerHTML = extTooltip["content"];
        var point=mySelf.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(mySelf.getMap().getBounds().getSouthWest(),mySelf.getMap().getZoom());
        var offset=mySelf.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),mySelf.getMap().getZoom());
        var anchor=marker.getIcon().iconAnchor;
        var width=marker.getIcon().iconSize.width;
        var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(offset.x - point.x - anchor.x + width,- offset.y + point.y +anchor.y - $(tooltipId).getHeight())); 
        pos.apply(tooltip);
        $(tooltipId).show();

        if( extTooltip["mouseOverImageName"] )
          marker.setImage(mySelf.markerIconBaseUrl + extTooltip["mouseOverImageName"] + ".png")
      });
      GEvent.addListener(marker,"mouseout", function() {
        $(tooltipId).hide();
        if( extTooltip["mouseOutImageName"] )
          marker.setImage(mySelf.markerIconBaseUrl + extTooltip["mouseOutImageName"] + ".png")
      });          
    }
    if( place["click"] )
    {
      var click = place["click"];
      if( click["useCustomScript"] == true )
      {
        GEvent.addListener(marker, "click", function(){ 
          eval(click["customScript"]);
        });          
      }
      else if( click["useAjax"] == true )
      {
        var tmpMapManager = new MapManager('tmp');
        tmpMapManager.setMarkerAjaxContent(marker, click["contentAjaxUrl"], click["contentAjaxUrlParams"] ? click["contentAjaxUrlParams"] : '');
      }
      else if( click["useExtInfoWindow"] == true )
      {
        GEvent.addListener(marker, "click", function(){ 
          marker.openExtInfoWindow(
            mySelf.getMap(),
            click["extInfoWindowCssId"],
            click["content"],
            {beakOffset: 3}
          ); 
        });
      }
      else
      {
        GEvent.addListener(marker, "click", function(){ 
          marker.openInfoWindowHtml(click["content"]); 
        });
      }
    }
    return marker;
  }

  function getIcon(mySelf, icon) 
  {
    if (icon && icon["image"]) 
    {
      if (mySelf.G_ICONS_CACHE[icon["image"]] == null) 
      {
        var gicon = new GIcon();
        gicon.image = mySelf.markerIconBaseUrl + icon["image"] + ".png";
        gicon.iconAnchor = icon["iconAnchor"] ? new GPoint(icon["iconAnchor"][0], icon["iconAnchor"][1]) : new GPoint(16, 16);
        gicon.iconSize = icon["iconSize"] ? new GSize(icon["iconSize"][0], icon["iconSize"][1]) : new GSize(32, 32);
        gicon.infoWindowAnchor = icon["infoWindowAnchor"] ? new GPoint(icon["infoWindowAnchor"][0], icon["infoWindowAnchor"][1]) : new GPoint(16, 0);
        gicon.shadow = mySelf.markerIconBaseUrl + icon["image"] + "-shadow.png";
        gicon.shadowSize = icon["shadowSize"] ? new GSize(icon["shadowSize"][0], icon["shadowSize"][1]) : new GSize(59, 32); 
        mySelf.G_ICONS_CACHE[icon["image"]] = gicon;
      }
      return mySelf.G_ICONS_CACHE[icon["image"]];
    }
    return null;
  }	  

}  
  
  
  
  
  
  
  
  
  
   
