var ge;
var currentTourKmlObject = null; // a KmlTour object
var currentFetchedKmlObject = null; // the original fetchKml'd target
var currentTourIndex = -1;
var currentExtraKmlsObject = null;
var loadingOverlay = null;

var appPath = document.location.href.replace(/\/[^\/]*$/, '/');

/**
 * Init function called when the DOM is ready.
 */
function init() {
  if (!checkTourHash()) {
    loadPlugin('earth', function() {
      if (loadingOverlay)
        loadingOverlay.setVisibility(false);
    });
  }

  // Generate the tour selection list.
  var tourListNode = document.getElementById('tourlist');
  for (var i = 0; i < tourList.length; i++) {
    var tour = tourList[i];

    // Create the tour link and its container.
    var linkNode = document.createElement('LI');
    linkNode.id = 'tourind-' + i;

    // Handle clicks on the tour links.
    linkNode.onclick = (function(tourIndex) {
      return function(e) {
        document.location.hash = '#' + tourList[tourIndex].id;
        loadTour(tourIndex);
      };
    })(i);

    var thumbnailNode = document.createElement('IMG');
    thumbnailNode.src = tour.thumbnail;
    linkNode.appendChild(thumbnailNode);

    var titleNode = document.createElement('SPAN');
    titleNode.className = 'title';
    titleNode.innerHTML = tour.title;
    linkNode.appendChild(titleNode);

    if (tour.duration) {
      var metaNode = document.createElement('SPAN');
      metaNode.className = 'meta';
      metaNode.innerHTML = '&nbsp;(' + tour.duration + ')';
      titleNode.appendChild(metaNode);
    }

    if (tour.narrator) {
      var narratorNode = document.createElement('SPAN');
      narratorNode.className = 'narrator';
      narratorNode.innerHTML = tour.narrator;
      linkNode.appendChild(narratorNode);
    }

    tourListNode.appendChild(linkNode);
  }

  // Hide the 'Loading' message and show the tourList list.
  document.getElementById('tourlist_status').style.display = 'none';
  document.getElementById('tourlist_container').style.display = '';

  // Watch the document location hash for changes.
  window.setInterval(checkTourHash, 100);
  
  // Watch for resume tour clicks
  window.setInterval(checkResumeButton, 100);
  
  if (navigator.userAgent.indexOf('MSIE 6') >= 0)
    window.setInterval(pngFix, 100);
}

function pngFix() {
  var imgs = document.getElementsByTagName('img');
  for (var i = 0; i < imgs.length; i++) {
    if (imgs[i].src.match(/.png$/)) {
      imgs[i].style.width = imgs[i].clientWidth + 'px';
      imgs[i].style.height = imgs[i].clientHeight + 'px';
      imgs[i].style.filter =
          "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
          imgs[i].src + "', sizingMethod='scale')";
      imgs[i].src = 'http://www.gstatic.com/news/img/cleardot.gif';
    }
  }
}

/**
 * Helper function for element.addEventListener/attachEvent
 */
function addDomListener(element, eventName, listener) {
  if (element.addEventListener)
    element.addEventListener(eventName, listener, false);
  else if (element.attachEvent)
    element.attachEvent('on' + eventName, listener);
}

/**
 * Sets up listeners on 'resume tour' buttons in tour balloons.
 */
function checkResumeButton() {
  var resumeButton = document.getElementById('resume-button');
  if (resumeButton && !resumeButton.getAttribute('hasResumeListener')) {
    addDomListener(resumeButton, 'click', function(evt) {
      ge.getTourPlayer().play();
      
      if (evt.preventDefault) {
        evt.preventDefault();
        evt.stopPropagation();
      }
      return false;
    });
    
    
    resumeButton.setAttribute('hasResumeListener', true);
  }
}

/**
 * Check the document location hash/anchor and load the requested tour
 * if the anchor changes.
 * @return Returns true if the hash has changed and a new tour is loading, and
 *     false otherwise.
 */
function checkTourHash() {
  var destID = document.location.hash.match(/(\w+)/);
  if (destID)
    destID = destID[1];

  if (destID && (currentTourIndex < 0 ||
                 destID != tourList[currentTourIndex].id)) {

    // Find the tour with this ID.
    var destTourIndex = -1;
    for (var i = 0; i < tourList.length; i++) {
      if (tourList[i].id == destID) {
        destTourIndex = i;
        break;
      }
    }

    // Select the tour and open it up.
    if (destTourIndex >= 0) {
      loadTour(destTourIndex);
      return true;
    }
  }

  return false;
}

/**
 * Load the Google Earth Plugin instance, deleting any existing instance.
 * @param {string} mapType The planet type to load (either 'mars' or 'earth').
 */
