// Copyright 2005 Google Inc.

var OMC_BUTTON_SIZE = 15;
var WHITE_BORDER_PX = 7;
var GRAY_BORDER_PX = 1;

var CMC_MAP_WIDTH = 256;
var CMC_MAP_HEIGHT = 128;
var CMC_TAB_HEIGHT = 32;
var CMC_BODY_HEIGHT = CMC_MAP_HEIGHT + 2*WHITE_BORDER_PX + GRAY_BORDER_PX;
var CMC_PANEL_WIDTH = CMC_MAP_WIDTH + WHITE_BORDER_PX + GRAY_BORDER_PX;
var CMC_PANEL_HEIGHT = CMC_BODY_HEIGHT + CMC_TAB_HEIGHT;

var DRAG_SCROLL_PERCENT = 0.04;
var DRAG_SCROLL_REPEAT_TIME = 30;

var OVC_RECT_HILITE = "#8888FF";
var OVC_RECT_BORDER = "#4444BB";
var OVC_RECT_SHADOW = "#111155";
var OVC_RECT_FILL = "#6666CC";
var OVC_RECT_ALPHA = 0.3;

var OVC_BORDER_STYLE = "1px solid #979797";

var CSS_border = "border";
var CSS_borderLeft = "borderLeft"
var CSS_borderTop = "borderTop"
var CSS_backgroundColor = "backgroundColor"
var CSS_borderRightWidth = "borderRightWidth"
var CSS_borderBottomWidth = "borderBottomWidth"

var EVENT_resize = "resize"
var EVENT_mouseover = "mouseover";
var EVENT_mouseout = "mouseout";
var EVENT_changed = "changed";

var MSG_Chart_show = "Show chart selector tool";
var MSG_Chart_hide = "Hide chart selector tool";


/**
 * ChartMapControl
 * @param {Size} opt_size specifies the size of this control
 * but it will be updated to reflect the copyright for the overview map.
 * @constructor
 */
function ChartMapControl(charts) {
  this.size_ = new GSize(CMC_PANEL_WIDTH, CMC_PANEL_HEIGHT);
  this.charts_ = charts;
}
ChartMapControl.prototype = new GControl();


/**
 * Set up the DIVs, the map, and events
 * @param {Map} map The main map on which to add the overview map
 */
ChartMapControl.prototype.initialize = function(map) {
  var me = this;
  me.map_ = map;

  var size = me.size_;

  me.innerSize_ = new GSize(CMC_MAP_WIDTH, CMC_MAP_HEIGHT);
  me.chartType_ = CHART_TYPE_GEO;
  me.currentChart_ = -1;

  var parent = map.getContainer();

  // Container includes the overview map, and also the minimize
  // hider button, which stays visible even when the overview map
  // is hidden
  var container = createElement("div", parent, null, GSize.ZERO);
  container.id = map.getContainer().id + "_overview";
  me.container_ = container;
  setSize(me.container_, GSize.ZERO);

  me.visibleSize_ = GSize.ZERO;

  me.initializeTabPanel_(parent);
  me.initializeMapContainer_();
  me.initializeChartMap_();
  me.initializeHider_();
  me.initializeEvents_();

  // update the layout after rendering is done
  objectSetTimeout(me, me.onMapResize_, 0);

  GEvent.addDomListener(me.charts_, "stateChanged", function() { 
    var container  = me.container_;
    if (me.charts_.isShowing()) {
      me.show();
    } else {
      me.hide();
    }
    GEvent.trigger(this, "resize");

  });

  // A callback to zoom to the current chart
  zc = function() { me.zoomAndPanTo(me.charts_.getIndex()); };

  return container;
};





// Reset the event handlers associated with this control.
ChartMapControl.prototype.resetEvents = function(win) {
  var me = this;
  me.initializeEvents_();
};

/**
 * The TabPanel is the white tabbed panel around the map, and
 * includes the map container.  It gets hidden by the minimize button.
 * @param {Element} parent The container of the parent map
 */
