// Copyright 2009 Google Inc. All Rights Reserved.

/**
 * @fileoverview Description of this file.
 * @author pamelafox@google.com (Pamela Fox)
 */
var NTSM_Globals;
var preload_cache = [];

google.setOnLoadCallback(function() {
  setupData();
});

function setupData() {
  NTS_setDebug();
  NTS_setEmbed();
  NTS_setLanguage();
  NTS_setUTC(function() {
    NTS_setDifference();
    NTS_setElapsed();
    NTS_setCurrentState();
    NTS_setCurrentIndex();
    params = {
      locations: locations,
      movies: videos,
      hours: NTS_Globals.hoursElapsed,
      minutes: NTS_Globals.minutesElapsed,
      seconds: NTS_Globals.secondsElapsed,
      language: NTS_Globals.language,
      currentIndex: NTS_Globals.index,
      currentState: NTS_Globals.state,
      debug: NTS_Globals.debug,
      embed: NTS_Globals.embed
    }
    trackerMap = new TrackerMap(params);
  });
}

/**
 * @type {LatLng}
 */
TrackerMap.NORTH_POLE = new google.maps.LatLng(84.134424, 172.438477);

/**
 * The index at which Santa begins flying.
 * Previous indices are considered 'pre-flight'.
 * @type {number}
 */
TrackerMap.SANTA_FLIGHT_INDEX = 33;

/**
 * @type {LatLngBounds}
 */
TrackerMap.SANTAS_WORKSHOP = new google.maps.LatLngBounds(
              new google.maps.LatLng(83.359511, 162.421875),
              new google.maps.LatLng(84.607816, 179.296875));

function TrackerMap(params) {
  for (param in params) {
    this[param] = params[param];
  }
  this.worldZoom = 2;
  this.markers = [];
  this.infoWindow = null;

  // Preload infowindow images
  preloadImages('infobox_above.gif', 'infobox_below.gif',
      'infobox_left.gif', 'infobox_right.gif');

  // Create fullscreen action, hide image if in fullscreen mode
  var me = this;
  $('#fullScreenImage').click(function() {
    me.showFullScreen();
  });
  if (window.location.href.indexOf('fullscreen') > -1) {
    $('#fullScreenImage').hide();
  }

  // Create map
  var myOptions = {
    zoom: this.worldZoom,
    center: new google.maps.LatLng(0, 0),
    mapTypeId: google.maps.MapTypeId.SATELLITE
  }
  this.map = new google.maps.Map($('#map_canvas')[0], myOptions);

  // If embedded, display logo control
  if (this.embed == true) {
    this.map.set('scrollwheel', false);
    var embedDiv = $('<div style="z-index: 1000; position: absolute; bottom: 20%; right: 10px;cursor:pointer;"><a target="_blank" href="http://www.noradsanta.org"><img src="images/norad_logo.png"></a></div>');
    $(document.body).append(embedDiv);
  }
  // Update messages with localized text
  $('#currentLocationMessage').html(
     '<b>' + messages.currentLocation[this.language] + '</b>');
  $('#nextLocationMessage').html(
     '<b>' + messages.nextStop[this.language] + '</b>');

  // Make sure to show overlay when we're in north pole area
  var me = this;
  google.maps.event.addListener(this.map, 'bounds_changed', function(e) {
    if (me.map.getZoom() >= 5 &&
        me.map.getBounds().contains(TrackerMap.NORTH_POLE)) {
      if (!me.northPoleOverlay) {
        me.northPoleOverlay = new ImageOverlay(
            'images/santa_workshop.png',
            TrackerMap.SANTAS_WORKSHOP,
            me.map);
      } else {
        me.northPoleOverlay.setVisible(true);
      }
    } else {
      if (me.northPoleOverlay) {
        me.northPoleOverlay.setVisible(false);
      }
    }
  });

  // Let the tracking begin!
  this.startTracker();
}

/**
 * Opens map up in full screen window.
 */
TrackerMap.prototype.showFullScreen = function() {
  window.open(window.location.href + '#fullscreen', '',
      'height=' + screen.height + ',width=' + screen.width +
      ',type=fullWindow, fullscreen=yes, scrollbars=auto');

};

/**
 * Starts tracker.
 */
