// Copyright 2007 Google Inc. All Rights Reserved.

var urlUpdater;

function throttle() { }
function setDefaults() {
  if (!gConfig) {
    gConfig = new Config(window.location.hash.substring(1), 
                      { lat: 3.7,          // map location
                        lon: 10.5,
                        zoom: 4,         // map zoom level
                        map: "apollo",  // maptype
                        snippets: 1,     // show snippets in sidebar
                        apollo: "apollo/1",       // apollo overlay on
                        chart: "",       // chart overlay on
                        q: "" });
  }
  throttle();
}

function loadApplication() {
    // These are our default configuration options.  They can be
    // overriden by parameters in the URL.
    urlUpdater = new urlUpdaterClass();
    setDefaults();
    var curConfig = gConfig;

   if (gConfig.getValue("fail")) {
      grayOut(true, {img:"images/cheese.jpg", opacity: 100, message: 
        "Due to an unexpectedly high number of users,<br>" +
        "Google Moon is unable to load.<br>" +
        "Please check back shortly.<p>", noclick: 1});
      return;
    }

    // Where does the data come from?
    var maps = {};
    maps["apollo"] = {
          location: mapsServer + "apollo",
          name: "Apollo",
          zoomlevels: 20,
          copyright: "NASA / USGS / LPI / ASU",
          caption: "A mosaic of landing site images and a tour of the Apollo landings",
          extension: ".jpg"
    };

    if (!gConfig.getValue("dm")) {
      maps["visible"] = { 
            location: mapsServer + "clem_bw",
            name: "visible",
            zoomlevels: 10,
            copyright: "NASA / USGS",
            caption: "A mosaic of images from the visible portion of the spectrum"
      };
      maps["elevation"] = { 
            location: mapsServer + "terrain", 
            name: "elevation",
            zoomlevels: 8,
            copyright: "NASA / USGS",
            caption: "A shaded relief map colorized by elevation"
      };
    }

    gMaptypes = {};
    var arr = [];
    for (i in maps) {
      gMaptypes[i] = makeMoonMap(maps[i]);
      arr.push(gMaptypes[i]);
    }

    // Create our global map instance, and add the default controls
    gMap = new GMap2($("map"), { mapTypes : arr });
    gMap.addControl(new GLargeMapControl());
    if (!gConfig.getValue("dm")) {
      gMap.addControl(new GMapTypeControl());
    }
    gMap.enableDoubleClickZoom();
    gMap.enableScrollWheelZoom();
    new GKeyboardHandler(gMap);

    makeIcons();

    gMap.addControl(new GScaleControl());
    
    resizeMap();
    gMap.setCenter(
        new GLatLng(curConfig.getValue('lat'), curConfig.getValue('lon')), 
        parseInt(curConfig.getValue('zoom'), 10));

    // Set up classes for search and the search results sidebar
    gMapSearch = new MapSearch(gMap);
    gSidebar = new Sidebar(resizeMap, gMap);
    // Add our custom controls: a caption for mapType and a scalebar
    if (!gConfig.getValue("dm")) makeCustomScalebar();

    // Charts must move these divs out of the way of the controller.
    // Note that this is by no means a rock-solid way of getting the 
    // terms of use div.  We make this alias here so we can fix it 
    // in only one place if it breaks.
    gMap.termsDiv_ = gMap.getContainer().childNodes[1];
    gMap.copyrightSpan_ = document.createElement("span");
    gMap.termsDiv_.insertBefore(gMap.copyrightSpan_,gMap.termsDiv_.firstChild);


    // Handle startup options (either passed in the URL or the defaults)
    //   Open the sidebar before setCenter or it'll be off.
    //   Also setCenter has to happen before any search terms 

    gMap.setCenter(new GLatLng(curConfig.getValue('lat'), 
                               curConfig.getValue('lon')), 
                               parseInt(curConfig.getValue('zoom'), 10),
                               maps[curConfig.getValue('map').toLowerCase()].map);

    /*
    */
    if (!gConfig.getValue("dm")) {
      gCharts = new Charts();
      gMap.addControl(gCharts);
    }

    if (!gConfig.getValue("dc")) {
      if (curConfig.getValue("chart") != "")  {
        gCharts.setCurrentByStr(curConfig.getValue("chart"));
      }
    }

    ApolloLayer = new Apollo(gMap);

    if (curConfig.getValue('map') == "apollo" || curConfig.getValue('map') == "") {
      setTimeout(function() { ApolloLayer.show(true); } ,0);
    }

    // If we're running the promo, and there's no initial config specified,
    // display that balloon by default.
    if (!window.location.hash && window.PROMO_HTML) {
      setTimeout(function() {
        gMap.openInfoWindowHtml(new GLatLng(0,0), PROMO_HTML);
      } ,0);
    } else if (curConfig.getValue("apollo") != "") {
      var path = curConfig.getValue("apollo");
      setTimeout(function() {go(path);} ,0);
    }

    /*
     * Apollo search queries will fail at this point because not all the data
     * has been loaded yet.
     */
    var q = curConfig.getValue("q");
    if (q != "") {
        $("searchtext").value = q;
        doSearch(q);
    }
    urlUpdater.enable();
    updatePageUrl();

    // A few additional actions to provide a nice UI experience.
    $("searchtext").focus();
    GEvent.addListener(gMap, "moveend", updatePageUrl);
    $("mapcaption").innerHTML = maps.apollo.caption;
    GEvent.addListener(gMap, "maptypechanged", function() {
        $("mapcaption").innerHTML = gMap.getCurrentMapType().getCaption();
    });
    GEvent.addListener(gMap, "infowindowclose", function() {
      gConfig.setValue("apollo", "");
    });
    // GEvent.addListener(gMap, "click", showMouseCoordinates,false);

    FirefoxScrollingPatch();
    resizeMap();
}