ChartMapControl.prototype.initializeTabPanel_ = function(parent) {
  var me = this;
  var tabPanel = createElement("div", me.container_, null, me.size_);
  tabPanel.id = "chartPanel";
  overflowHidden(tabPanel);

  // Cover the border:
  me.alignmentPoint_ = new GPoint(
      -cssGetPropertyPixelValue(parent, CSS_borderRightWidth),
      -cssGetPropertyPixelValue(parent, CSS_borderBottomWidth));

  setBottomRightViaBR(tabPanel, me.alignmentPoint_);
  me.tabPanel_ = tabPanel;

  bodySize = new GSize(CMC_PANEL_WIDTH-GRAY_BORDER_PX, CMC_BODY_HEIGHT);
  var panelBody = createElement("div", tabPanel, null, bodySize);
  var style = panelBody.style;
  style[CSS_borderLeft] = OVC_BORDER_STYLE;
  style[CSS_backgroundColor] = "white";
  overflowHidden(panelBody);
  setBottomRightViaTL(panelBody, GPoint.ORIGIN);
  me.panelBody_ = panelBody;

  topSize = new GSize(CMC_PANEL_WIDTH-GRAY_BORDER_PX-WHITE_BORDER_PX, WHITE_BORDER_PX);
  var topBorder = createElement("div", tabPanel, null, topSize);
  var topStyle = topBorder.style;
  topStyle[CSS_borderTop] = OVC_BORDER_STYLE;
  topStyle[CSS_backgroundColor] = "white";
  setBottomRightViaTL(topBorder, new GPoint(0, CMC_BODY_HEIGHT) );

  tabsSize = new GSize(196,32);
  var tabsContainer = createElement("div", tabPanel, null, tabsSize);
  var tabsImage;
  if (gBrowser.type == BROWSER_IE) {
    tabsImage = createElement("div", tabsContainer, GPoint.ORIGIN);
	makeFilterDivIE(tabsImage, "http://" + mapsServer + "util/tabs.png");
	tabsImage.style.width = 196;
	tabsImage.style.height = 64;
  } else {
    tabsImage = createElement("img", tabsContainer, GPoint.ORIGIN);
    tabsImage.src = "http://" + mapsServer + "util/tabs.png";
  }

  me.tabsImage_ = tabsImage;
  overflowHidden(tabsContainer);
  setBottomRightViaTL(tabsContainer, new GPoint(CMC_PANEL_WIDTH-196,CMC_BODY_HEIGHT));
  tabsContainer.style.cursor = "default";

  var geoTab = createElement("div", tabsContainer, new GPoint(18,5), new GSize(84,23));
  geoTab.innerHTML = "Geologic";
  geoTab.className = "activeTab";
  geoTab.align = "center";
  me.geoTab_ = geoTab;
  geoTab.control_ = this;
  
  var topoTab = createElement("div", tabsContainer, new GPoint(18+84+2,5), new GSize(84,23));
  topoTab.innerHTML = "Topographic";
  topoTab.className = "inactiveTab";
  topoTab.align = "center";
  me.topoTab_ = topoTab;
  topoTab.control_ = this;

  var pickText = createElement("div", tabPanel, new GPoint(6,CMC_TAB_HEIGHT-3));
  pickText.innerHTML = "Pick a chart:";
  me.pickText_ = pickText;

  var chartTitle = createElement("div", tabPanel, new GPoint(pickText.clientWidth+12,CMC_TAB_HEIGHT-3));
  if (me.charts_.getIndex() != -1) {
    chartTitle.innerHTML = ChartList[me.charts_.getIndex()][CHART_TITLE];
  }
  chartTitle.className = "currentTitle";
  me.chartTitle_ = chartTitle;

  var infoLinkDiv = createElement("div", tabPanel, new GPoint(200,CMC_TAB_HEIGHT-3));
  infoLinkDiv.style.color = "#0000CC";
  infoLinkDiv.style.textDecoration = "underline";
  var infoLink = createElement("a", infoLinkDiv);
  infoLink.innerHTML = "More info";
  infoLink.href = "chartinfo.html";
  setPosition(infoLinkDiv,new GPoint(tabPanel.clientWidth-infoLinkDiv.clientWidth-WHITE_BORDER_PX,CMC_TAB_HEIGHT-3));

  GEvent.addDomListener(topoTab, "click", function() {
    var me = this.control_;
    if( me.chartType_ == CHART_TYPE_GEO ) {
      me.geoTab_.className = "inactiveTab";
      me.topoTab_.className = "activeTab";
      me.tabsImage_.style.top = "-32px";
      me.chartType_ = CHART_TYPE_TOPO;
      me.charts_.setCurrent(me.charts_.getIndex(),me.chartType_);
    }
  });

  GEvent.addDomListener(geoTab, "click", function() {
    var me = this.control_;
    if( me.chartType_ == CHART_TYPE_TOPO ) {
      me.geoTab_.className = "activeTab";
      me.topoTab_.className = "inactiveTab";
      me.tabsImage_.style.top = "0px";
      me.chartType_ = CHART_TYPE_GEO;
      me.charts_.setCurrent(me.charts_.getIndex(),me.chartType_);
    }
  });
}


