// Copyright 2007 Google Inc. All Rights Reserved.

/*
** Controls for the charts maps
*/


/**
 */

var HMC_BUTTON_WIDTH_EM = 5;

// These values affect the control position on the map,
// and the button within the control
var HMC_CONTROL_RIGHT_PX = 7;
var HMC_CONTROL_TOP_PX = 7;

var HMC_MARGIN_RIGHT_EM = 16.0;
var HMC_SMALL_MARGIN_TOP_EM = 1.8;
// Used for positioning in IE; see below:
var HMC_SMALL_MARGIN_TOP_IE_MULTIPLIER = 1.2;

// Screen size below which we use the small layout:
var HMC_MEDIUM_SCREEN_WIDTH = 1024;
var HMC_MEDIUM_SCREEN_HEIGHT = 768;

var MSG_charts = "Charts";
var MSG_charts_hide = "Hide Lunar chart overlays";
var MSG_charts_show = "Show Lunar chart overlays";

var ChartList = [
  ["I604", "LAC11", "X",     -50, -20, 64, 48,    168, 281, 306, 380,  171, 241, 326, 379,  "J. Herschel"],
  ["I701", "LAC12", "X",     -20, 10, 64, 48,     215, 331, 303, 381,  214, 283, 326, 378,  "Plato"],
  ["I725", "LAC13", "X",     10, 40, 64, 48,      259, 382, 311, 381,  257, 326, 327, 379,  "Aristoteles"],
  ["I805", "LAC23", "X",     -62, -38, 48, 32,    159, 245, 282, 337,  158, 207, 299, 336,  "R&uuml;mker"],
  ["I602", "LAC24", "X",     -38, -14, 48, 32,    193, 271, 294, 338,  192, 241, 299, 336,  "Sinus Iridum"],
  ["I666", "LAC25", "X",     -14, 10, 48, 32,     227, 303, 290, 338,  226, 275, 299, 336,  "Cassini"],
  ["I705", "LAC26", "X",     10, 34, 48, 32,      262, 344, 281, 337,  260, 309, 299, 336,  "Eudoxus"],
  ["I841", "LAC27", "X",     34, 58, 48, 32,      296, 380, 295, 337,  294, 343, 299, 336,  "Geminus"],
  ["I527", "LAC38", "LM38",  -70, -50, 32, 16,    149, 216, 260, 312,  147, 188, 274, 305,  "Seleucus"],
  ["I465", "LAC39", "LM39",  -50, -30, 32, 16,    177, 245, 262, 307,  176, 216, 274, 305,  "Aristarchus"],
  ["I462", "LAC40", "X",     -30, -10, 32, 16,    206, 269, 265, 307,  204, 245, 274, 305,  "Timocharis"],
  ["I463", "LAC41", "LM41",  -10, 10, 32, 16,     234, 300, 263, 307,  233, 274, 274, 305,  "Montes Apenninus"],
  ["I489", "LAC42", "LM42",  10, 30, 32, 16,      263, 330, 267, 306,  261, 302, 274, 305,  "Mare Serenitatis"],
  ["I799", "LAC43", "X",     30, 50, 32, 16,      291, 362, 264, 307,  290, 330, 275, 305,  "Macrobius"],
  ["I707", "LAC44", "X",     50, 70, 32, 16,      320, 393, 263, 308,  318, 359, 274, 305,  "Cleomedes"],
  ["I491", "LAC56", "X",     -70, -50, 16, 0,     151, 208, 246, 281,  150, 185, 252, 279,  "Hevelius"],
  ["I355", "LAC57", "X",     -50, -30, 16, 0,     180, 231, 242, 281,  178, 213, 252, 279,  "Kepler"],
  ["I515", "LAC58", "X",     -30, -10, 16, 0,     208, 272, 243, 281,  207, 242, 252, 279,  "Copernicus"],
  ["I548", "LAC59", "X",     -10, 10, 16, 0,      236, 301, 241, 282,  235, 270, 252, 279,  "Mare Vaporum"],
  ["I510", "LAC60", "LM60",  10, 30, 16, 0,       264, 322, 243, 281,  264, 299, 252, 279,  "Julius Caesar"],
  ["I722", "LAC61", "X",     30, 50, 16, 0,       293, 359, 244, 281,  292, 327, 252, 279,  "Taruntius"],
  ["I837", "LAC62", "LM62",  50, 70, 16, 0,       322, 383, 245, 281,  320, 356, 252, 279,  "Mare Undarum"],
  ["I740", "LAC74", "X",     -70, -50, 0, -16,    150, 218, 220, 258,  150, 185, 229, 256,  "Grimaldi"],
  ["I385", "LAC75", "X",     -50, -30, 0, -16,    180, 231, 219, 258,  178, 213, 229, 256,  "Letronne"],
  ["I458", "LAC76", "LM76",  -30, -10, 0, -16,    208, 270, 223, 258,  207, 242, 229, 256,  "Riphaeus Mtns."],
  ["I566", "LAC77", "LM77",  -10, 10, 0, -16,     236, 301, 221, 258,  235, 270, 229, 256,  "Ptolemaeus"],
  ["I546", "LAC78", "LM78",  10, 30, 0, -16,      264, 322, 223, 258,  264, 299, 229, 256,  "Theophilus"],
  ["I714", "LAC79", "X",     30, 50, 0, -16,      293, 357, 218, 260,  292, 327, 229, 256,  "Colombo"],
  ["I739", "LAC80", "X",     50, 70, 0, -16,      321, 380, 216, 261,  320, 356, 229, 256,  "Langrenus"],
  ["I755", "LAC92", "X",     -70, -50, -16, -32,  148, 220, 200, 236,  147, 188, 203, 234,  "Byrgius"],
  ["I495", "LAC93", "X",     -50, -30, -16, -32,  176, 242, 194, 235,  176, 216, 204, 234,  "Mare Humorum"],
  ["I485", "LAC94", "X",     -30, -10, -16, -32,  205, 275, 193, 236,  204, 245, 203, 234,  "Pitatus"],
  ["I822", "LAC95", "X",     -10, 10, -16, -32,   233, 308, 198, 236,  232, 273, 203, 234,  "Purbach"],
  ["I690", "LAC96", "X",     10, 30, -16, -32,    263, 333, 191, 236,  261, 302, 203, 234,  "Rupes Altai"],
  ["I720", "LAC97", "X",     30, 50, -16, -32,    291, 367, 194, 235,  290, 330, 203, 234,  "Fracastorius"],
  ["I794", "LAC98", "X",     50, 70, -16, -32,    320, 382, 186, 235,  318, 359, 203, 234,  "Petavius"],
  ["I823", "LAC110","X",     -62, -38, -32, -48,  159, 248, 165, 212,  158, 207, 173, 210,  "Schickard"],
  ["I824", "LAC111","X",     -38, -14, -32, -48,  193, 282, 152, 211,  192, 242, 173, 210,  "Wilhelm"],
  ["I713", "LAC112","X",     -14, 10, -32, -48,   228, 308, 165, 212,  226, 275, 173, 210,  "Tycho"],
  ["I695", "LAC113","X",     10, 34, -32, -48,    260, 343, 156, 211,  260, 310, 173, 210,  "Maurolycus"],
  ["I694", "LAC114","X",     34, 58, -32, -48,    295, 374, 159, 212,  294, 344, 173, 210,  "Rheita"],
  ["I691", "LAC125","X",     -50, -20, -48, -64,  174, 292, 104, 185,  172, 241, 130, 182,  "Schiller"],
  ["I706", "LAC126","X",     -20, 10, -48, -64,   210, 322, 121, 185,  214, 284, 130, 183,  "Clavius"],
  ["I702", "LAC127","X",     10, 40, -48, -64,    259, 361, 125, 184,  257, 327, 130, 183,  "Hommel"]
];