function showMouseCoordinates(p) {
  if (p) {
    var lat = p.lat().toFixed(3);
    var lng = ((p.lng() + 360)%360).toFixed(3);
    $("readout").innerHTML = lng + ", " + lat + "N";
  }
}


// Make an instance of a MoonMapType.
function makeMoonMap(m) {
    var name = m.name.charAt(0).toUpperCase() + m.name.substr(1);
    var map = new GMapType(
                [new MoonTileLayer(m.location, m.zoomlevels-1, m.copyright, m.extension)],
                new GMercatorProjection(m.zoomlevels),
                name, { shortName: name, 
                        radius: 1738000,
                        errorMessage : "No imagery available at this zoom level.  "+
                        "Try zooming out or "+
                        "<a href='javascript:go(" + '"a11"' + ")'>center</a> "+
                        "on a high-resolution insert."
    } );
    map.getCaption = function() { return m.caption; };
    map.copyright = m.copyright;
    m.map = map;
    return(map);
};

// Add a custom scalebar for just the elevation map
function makeCustomScalebar() {
    var scalebar = new Scalebar(document,
               [-8.9, 8], 
               [-8, -6, -4, -2, 0, 2, 4, 6, 8], "km");
    gMap.getContainer().appendChild(scalebar.getContainer());
    // Check if we have the right maptype yet
    if (gMap.getCurrentMapType().getName().toLowerCase() != "elevation") {
      scalebar.hide();
    }
    // Set up listener to show/hide the scalebar on map change.
    GEvent.addListener(gMap, "maptypechanged", function() {
        var name = gMap.getCurrentMapType().getName();
        if (name.toLowerCase() == "elevation") {
            scalebar.show();
        } else {
            scalebar.hide();
        }
    });
}

function urlUpdaterClass() { this.enabled = 0; }
urlUpdaterClass.prototype.enable = function () { this.enabled = 1; }
urlUpdaterClass.prototype.isEnabled = function () { return(this.enabled); }