TrackerMap.prototype.startTracker = function() {
  var me = this;
  if (this.currentState == NTS_Globals.STATE_DURING && this.currentIndex > -1) {
    var currentTime = {
        hours: this.hours,
        minutes: this.minutes,
        seconds: this.seconds
    };
    this.refreshTimer = window.setTimeout(
        function() {me.updateRefresh()},
        this.getRefreshDelay(currentTime));
    this.countdownTimer = window.setInterval(
        function() {me.updateCounter()},
        1000);
    this.addPastLocations();
    this.updateTracker();
    this.updateCounter();
  } else if (this.currentState == NTS_Globals.STATE_BEFORE) {
    $('#follow-status').hide();
    this.map.setCenter(TrackerMap.NORTH_POLE);
    this.map.setZoom(6);
    this.closeInfoWindow();
    this.infoWindow = new google.maps.InfoWindow({
      content: '<b>' + messages.santaPrepping[this.language] + '</b>&nbsp;&nbsp;',
      position: this.map.getCenter()
    });
    this.infoWindow.open(this.map);
    StartCountDown();
  } else { // after or the 1.5 hours at the end of 'during'
    this.currentIndex = locations.length;
    this.addPastLocations();
    this.displayFinal();
  }
};

/**
 * Displays the final message.
 */
TrackerMap.prototype.displayFinal = function() {
  $('#follow-status').hide();
  $('#currentLocationText').text('North Pole, Arctic');
  $('#nextUpdateText').text('2010');
  this.closeInfoWindow();
  this.infoWindow = new google.maps.InfoWindow({
    content: '<b>' + messages.coming[this.language] + '</b>',
    position: this.map.getCenter()
  });
  this.infoWindow.open(this.map);
};

/**
 * Closes any open infowindow.
 */
TrackerMap.prototype.closeInfoWindow = function() {
  if (this.infoWindow) {
    this.infoWindow.close();
  }
};

/**
 * Calculates seconds until it should refresh.
 * @param {Object} currentTime The current time.
 * @return {number} The delay in seconds.
 */
TrackerMap.prototype.getRefreshDelay = function(currentTime) {
  var delay;
  // If we're at the final location, just hardcode to 12 minutes
  if (this.currentIndex == (this.locations.length - 1)) {
    this.secondsLeft = 60 * 12;
    delay = this.secondsLeft * 1000;
  } else {
    var startTime = currentTime || this.getTimeForLocation(this.currentIndex);
    var nextStartTime = this.getTimeForLocation(this.currentIndex + 1);
    delay = this.getSecondsLeft(startTime, nextStartTime) * 1000;
  }
  return delay;
};

/**
 * Gets time for the current location index.
 * @param {number} index The index of the location.
 * @return {Object} An object representing a time.
 */
TrackerMap.prototype.getTimeForLocation = function(index) {
  var location = this.locations[index];
  var timeSplit = location.time.split(':');
  return {
    hours: parseInt(timeSplit[0], 10),
    minutes: parseInt(timeSplit[1], 10),
    seconds: 0
  };
};


/**
 * Moves to next location.
 */
TrackerMap.prototype.updateRefresh = function() {
  this.currentIndex++;
  // If we're past the final location, stop the tracker
  if (this.currentIndex > (this.locations.length - 2)) {
    if (this.markers[this.currentIndex - 1]) {
      this.markers[this.currentIndex - 1].setOptions(
          this.getMarkerOptions(this.currentIndex - 1));
    }
    window.clearInterval(this.countdownTimer);
    window.clearTimeout(this.refreshTimer);
    this.cloudOverlay.setMap(null);
    this.cloudOverlay = null;
    $('#follow-status').hide();
    this.displayFinal();
    return;
  }

  this.updateTracker();
  var me = this;
  this.refreshTimer = window.setTimeout(
     function() {me.updateRefresh()}, me.getRefreshDelay());
};

/**
 * Calculates seconds left between times.
 * @param {Object} startTime The start time.
 * @param {Object} nextStartTime The next start time.
 * @return {number} The seconds left.
 */
TrackerMap.prototype.getSecondsLeft = function(startTime, nextStartTime) {
  var minutesLeft;
  if (startTime.hours == nextStartTime.hours) {
    minutesLeft = nextStartTime.minutes - startTime.minutes;
  } else { // currentTime is less than next start time
    minutesLeft = (60 - startTime.minutes) + nextStartTime.minutes;
  }
  this.secondsLeft = ((minutesLeft * 60) - (startTime.seconds));
  return this.secondsLeft;
};

/**
 * Pads a single digit with zero if needed.
 * @param {number} num The number to pad.
 * @return {string} The modded number.
 */
TrackerMap.prototype.zeroPad = function(num) {
  return (num < 10) ? ('0' + num) : ('' + num);
};

/**
 * Updates counter with time remaining.
 */