var CHART_GEONAME = 0
var CHART_TOPONAME = 1;
var CHART_WEST = 3;
var CHART_EAST = 4;
var CHART_NORTH = 5;
var CHART_SOUTH = 6;
var CHART_GEOMINX = 7;
var CHART_GEOMAXX = 8;
var CHART_GEOMINY = 9;
var CHART_GEOMAXY = 10;
var CHART_TOPOMINX = 11;
var CHART_TOPOMAXX = 12;
var CHART_TOPOMINY = 13;
var CHART_TOPOMAXY = 14;
var CHART_TITLE = 15;

var CHART_TYPE_GEO = CHART_GEONAME;
var CHART_TYPE_TOPO = CHART_TOPONAME;


/**
 * The Charts object that holds whether the charts layer is showing.
 */
function Charts(mapOverlays) {
  var me = this;

  if (gConfig.getValue("dc")) {
    Charts.prototype.onShowEvent = function() {
      grayOut(true, { message: 
        "Due to an unexpectedly high number of users,<br>" +
        "the charts feature has been temporarily disabled.<br>" +
        "Please check back later today.<p>"+
        "<a href='#'>Click here to continue.</a>" });
      me.hide(0);
    }
    Charts.prototype.onHideEvent = function() { }
  } else {
    me.tileOverlay_ = [];
    for (var i = 0 ; i < ChartList.length ; i++) {
      me.tileOverlay_.push(me.makeTileLayerOverlay({ 
                        location: mapsServer+"charts/geo/"+ChartList[i][CHART_GEONAME],
                        extension: "", maxZoom: 9,
                        minX: ChartList[i][CHART_GEOMINX],
                        maxX: ChartList[i][CHART_GEOMAXX],
                        minY: ChartList[i][CHART_GEOMINY],
                        maxY: ChartList[i][CHART_GEOMAXY] })
                      );


      me.tileOverlay_.push(me.makeTileLayerOverlay({ 
                        location:
                        mapsServer+"charts/lac/"+ChartList[i][CHART_TOPONAME],
                        extension: "", maxZoom: 9,
                        minX: ChartList[i][CHART_TOPOMINX],
                        maxX: ChartList[i][CHART_TOPOMAXX],
                        minY: ChartList[i][CHART_TOPOMINY],
                        maxY: ChartList[i][CHART_TOPOMAXY] })
                      );
    }

    me.setIndex(-1);
    me.setType(CHART_TYPE_GEO);
  }

  /* Set the layer options */
  var opt = {};
  opt.AnchorPosition = G_ANCHOR_TOP_RIGHT;
  opt.ControlPosition = new GSize(HMC_CONTROL_RIGHT_PX, HMC_CONTROL_TOP_PX);
  opt.Name = MSG_charts;
  opt.msgShow = MSG_charts_show;
  opt.msgHide = MSG_charts_hide;
  opt.buttonStyle = { right: px(0) };
  opt.buttonWidth = 5;
  opt.containerStyle = { marginRight: em(HMC_MARGIN_RIGHT_EM) };

  me.setOptions(opt);

}