/**
 * The mapContainer is the inner gray-border box with the map
 */
ChartMapControl.prototype.initializeMapContainer_ = function() {
  var mapContainer = createElement("div", this.panelBody_, null,
                                   this.innerSize_);
  mapContainer.style[CSS_border] = OVC_BORDER_STYLE;
  setBottomRightViaTL(mapContainer, GPoint.ORIGIN);
  overflowHidden(mapContainer);
  this.mapContainer_ = mapContainer;
}


ChartMapControl.prototype.initializeChartMap_ = function() {
  var me = this;
  var overviewMap = new GMap(me.mapContainer_, {
    mapTypes: me.map_.getMapTypes(),
    size: me.innerSize_,
    suppressCopyright: true
  });
  GEvent.addListener(me.map_, "maptypechanged", function() {
      overviewMap.setMapType(me.map_.getCurrentMapType());
  });

  // Turn off double click to zoom in/out for the overview map.
  //overviewMap.disableDoubleClickZoom();

  me.overviewMap_ = overviewMap;
  me.overviewMap_.hideControls();
}


ChartMapControl.prototype.initializeHider_ = function() {
/*
  var hider = imageCreate(imagePathFromName("overcontract", true),
                          this.container_, null,
                          new GSize(OMC_BUTTON_SIZE, OMC_BUTTON_SIZE));
  setCursor(hider, "pointer");
  setBottomRight(hider, this.alignmentPoint_);
  this.hider_ = hider;
  this.hiderSize_ = new GSize(hider.offsetWidth, hider.offsetHeight);
*/
}

function cancelEvent(e) {
  if (gBrowser.type == BROWSER_IE) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  } else {
    e.preventDefault();
    e.stopPropagation();
  }
}


ChartMapControl.prototype.initializeEvents_ = function() {
  var me = this;
  // eventBindClick(me.hider_, me, me.showOrHide_);

  var map = me.map_;
  //GEvent.bind(map, "movestart", me, me.onMapMoveStart_);
  GEvent.bind(map, "moveend", me, me.reset_);
  GEvent.bind(map, "resize", me, me.onMapResize_);
  // GEvent.bind(map, "move", me, me.onMapMove_);
  // GEvent.bind(map, "maptypechanged", me, me.onMapTypeChanged_);

  var overviewMap = me.overviewMap_;
  GEvent.bind(overviewMap, "mouseover", me, me.onMouseMove_);
  GEvent.bind(overviewMap, "mousemove", me, me.onMouseMove_);
  GEvent.bind(overviewMap, "mouseout", me, me.onMouseOut_);

  var div = overviewMap.getContainer();
  GEvent.bindDom(div, "click", me, me.onClick_);
  GEvent.bindDom(div, "dblclick", me, me.onDblClick_);

  // Prevents mouse scroll events from propagating through to the
  // main map.  (This doesn't seem to be working?)
  GEvent.bindDom(div, "mousewheel", me, cancelEvent);
  GEvent.bindDom(div, "mousewheel_gecko", me, cancelEvent);

  overviewMap.disableDragging();
  overviewMap.disableDoubleClickZoom();
}

ChartMapControl.prototype.onMapMoveStart_ = function() {
  this.mapMoveStartSeen_ = true;
};


ChartMapControl.prototype.onMapResize_ = function() {
  var me = this;

  setBottomRight(me.container_, GPoint.ORIGIN);

  if (!me.map_.isLoaded()) {
    return;
  }

  // Since user zoom control is disabled, update the zoom level
  // when the user resizes the maps
  me.reset_();
};


ChartMapControl.prototype.onMouseMove_ = function(latlng) {
  var me = this;
  if (me.map_.getZoom() > 9) { return; }
  var chart = me.charts_.LatLngToChart(latlng);
  if (chart != me.currentChart_) {
    me.setRectangle(chart);
    me.setTitle(chart);
  }
  me.currentChart_ = chart;
  if (chart!=-1) {
    me.map_.getContainer().style.cursor="pointer";
  }
  else {
    me.map_.getContainer().style.cursor="default";
  }
};

ChartMapControl.prototype.onMouseOut_ = function(latlng) {
  var me = this;
  if (me.map_.getZoom() > 9) { return; }
  me.setRectangle(-1);
  me.setTitle(-1);
  me.currentChart_ = -1;
  me.map_.getContainer().style.cursor="default";
}