TrackerMap.prototype.updateCounter = function() {
  var minutes = Math.floor(this.secondsLeft / 60);
  var seconds = this.secondsLeft - (minutes * 60);
  $('#nextUpdateText').text(
      this.zeroPad(minutes) + ':' + this.zeroPad(seconds));
  if (this.secondsLeft > 0) {
    this.secondsLeft--;
  } else {
    this.secondsLeft = 300;
  }
};

/**
 * Adds past locations to the map.
 */
TrackerMap.prototype.addPastLocations = function() {
  for (var i = 0; i < this.currentIndex; i++) {
    this.createMarker(i);
  }
};

/**
 * Updates current location and adds current marker.
 */
TrackerMap.prototype.updateTracker = function() {
  var currentLocation = this.locations[this.currentIndex];
  $('#currentLocationText').text(currentLocation.full_location);
  var nextLocation = this.locations[this.currentIndex + 1];
  if (nextLocation) {
    $('#nextLocationText').text(nextLocation.full_location);
  }

  // Change icon of old marker to present or video
  if (this.markers[this.currentIndex - 1]) {
    this.markers[this.currentIndex - 1].setOptions(
        this.getMarkerOptions(this.currentIndex - 1));
  }

  // add new marker
  this.createMarker(this.currentIndex);

  // Update cloud overlay
  if (this.cloudOverlay) {
    this.cloudOverlay.setMarkers(this.markers.slice(-7));
  } else if (this.currentIndex > TrackerMap.SANTA_FLIGHT_INDEX) { 
     // moved past north pole
    this.cloudOverlay = new CloudOverlay(this.markers.slice(-7), this.map);
  }

  currentPosition = this.markers[this.currentIndex].getPosition();
  if (this.currentIndex < TrackerMap.SANTA_FLIGHT_INDEX) {
    this.map.setZoom(6);
    this.map.setCenter(currentPosition);
    $('#follow-status').hide();
    $('#preflight-status').show();
    $('#preflight-status-text').text(preflightSceneMessages[this.currentIndex][this.language]);
  } else {
    if (this.currentIndex == TrackerMap.SANTA_FLIGHT_INDEX) {
      // Jitter the actual zoom over a period of slightly less than 4 min
      var jitterMS = Math.floor(Math.random() * 238 * 1000);
      var me = this;
      window.setTimeout(function() {
            me.map.setZoom(me.worldZoom);
          }, jitterMS);
    }
    $('#follow-status').show();
    $('#preflight-status').hide();
    $('#currentLocationText').text(currentLocation.full_location);
    var nextLocation = this.locations[this.currentIndex + 1];
    if (nextLocation) {
      $('#nextLocationText').text(nextLocation.full_location);
    }
  }

  if (this.map.getZoom() <= this.worldZoom) {
    this.map.setCenter(currentPosition);
  }
};

/**
 * Retrieves icon to use for each location.
 * @param {number} index The location index.
 * @return {Object} The MarkerOptions object.
 */
TrackerMap.prototype.getMarkerOptions = function(index) {
  var location = locations[index];
  var level, icon, tooltip;
  if (index == this.currentIndex) {
    tooltip = location.full_location;
    icon = new google.maps.MarkerImage(
      'images/santa.png',
      new google.maps.Size(32, 32),
      new google.maps.Point(0, 0),
      new google.maps.Point(16, 16));
    level = locations.length + 100;
  } else if (location.video != '') {
    tooltip = location.full_location + ' (' + messages.video[this.language] + ')';
    icon = new google.maps.MarkerImage(
      'images/play.png',
      new google.maps.Size(32, 32),
      new google.maps.Point(0, 0),
      new google.maps.Point(16, 16));
    level = locations.length + parseInt(location.video) + 1;
  } else {
    tooltip = location.full_location;
    icon = new google.maps.MarkerImage(
      'images/icon_present_red.png',
      new google.maps.Size(20, 20),
      new google.maps.Point(0, 0),
      new google.maps.Point(10, 10));
    level = index;
  }
  return {icon: icon, zIndex: level, title: tooltip};
};


/**
 * Creates marker for location.
 * @param {number} index The location index.
 */