Charts.prototype = new Layer();
/**
 * Figure out which chart this latlng falls into
 */
Charts.prototype.LatLngToChart = function(latlng) {
  var lat = latlng.lat();
  var lng = latlng.lng();

  if (lat > 64 || lat < -64) return(-1);
  for (var i = ChartList.length-1 ; i >= 0 ; i--) {
    if (lng > 180) {
      lng -= 360;
    }
    if (ChartList[i][CHART_NORTH] >= lat && ChartList[i][CHART_SOUTH] <= lat &&
        ChartList[i][CHART_EAST] >= lng && ChartList[i][CHART_WEST] <= lng) {
        return(i);
    }
  }
  return(-1);
}


/**
 * Compute the center of the given chart region
 */
Charts.prototype.ChartCenter = function(index) {
  return new GLatLng((ChartList[index][CHART_NORTH] + ChartList[index][CHART_SOUTH])/2,
                     (ChartList[index][CHART_EAST]  + ChartList[index][CHART_WEST] )/2);
}

/**
 * Figure out which chart this latlng is nearest to
 */
Charts.prototype.LatLngToNearestChart = function(latlng) {
  var me = this;
  var lat = latlng.lat();
  var lng = latlng.lng();

  var bestIdx = 0;
  var bestDist = latlng.distanceFrom(me.ChartCenter(0));
  for (var i = 1 ; i <ChartList.length ; i++) {
    var dist = latlng.distanceFrom(me.ChartCenter(i));
    if (dist<bestDist) {
      bestIdx = i;
      bestDist = dist;
    }
  }
  return(bestIdx);
}