function loadPlugin(mapType, callback) {
  google.earth.createInstance('map3d', function(pluginInstance) {
    ge = pluginInstance;
    ge.getWindow().setVisibility(true);
    ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);

    // Create the loading overlay.
    var loadingImage = ge.createIcon('');
    loadingImage.setHref(appPath + 'images/loading.png');

    loadingOverlay = ge.createScreenOverlay('');
    loadingOverlay.setIcon(loadingImage);
    loadingOverlay.getOverlayXY().set(
        25, ge.UNITS_PIXELS, 25, ge.UNITS_INSET_PIXELS);
    loadingOverlay.getScreenXY().set(
        0, ge.UNITS_FRACTION, 1, ge.UNITS_FRACTION);
    loadingOverlay.getSize().set(-1, ge.UNITS_FRACTION, -1, ge.UNITS_FRACTION);
    ge.getFeatures().appendChild(loadingOverlay);

    // Load default view.
    var lookAt = ge.createLookAt('');
    lookAt.set(0.5, 0.5, 0, ge.ALTITUDE_RELATIVE_TO_GROUND,
        0, 0, 7000000);
    ge.getView().setAbstractView(lookAt);

    if (callback) {
      callback.call(null);
    }
  }, function(errorCode) {
    if (errorCode == 'ERR_NOT_INSTALLED' ||
        errorCode == 'ERR_CREATE_PLUGIN' && !google.earth.isInstalled()) {
      document.getElementById('tourlist_status').innerHTML =
          'To tour the world in your browser, you must first install the ' +
          'Google Earth Plugin by clicking the download link to the right.';
    } else {
      document.getElementById('tourlist_status').className = 'error';
      document.getElementById('tourlist_status').innerHTML =
          'There was an error loading the touring application.';
    }
  }, (mapType == 'mars' ?
         { database: 'http://khmdb.google.com/?db=mars' } : {}));
}

/**
 * Load the given tour and begin playback, stopping any currently playing tours.
 * Also selects the link to the tour and scrolls the link into view.
 */
function loadTour(tourIndex) {
  if (currentTourIndex == tourIndex)
    return;

  // Deselect the currently playing tour's link.
  var oldTourIndex = currentTourIndex;
  if (currentTourIndex >= 0) {
    document.getElementById('tourind-' + oldTourIndex).className = '';
    currentTourIndex = -1;
  }

  // Mark the link as selected and scroll it into view.
  var linkNode = document.getElementById('tourind-' + tourIndex);
  if (!linkNode)
    return;

  linkNode.className = 'selected';
  if ('linkNode' in linkNode)
    linkContainerNode.scrollIntoView(false);

  currentTourIndex = tourIndex;

  // Set up the embed link.
  //resetEmbedLink(currentTourIndex);

  // Reload the plugin if necessary.
  if (!ge) {
    // Destroy the existing plugin.
    // TODO(romannurik): assess the implications of this
    ge = null;
    document.getElementById('map3d').innerHTML = '';

    currentFetchedKmlObject = null;
    loadingOverlay = null;

    loadPlugin(tourList[currentTourIndex].mapType, continueLoadTour_);
  } else {
    if (loadingOverlay)
      loadingOverlay.setVisibility(true);

    continueLoadTour_(null);
  }
}

/**
 * Continuation function for loadTour()
 */
function continueLoadTour_() {
  // Stop any currently playing tour.
  if (currentTourKmlObject) {
    //ge.getTourPlayer().reset();
    ge.getTourPlayer().setTour(null);
  }

  // Turn on/off extra layers.
  /*if (tourList[currentTourIndex].options) {
    ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS,
        tourList[currentTourIndex].options.buildings ? true : false);
  }*/
  
  ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS, true);
  ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
  ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);

  // Load the first (or tourNumber'th) <gx:Tour> in the tour's KML URL.
  var tourNumber = tourList[currentTourIndex].tourNumber || 1;
  var tourIndexAtFetch = currentTourIndex;

  google.earth.fetchKml(
    ge,
    tourList[currentTourIndex].url,
    function(kmlObject) {
      if (!kmlObject) {
        // TODO(romannurik): non-obtrusive error.
        return;
      }

      // If the user clicks a different tour while this one is being fetched,
      // cancel the loading of this tour.
      if (tourIndexAtFetch != currentTourIndex) {
        return;
      }

      if (currentFetchedKmlObject) {
        ge.getFeatures().removeChild(currentFetchedKmlObject);
        currentFetchedKmlObject = null;
      }

      currentFetchedKmlObject = kmlObject;
      ge.getFeatures().appendChild(currentFetchedKmlObject);

      // Walk the loaded KML object hierarchy looking for a <gx:Tour>.
      walkKmlDom(kmlObject, function(context) {
        if (this.getType() == 'KmlTour' && !--tourNumber) {
          ge.getTourPlayer().setTour(this);

          // Hide the loading overlay.
          if (loadingOverlay)
            loadingOverlay.setVisibility(false);

          ge.getTourPlayer().play();

          currentTourKmlObject = this;
          return false;
        }
      });
      
      // Remove any existing extra KMLs folder.
      if (currentExtraKmlsObject) {
        ge.getFeatures().removeChild(currentExtraKmlsObject);
        currentExtraKmlsObject = null;
      }
      
      // Load any extra KML files necessary to view this tour into a new
      // folder.
      var extraKmls = tourList[currentTourIndex].extraKmls || [];
      var currentExtraKmlsObject = ge.createFolder('');
      ge.getFeatures().appendChild(currentExtraKmlsObject);
      
      for (var i = 0; i < extraKmls.length; i++) {
        // Create a network link to this extra KML file
        // and place it in the extra KMLs folder.
        var link = ge.createLink('');
        link.setHref(extraKmls[i]);
        
        var networkLink = ge.createNetworkLink('');
        networkLink.setLink(link);
        
        currentExtraKmlsObject.getFeatures().appendChild(networkLink);
      }
    }
  );
}