TrackerMap.prototype.createMarker = function(index) {
  var me = this;

  var location = locations[index];
  var isYoutube = (location.video != '');
  var isPreflight = (location.screenshot != '');

  var latlng = new google.maps.LatLng(location.lat, location.lng);
  var opts = this.getMarkerOptions(index);
  opts.map = me.map;
  opts.position = latlng;
  var marker = new google.maps.Marker(opts);

  google.maps.event.addListener(marker, 'click', function(e) {
    var clickUrl = '';
    var embedUrl = '';
    var width;
    var height;
    var zoomedIn;

    var infoDiv = $('<div></div>');
    infoDiv.css({'text-align': 'center', 'font-size': '14px'});
    infoDiv.html('<center><b>' + location.full_location + '</b></center>');
    function onInfoBoxLoad() {}

    var clickMoreMessage;
    if (isYoutube) {
      clickUrl = 'http://www.noradsanta.org/' + me.language + '/video.html';
      clickMoreMessage = messages.youtubeMore[me.language];
      var youtubeId = me.movies[location.video][me.language];
      infoDiv.append('<object style="position:relative" width="252" height="153"><param name="movie" value="http://www.youtube.com/v/' + youtubeId + '&fs=1&rel=0&showinfo=0"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="window"></param><embed src="http://www.youtube.com/v/' + youtubeId + '&fs=1&rel=0&showinfo=0" type="application/x-shockwave-flash" wmode="window" allowfullscreen="true" width="252" height="153"></embed></object>');
    } else if (isPreflight) {
      clickUrl = me.language + '/track3d.html';
      clickMoreMessage = messages.earthMore[me.language];
      var imgUrl = 'images/preflight_' + location.screenshot + '.jpg';
      var img = $('<img src="' + imgUrl + '" width="240" height="180"/>');
      infoDiv.append(img);
    } else {
      clickUrl = 'http://www.panoramio.com/photo/' + location.panoramio_id;
      clickMoreMessage = messages.panoramioMore[me.language];
      var imgUrl = 'http://mw2.google.com/mw-panoramio/photos/small/' +
          location.panoramio_id + '.jpg';
      var img = $('<img src="' + imgUrl + '" width="240" height="180"/>');
      infoDiv.append(img);
      var authorUrl = 'http://www.panoramio.com/user/' +
          location.panoramio_author_id;
      infoDiv.append('<div class="linkbutton" style="margin:auto; text-align: right; width: 240px;"><a href="' + authorUrl + '">' + location.panoramio_author_name + '</a></div>');
    }

    function makeLink(text, url, id, callback) {
      var id = id || '';
      var div = document.createElement('div');
      div.className = 'linkbutton';
      div.innerHTML = '<a id="' + id + '" target="_blank" href="' + url + '">' + text + '</a>';
      if (callback) {
        div.innerHTML = '<a id="' + id + '" href="javascript:void(0)">' + text + '</a>';
        div.onclick = callback;
      } else {
        div.innerHTML = '<a target="_blank" href="' + url + '">' + text + '</a>';
      }
      infoDiv.append(div);
    }

    // Panoramio or Youtube button
    makeLink(clickMoreMessage, clickUrl);
    infoDiv.append('<br/>');

    // Learn button
    makeLink(messages.learnMore[me.language],
      'http://www.google.com/search?q=site:wikipedia.org+' +
      location.full_location + '&btnI=I\'m+Feeling+Lucky');

    // Zoom buttom
    var defaultMaxZoom = 13;
    if (location.zoom != '') {
      defaultMaxZoom = parseInt(location.zoom, 10);
    }
    var zoomLabel, zoomedIn;
    function calcZoom() {
      if (me.map.getZoom() < defaultMaxZoom) {
        zoomLabel = messages.zoomIn[me.language];
        zoomedIn = false;
      } else {
        zoomLabel = messages.zoomOut[me.language];
        zoomedIn = true;
      }
    }
    calcZoom();

    makeLink(zoomLabel, '#', 'zoomLink', function() {
     // In case zoom changed, re-calculate
     calcZoom();
     if (!zoomedIn) {
        zoomedIn = true;
        me.map.setCenter(latlng);
        me.map.setZoom(defaultMaxZoom);
        $('#zoomLink').html(messages.zoomOut[me.language]);
      } else {
        zoomedIn = false;
        me.map.setCenter(latlng);
        me.map.setZoom(me.worldZoom);
        $('#zoomLink').html(messages.zoomIn[me.language]);
      }
    });

    me.closeInfoWindow();
    me.infoWindow = new InfoBox({position: latlng, map: this.map, content: infoDiv[0]});
    google.maps.event.addListener(me.infoWindow, 'load', onInfoBoxLoad);
  });

  this.markers[index] = marker;
};

/**
 * Preloads an array of images.
 */
function preloadImages() {
  var args_len = arguments.length;
  for (var i = args_len; i--;) {
    var cacheImage = document.createElement('img');
    cacheImage.src = 'images/' + arguments[i];
    preload_cache.push(cacheImage);
  }
}