Charts.prototype.makeTileLayerOverlay = function (options) {
  var cc = new GCopyrightCollection("Chart");
  var bounds = new GLatLngBounds(
    new GLatLng(options.minX, options.minY),
    new GLatLng(options.maxX, options.maxY));
  cc.addCopyright(new GCopyright(1, bounds, 0, "NASA/USGS/LPI"));

  var tilelayer = new GTileLayer(cc, 0, 10);
  tilelayer.isPng = function() { return true };
  tilelayer.getTileUrl = function(tile, zoom) {
    var bound = Math.pow(2, zoom);
    var y = bound-tile.y-1;
    var scale = Math.pow(2,options.maxZoom-zoom);
    if( zoom > options.maxZoom ||
        (tile.x+1)*scale <= options.minX ||
        (y+1)*scale <= options.minY ||
        tile.x*scale > options.maxX ||
        y*scale > options.maxY ) {
      return("http://www.google.com/intl/en_us/mapfiles/transparent.png");
    }
    var url = "http://" + options.location + "/" + zoom + "/" + tile.x + "/" + y +
      options.extension;
    return(url);
  };
  return(new GTileLayerOverlay(tilelayer));
}

Charts.prototype.getTileOverlay_ = function(type, index) {
  var me = this;
  return(me.tileOverlay_[2*index+type]);
}

Charts.prototype.onShowEvent = function() {
  var me = this;
  if (!me.chartMapControl) {
    me.chartMapControl = new ChartMapControl(me);
    me.map_.addControl(me.chartMapControl);
  }

  // We pick and zoom to the nearest chart the first time the user 
  // turns on Charts, so there's no risk of it looking like a no-op.
  if (me.getIndex() == -1) {
    var chart = me.LatLngToNearestChart(me.map_.getCenter());
    me.chartMapControl.zoomAndPanTo(chart,true);
    me.setCurrent(chart,CHART_TYPE_GEO);
  } else {
    me.map_.addOverlay(me.getTileOverlay_(me.getType(), me.getIndex()));
  }

  me.map_.termsDiv_.style.right = "268px";

  GEvent.trigger(me, "stateChanged");

  updatePageUrl();
  updateCopyright();
}

Charts.prototype.onHideEvent = function() {
  var me = this;
  if (me.getIndex() != -1) {
    me.map_.removeOverlay(me.getTileOverlay_(me.getType(), me.getIndex()));
  }

  me.map_.termsDiv_.style.right = "3px";

  GEvent.trigger(me, "stateChanged");

  updatePageUrl();
  updateCopyright();
}

Charts.prototype.setCurrent = function(newIndex,newType) {
  var me = this;
  if (me.isShowing()) {
    var curIndex = me.getIndex();
    var curType = me.getType()

    if (newIndex == curIndex && newType == curType) return;

    if (newIndex > -1) {
      me.map_.addOverlay(me.getTileOverlay_(newType, newIndex));
    }
    if (curIndex != -1) {
      me.map_.removeOverlay(me.getTileOverlay_(curType, curIndex));
    }
  }
  me.setIndex(newIndex);
  me.setType(newType);
  GEvent.trigger(this, "chartChanged");

  updatePageUrl();
}

/* Identify our current chart in a string, so we can get back to this state */
Charts.prototype.getCurrentAsStr = function() {
  return(this.getType() + "," + this.getIndex());
}
/* The incoming string should contains a type,index */
Charts.prototype.setCurrentByStr = function(input) {
  var settings = input.split(",");
  if (settings.length == 2) {
    this.setCurrent( parseInt(settings[1]), parseInt(settings[0]));
    this.show();
  }
}

/* Basic getters and setters  */
Charts.prototype.setIndex = function(newIndex) { this.index_ = newIndex; }
Charts.prototype.setType = function(newType) { this.type_ = newType; }
Charts.prototype.getIndex = function() { return(this.index_); }
Charts.prototype.getType = function() { return(this.type_); }