// This positions the green "fixed" rectangle
ChartMapControl.prototype.setCurrentRectangle = function(index) {
  if (index == -1) return;
  var bounds = new GLatLngBounds(new GLatLng(ChartList[index][CHART_SOUTH],
                                             ChartList[index][CHART_WEST]),
                                 new GLatLng(ChartList[index][CHART_NORTH],
                                             ChartList[index][CHART_EAST]));
  if (!this.currentRectangle) {
        this.currentRectangle = new Rectangle(bounds,
                                       1,
                                       "#00CC00",
                                       "#00EE00",
                                       "#00AA00",
                                       "#FFFFFF",
                                       0.75, false
        );
        this.overviewMap_.addOverlay(this.currentRectangle);
  } else {
      this.currentRectangle.setBounds(bounds);
  }
}


// This positions the red "floating" rectangles
ChartMapControl.prototype.setRectangle = function(index) {
  var me = this;
  if (index == -1) {
    if (me.rectangle) {
      me.rectangle.remove();
      me.rectangle = undefined;
      me.rectangleLG.remove();
      me.rectangleLG = undefined;
    }
    return;
  }
  var bounds = new GLatLngBounds(new GLatLng(ChartList[index][CHART_SOUTH],
                                             ChartList[index][CHART_WEST]),
                                 new GLatLng(ChartList[index][CHART_NORTH],
                                             ChartList[index][CHART_EAST]));
  if (!me.rectangle) {
        me.rectangle = new Rectangle(bounds,
                                     2,
                                     "#CC0000",
                                     "#EE0000",
                                     "#AA0000",
                                     "#FF0000",
                                     0.25, false
        );
        me.overviewMap_.addOverlay(me.rectangle);
        me.rectangleLG = new Rectangle(bounds,
                                       2,
                                       "#CC0000",
                                       "#FF0000",
                                       "#AA0000",
                                       "#FF0000",
                                       0.25, false, me.map_.getPane(G_MAP_FLOAT_PANE)
        );
        me.map_.addOverlay(me.rectangleLG);
  } else {
      me.rectangle.setBounds(bounds);
      me.rectangleLG.setBounds(bounds);
  }
}


ChartMapControl.prototype.zoomAndPanTo = function(index,noZoomIn) {
  var me = this;
  var bounds = new GLatLngBounds(new GLatLng(ChartList[index][CHART_SOUTH],
                                             ChartList[index][CHART_WEST]),
                                 new GLatLng(ChartList[index][CHART_NORTH],
                                             ChartList[index][CHART_EAST]));
  var bestZoom = me.map_.getBoundsZoomLevel(bounds);
  var zoom = me.map_.getZoom();
  if (bestZoom<zoom || (bestZoom>zoom && !noZoomIn)) {
    me.map_.setCenter(bounds.getCenter(),bestZoom);
  }
  else {
    me.map_.panTo(bounds.getCenter());
  }
}


// This updates the chart title, either to the chart the cursor 
// is hovering over (in red) or the current chart (in black) if 
// the cursor is not over a chart region.
ChartMapControl.prototype.setTitle = function(index) {
  var me = this;
  if (index == -1) {
    index = me.charts_.getIndex();
    if (index != -1) {
      me.chartTitle_.innerHTML = ChartList[index][CHART_TITLE];
      me.chartTitle_.className = "currentTitle";
    }
  }
  else {
    me.chartTitle_.innerHTML = ChartList[index][CHART_TITLE];
    me.chartTitle_.className = "hoverTitle";
  }
}

ChartMapControl.prototype.onClick_ = function() {
  var me = this;
  if (me.currentChart_ > -1) {
    me.charts_.setCurrent(me.currentChart_,me.chartType_);
    me.setCurrentRectangle(me.currentChart_);
  }
};

ChartMapControl.prototype.onDblClick_ = function() {
  var me = this;
  if (me.currentChart_ > -1) {
    me.charts_.setCurrent(me.currentChart_,me.chartType_);
    me.setCurrentRectangle(me.currentChart_);
    me.zoomAndPanTo(me.currentChart_);
  }
};

ChartMapControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, GSize.ZERO);
};

ChartMapControl.prototype.getSize = function() {
  // This is a real-time updated size measurement,
  // in case we are in the middle of animation:
  return this.visibleSize_;
};


/**
 * Resets the size and position of the overview map & rectangle
 */