// makeUrl - create a url that will get the application back 
//           to its current state, for bookmarking.
urlUpdaterClass.prototype.makeUrl = function() {
  gConfig.setValues({
      lat:      formatFloat(gMap.getCenter().lat(), 6)
      , lon:      formatFloat(gMap.getCenter().lng(), 6)
      , zoom:     gMap.getZoom()
      , map:      gMap.getCurrentMapType().getName().toLowerCase()
      , snippets: gConfig.getValue("snippets")
      , chart:    gCharts ? (gCharts.isShowing() ? gCharts.getCurrentAsStr() : "") : ""
      , q:        gSidebar.isOpen() ? gMapSearch.lastSearchQuery : ""
      });
  /*
   *
  if (!ApolloLayer.isShowing()) {
    gConfig.setValue("apollo", "")
  } else if (gMap.getInfoWindow().isHidden()) {
    gConfig.setValue("apollo", "apollo");
  }
  */

  var loc = window.location.href;
  // Truncate any existing parameters
  loc = loc.replace(/[?#]+.*/,"");
  return(loc + "#" + gConfig.getChanged().join("&"));
}

function updatePageUrl(opt_key, opt_val) {
  if (opt_key) {
    gConfig.setValue(opt_key, opt_val);
  }

  if (urlUpdater.isEnabled()) {
    if ($("link")) $("link").href = urlUpdater.makeUrl();
  }
}

// Resize the UI components because something's been opened or closed
function resizeMap() {
    var map = $("map");
    var sidebar = $("sidebar");
    var iconpanel = $("iconpanel");
    var page = $("page");

    var panelState = 0;
    var sidebarState = 0;

    /* compute our expected state */
    if (ApolloLayer) {
      panelState = ApolloLayer.isShowing();
    }
    if (gSidebar) {
      sidebarState = gSidebar.isOpen();
    }
    var height = getWindowHeight() - getPosition(map).top;
    var width = getWindowWidth();
    var sidebarWidth = getPosition(sidebar).width;

    var mapheight = height - (panelState ? APOLLO_ICONPANEL_HEIGHT : 0);
    var mapwidth = width - (sidebarState ? sidebarWidth : 0);
    var mapleft = sidebarState ? sidebarWidth +10 : 0;

    /* try setting everything's size: */
    map.style.height = px(mapheight);
    map.style.width = px(mapwidth);
    map.style.left = px(mapleft);
    if (gSidebar) {
      sidebar.height = px(mapheight);
    }

    if (gMap) gMap.checkResize();
    if (gSidebar) gSidebar.resize();
    // if (location) gMap.setCenter(location);
}


// Do everything necessary to execute a search query.
function doSearch(queryText) {
    if (!queryText) queryText = htmlEscape($("searchtext").value);
    var results = gMapSearch.doSearch(queryText);

    gSidebar.open();
    gSidebar.displaySearchResults(queryText, 
                                  results,
                                  gConfig.getValue("snippets"),
                                  gMap.getBounds());
    updatePageUrl();
}
function q(queryText) {
    $("searchtext").value = queryText;
    doSearch();
}

// These functions are used in various places as the href on HTML links
// or in places where one of the globals in this file is needed.
//
// (un)limit search to the current window bounds
function limit() { gSidebar.limitSearch(); }
function unlimit() { gSidebar.unlimitSearch(); }
// close the sidebar.  Used in the sidebar's close button's html
function closeSidebar() { gSidebar.close(); }
// open a specific marker.  Used in the sidebar's result's html links
function openMarker(i) { gSidebar.openMarker(i); }
// Show a page.  Used in the sidebar's paging controls.
function showPage(index, dir) {
    gSidebar.showPage(index, dir, gConfig.getValue("snippets"));
}
function center(lat,lon) {
	if (arguments.length == 1) gMap.panTo(lat);
	else gMap.panTo(new GLatLng(lat, lon));
}
function zoomto(zoom) {
  gMap.setZoom(zoon);
}


var marker_icons = {};

function makeIcons() {
  var colors = [ "red", "blue", "green", "yellow", "orange" ];

  for (var i = 0 ; i < colors.length ; i++) {
    var c = colors[i];
    var icon = new GIcon();
    icon.image = 'http://labs.google.com/ridefinder/images/mm_20_' + c + '.png';
    icon.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
    icon.iconSize = new GSize(12, 20);
    icon.shadowSize = new GSize(22, 20);
    icon.iconAnchor = new GPoint(6, 20);
    icon.infoWindowAnchor = new GPoint(5, 1);

    marker_icons[c] = icon;
  }
}

function closeIPF() {
  ApolloLayer.hide();
  gMap.setMapType(gMaptypes["visible"]);
}
function go(path) { openInfoWindow(path); }  
function iw(path) { openInfoWindow(path); }  
function openInfoWindow(path) {
  ApolloLayer.go(path);
}

/*
** A nasty hack to get around the firefox infowindow overflow bug
*/
function FirefoxScrollingPatch() {
  if (gBrowser.type == BROWSER_FIREFOX) {
    GEvent.addListener(gMap, "movestart", IWHideScrollBars);
    GEvent.addListener(gMap, "moveend", IWShowScrollBars);
  }
}

function IWShowScrollBars() {
  var iw = gMap.getInfoWindow().getContentContainers()[0];
  if (iw) {
    var body = getChildByClass(iw, "Ainfo_body")
    if (body) {
      var scrollTop = body.scrollTop;
      body.style.overflow = "auto";
      body.scrollTop = scrollTop
    }
  }
}
function IWHideScrollBars() {
  var iw = gMap.getInfoWindow().getContentContainers()[0];
  if (iw) {
    var body = getChildByClass(iw, "Ainfo_body")
    if (body) {
      var scrollTop = body.scrollTop;
      body.style.overflow = "hidden";
      body.scrollTop = scrollTop
    }
  }
}