ChartMapControl.prototype.reset_ = function() {
  var me = this;
  var map = me.map_;
  if (map.getZoom() > 9) {
    if( !me.disableRectangle ) {
      me.disableRectangle = new Rectangle(me.overviewMap_.getBounds(),
					  0,
					  "#404040",
					  "#404040",
					  "#404040",
					  "#404040",
					  0.75, false
					  );
      me.overviewMap_.addOverlay(me.disableRectangle);
    }
    if (this.currentRectangle) {
      this.currentRectangle.remove();
      this.currentRectangle = undefined;
    }
    me.pickText_.innerHTML = "<a href=\"javascript:zc()\">Zoom out</a> to see charts";
    me.map_.getContainer().style.cursor="default";
    me.chartTitle_.innerHTML = "";
  } else {
    var overviewMap = me.overviewMap_;
    overviewMap.setCenter(new GLatLng(0,0));
    if (!me.gridDrawn) {
      for (var i=0; i<ChartList.length; i++) {
	var bounds = new GLatLngBounds(new GLatLng(ChartList[i][CHART_SOUTH],
						   ChartList[i][CHART_WEST]),
				       new GLatLng(ChartList[i][CHART_NORTH],
						   ChartList[i][CHART_EAST]));
	var rect = new Rectangle(bounds,
				 0,
				 "#0000EE",
				 "#0000EE",
				 "#0000EE",
				 "#0000CC",
				 0.2, false );
	me.overviewMap_.addOverlay(rect);
      }
      me.gridDrawn = true;
    }
    me.setCurrentRectangle(me.charts_.getIndex());
    overviewMap.setMapType(me.map_.getCurrentMapType());
    if (me.disableRectangle) { 
      me.disableRectangle.remove();
      me.disableRectangle = undefined;
    }
    me.pickText_.innerHTML = "Pick a chart:";
    me.setTitle(me.currentChart_);
  }
};


/**
 * Moves the rectangle to the proper position based on the bounds of the main
 * map.
 */
ChartMapControl.prototype.onMapMove_ = function() {
  var me = this;
  if (!me.overviewMap_.isLoaded()) {
    return;
  }

  var mapBounds = me.map_.getBounds();

  // Bugfix for FF/Linux: move without a movestart; simulate a moveend too
  if (!me.mapMoveStartSeen_) {
    me.reset_();
  }
};



/**
 * Show or hide the overview map based on its current state.
 */
ChartMapControl.prototype.showOrHide_ = function() {
  if (this.isHidden()) {
    this.show();
  } else {
    this.hide();
  }
  eventTrigger(this, EVENT_changed);
};


/**
 * Returns true if the overview map is hidden.
 */
ChartMapControl.prototype.isHidden = function() {
  return this.hidden_;
};


/**
 * Expands the overview map if it is currently contracted.
 * @param {Boolean} opt_fast specifies that no animation should occur
 */
ChartMapControl.prototype.show = function() {
  this.hidden_ = false;
  this.setSize(this.size_);

  // Make sure controls are visible:
  this.overviewMap_.showControls();

  // Update position & rectangles:
  this.reset_();
  if (this.copyrightControl_) {
    this.copyrightControl_.monitorMap(this.overviewMap_);
  }
};


/**
 * Contracts the overview map if it is currently expanded.
 * @param {Boolean} opt_fast specifies that no animation should occur
 */
ChartMapControl.prototype.hide = function() {
  this.hidden_ = true;
  this.setSize(GSize.ZERO);
  if (this.copyrightControl_) {
    this.copyrightControl_.cancelMonitorMap(this.overviewMap_);
  }
};


/**
 * Performs the hiding/showing size setting
 * @param {Size} endSize is the final size
 */
ChartMapControl.prototype.setSize = function(endSize) {
  var me = this;

  var tabPanel = me.tabPanel_;
  end = endSize;

  var size = new GSize(end.width, end.height);
  setSize(this.tabPanel_, size);

  // Keep the container in the corner:
  setBottomRight(me.container_, GPoint.ORIGIN);

  me.visibleSize_ = size;

  GEvent.trigger(this, EVENT_resize);
};





/**
 * Public accessor for overview map -- for API users and testing
 */
ChartMapControl.prototype.getChartMap = function() {
  return this.overviewMap_;
};

ChartMapControl.prototype.getAlt_ = function() {
  var me = this;
  return me.isShowApollo() ? MSG_Chart_hide  : MSG_Chart_show;
};

