google.load("gdata", "1");
google.load("maps", "2")
google.setOnLoadCallback(initializePage);

var map;
var icons = [];                      // Array of google.maps.Icons indexed by event type.
var states;                          // Array of states ordered by database ID; range complete.
var addresses;                       // Array of addresses ordered by database ID.
var addresses_by_id = new Object();  // Hash of addresses keyed by database ID.
var events;                          // Array of events ordered by ascending start date.
var first_upcoming_event_index = -1; // Index into events array of the first upcoming event.
var events_by_id = new Object();     // Hash of events keyed by database ID.
var EVENT_TYPE_ID_EVENT = 1;
var EVENT_TYPE_ID_BLOG_POST = 2;
var EVENT_TYPE_ID_VIDEO_POST = 3;
var EVENT_TYPE_ID_RV_LOCATION = 4;
var EVENT_TYPE_ID_SUGGESTED_STOP = 5;
var WEEKDAY_ABBREVIATION = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
var MONTH_ABBREVIATION = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var TODAY = new Date();
var COLOR_PAST = '#ED1E24';
var COLOR_UPCOMING = '#6DE8A5';
var debug = false;

function initializeMap() {
  map = new google.maps.Map2(document.getElementById('map-large'));
  map.setCenter(new google.maps.LatLng(37,-97), 4);
  map.addControl(new google.maps.LargeMapControl());
  map.addControl(new google.maps.MapTypeControl());

  // Create custom icons.
  var icon_event = new google.maps.Icon();
  icon_event.image = "http://www.coveramericatour.org/images/gicons/pushpin.png";
  icon_event.iconSize = new google.maps.Size(14, 26);
  icon_event.shadow = "http://www.coveramericatour.org/images/gicons/pushpin-shadow.png";
  icon_event.shadowSize = new google.maps.Size(21, 26);
  icon_event.iconAnchor = new google.maps.Point(7, 26);
  icon_event.infoWindowAnchor = new google.maps.Point(7, 1);
  icon_event.transparent = "http://www.coveramericatour.org/images/gicons/pushpin-transparent.png";
  icon_event.printImage = "http://www.coveramericatour.org/images/gicons/pushpin.gif";
  icon_event.mozPrintImage = "http://www.coveramericatour.org/images/gicons/pushpin-moz-image.gif";
  icons[EVENT_TYPE_ID_EVENT] = icon_event;

  var icon_blog_post = new google.maps.Icon();
  icon_blog_post.image = "http://www.coveramericatour.org/images/gicons/talk-bubble.png";
  icon_blog_post.iconSize = new google.maps.Size(26, 21);
  icon_blog_post.shadow = "http://www.coveramericatour.org/images/gicons/talk-bubble-shadow.png";
  icon_blog_post.shadowSize = new google.maps.Size(32, 22);
  icon_blog_post.iconAnchor = new google.maps.Point(19, 21);
  icon_blog_post.infoWindowAnchor = new google.maps.Point(13, 1);
  icon_blog_post.transparent = "http://www.coveramericatour.org/images/gicons/talk-bubble-transparent.png";
  icon_blog_post.printImage = "http://www.coveramericatour.org/images/gicons/talk-bubble.gif";
  icon_blog_post.mozPrintImage = "http://www.coveramericatour.org/images/gicons/talk-bubble-moz-image.gif";
  icons[EVENT_TYPE_ID_BLOG_POST] = icon_blog_post;

  var icon_video = new google.maps.Icon();
  icon_video.image = "http://www.coveramericatour.org/images/gicons/video.png";
  icon_video.iconSize = new google.maps.Size(26, 27);
  icon_video.shadow = "http://www.coveramericatour.org/images/gicons/video-shadow.png";
  icon_video.shadowSize = new google.maps.Size(38, 27);
  icon_video.iconAnchor = new google.maps.Point(13, 27);
  icon_video.infoWindowAnchor = new google.maps.Point(13, 1);
  icon_video.transparent = "http://www.coveramericatour.org/images/gicons/video-transparent.png";
  icon_video.printImage = "http://www.coveramericatour.org/images/gicons/video.gif";
  icon_video.mozPrintImage = "http://www.coveramericatour.org/images/gicons/video-moz-image.gif";
  icons[EVENT_TYPE_ID_VIDEO_POST] = icon_video;

  var icon_rv = new google.maps.Icon();
  icon_rv.image = "http://www.coveramericatour.org/images/gicons/rv-simple.png";
  icon_rv.iconSize = new google.maps.Size(35, 19);
  icon_rv.shadow = "http://www.coveramericatour.org/images/gicons/rv-simple-shadow.png";
  icon_rv.shadowSize = new google.maps.Size(53, 20);
  icon_rv.iconAnchor = new google.maps.Point(17, 19);
  icon_rv.infoWindowAnchor = new google.maps.Point(17, 1);
  icon_rv.transparent = "http://www.coveramericatour.org/images/gicons/rv-transparent.png";
  icon_rv.printImage = "http://www.coveramericatour.org/images/gicons/rv-simple.gif";
  icon_rv.mozPrintImage = "http://www.coveramericatour.org/images/gicons/rv-moz-image.gif";
  icons[EVENT_TYPE_ID_RV_LOCATION] = icon_rv;

  var icon_suggested = new google.maps.Icon();
  icon_suggested.image = "http://www.coveramericatour.org/images/gicons/suggested.png";
  icon_suggested.iconSize = new google.maps.Size(23, 25);
  icon_suggested.shadow = "http://www.coveramericatour.org/images/gicons/suggested-shadow.png";
  icon_suggested.shadowSize = new google.maps.Size(23, 25);
  icon_suggested.iconAnchor = new google.maps.Point(10, 19);
  icon_suggested.infoWindowAnchor = new google.maps.Point(10, 1);
  icon_suggested.transparent = "http://www.coveramericatour.org/images/gicons/suggested-transparent.png";
  icon_suggested.printImage = "http://www.coveramericatour.org/images/gicons/suggested.gif";
  icon_suggested.mozPrintImage = "http://www.coveramericatour.org/images/gicons/suggested-moz-image.gif";  
  icons[EVENT_TYPE_ID_SUGGESTED_STOP] = icon_suggested;
}


// Retrieve state, address, and event information as JSON objects.  Requests are processed
// in parallel with the aid of the utility functions in ajax_utilities.js.
function initializeData(){
  initialize_data_ready_states([ 'STATES', 'ADDRESSES', 'EVENTS' ]);

  $.getJSON('/js/states.json', function(json){
    states = json;
    if( data_is_ready('STATES', true) )  processEvents();
  });
  
  $.getJSON('/data/addresses?format=json', function(json){
    addresses = json;
    var current_address;
    for ( var address_index = 0; address_index < addresses.length; address_index++ ) {
      current_address = addresses[address_index];
      addresses_by_id[addressKey(current_address.id)] = current_address;
    }
    if( data_is_ready('ADDRESSES', true) )  processEvents();
  });
  
  $.getJSON('/data/events?format=json', function(json){
    events = json;
    var current_event;
    for ( var event_index = 0; event_index < events.length; event_index++ ) {
      current_event = events[event_index];
      events_by_id[eventKey(current_event.id)] = current_event;
      
      // Create JavaScript dates for starts_at and ends_at date strings.
      if( current_event.starts_at != null )  current_event.starts_at_date = new Date(current_event.starts_at);
      if( current_event.ends_at   != null )  current_event.ends_at_date   = new Date(current_event.ends_at);
    }
    if( data_is_ready('EVENTS', true) )  processEvents();
  });
}


function initializePage() {
  initializeMap();
  initializeData();
}


function addressKey(id){ return 'address_' + id; }
function eventKey(id){ return 'event_' + id; }


// Iterate through the collection of events and add an appropriate placemark for each one.
function processEvents() {
  var current_event;
  // Prepare the data.
  for ( var event_index = 0; event_index < events.length; event_index++ ) {
    // Create a google.maps.LatLng object for each event location.
    current_event = events[event_index];
    var address = addresses_by_id[addressKey(current_event.address_id)];
    current_event.point = new google.maps.LatLng(address.latitude, address.longitude);
  }
  
  // Process each event.
  for ( var event_index = 0; event_index < events.length; event_index++ ) {
    // Add route lines between adjacent displayed events.
    current_event = events[event_index];
    if( (current_event.displayed_on_route == 1) && (event_index < events.length - 1) ){
      for( var next_event_index = event_index + 1; next_event_index < events.length; next_event_index++ ){
        next_event = events[next_event_index];
        if( next_event.displayed_on_route == 1 ){
          addRouteLine(current_event, next_event);
          break;
        }
      }
    }
    
    // Skip RV event types for now as we'll only display the last one.
    if( current_event.event_type_id != EVENT_TYPE_ID_RV_LOCATION ){
      // Place a marker on the map for the event and add the event to the event list.
      addMarker(current_event);
      addEventListing(current_event);
    }
  }
  
  // Place a marker on the map for the most recent RV location.
  for ( var event_index = events.length - 1; event_index >= 0; event_index-- ) {
    current_event = events[event_index];
    if( current_event.event_type_id == EVENT_TYPE_ID_RV_LOCATION ){
      addMarker(current_event);
      break;
    }
  }
  
  // Update the event list footers.
  var total_events = events.length;
  for ( var event_index = events.length - 1; event_index >= 0; event_index-- ) {
    current_event = events[event_index];
    if( current_event.event_type_id == EVENT_TYPE_ID_RV_LOCATION )  total_events--;
  }
  $('.events-table-footer-total_number').html(total_events);
  updateEventListingFooters();
  
  // Stripe the tables.
  stripeTables();
}


// Place a polyline on the map between the given events.
function addRouteLine(current_event, subsequent_event){
  var route_color;
  var current_event_in_range = compareDates(current_event.starts_at_date, TODAY);
  var subsequent_event_in_range = compareDates(subsequent_event.starts_at_date, TODAY);

  if( current_event_in_range == 1 ){ route_color = COLOR_UPCOMING; }
  else if( subsequent_event_in_range == -1 ){ route_color = COLOR_PAST; }
  else { route_color = COLOR_UPCOMING; }

  // Draw the route line.
  var polyline = new google.maps.Polyline([ current_event.point, subsequent_event.point ], 
      route_color, 5, 0.75);
  map.addOverlay(polyline);
}


// Place a marker on the map for the given event.
function addMarker(current_event){
  var options = { icon: icons[current_event.event_type_id] };
  var marker = new google.maps.Marker(current_event.point, options);

  // Build the information window output.
  var output = '<div class="marker-container">\n';
  output += eventString(current_event);
  if( current_event.event_type_id == EVENT_TYPE_ID_SUGGESTED_STOP &&
      current_event.description != null ){
    output += "\n<br/>\n";
    output += current_event.description;
  }
  output += '</div>';

  marker.bindInfoWindowHtml(output);
  map.addOverlay(marker);

  // Store the marker with the event.
  current_event['marker'] = marker;
}


// Add the given event to the appropriate Event Listing table.
function addEventListing(current_event){
  current_event.event_type_id == EVENT_TYPE_ID_SUGGESTED_STOP ?
      addSuggestedStopListing(current_event) :
      addCalendarListing(current_event);
}

// Add the given event to the Past Events table.
function addCalendarListing(current_event) {
  var td_event_name = document.createElement('td');
  td_event_name.innerHTML = current_event.name;

  var td_event_date = document.createElement('td');
  td_event_date.innerHTML = current_event.starts_at != null ? dateString(current_event.starts_at_date) : 'N/A'

  var td_event_location = document.createElement('td');
  td_event_location.innerHTML = eventLocationString(current_event);

  var tr = document.createElement('tr');
  tr.id = eventKey(current_event.id);
  tr.className = 'event_past'
  
  // Show the marker's information window on the map when the row is clicked.
  tr.onclick = function(){ showDetail(this); };

  var table_body = document.getElementById('events-past-table-body');
  tr.appendChild(td_event_name);
  tr.appendChild(td_event_date);
  tr.appendChild(td_event_location);
  table_body.appendChild(tr);

  // Add the table row to the event.
  current_event['tr'] = tr;
}


// Add the given event to the Suggested Stop table.
function addSuggestedStopListing(current_event) {
  var td_event_name = document.createElement('td');
  td_event_name.innerHTML = current_event.name;

  var td_event_location = document.createElement('td');
  td_event_location.innerHTML = eventLocationString(current_event);

  var td_event_description = document.createElement('td');
  td_event_description.innerHTML = current_event.description != null ? current_event.description : 'N/A'

  var tr = document.createElement('tr');
  tr.id = eventKey(current_event.id);

  // Show the marker's information window on the map when the row is clicked.
  tr.onclick = function(){ showDetail(this); };

  var table_body = document.getElementById('events-suggested-table-body');
  tr.appendChild(td_event_name);
  tr.appendChild(td_event_location);
  tr.appendChild(td_event_description);
  table_body.appendChild(tr);

  // Add the table row to the event.
  current_event['tr'] = tr;
}


// Display details about the selected event.
function showDetail(current_row) {
  current_event = events_by_id[current_row.id];
  google.maps.Event.trigger(current_event.marker, 'click');
  map.panTo(current_event.point);
}


// Update the display of the Event Listing footers.
function updateEventListingFooters() {
  var current_event;
  
  // Calculate the number of currently displayed past events.
  var displayed_events = 0;
  for( var event_index = 0; event_index < events.length; event_index++ ){
    current_event = events[event_index];
    if( current_event.event_type_id == EVENT_TYPE_ID_RV_LOCATION )     continue;
    if( current_event.event_type_id == EVENT_TYPE_ID_SUGGESTED_STOP )  continue;
    if( ! current_event.marker.isHidden() )  displayed_events = displayed_events + 1;
  }
  $('#events-past-table-footer-current_number').html(displayed_events);
  
  // Calculate the number of currently displayed suggested stops.
  displayed_events = 0;
  for( var event_index = 0; event_index < events.length; event_index++ ){
    current_event = events[event_index];
    if( current_event.event_type_id == EVENT_TYPE_ID_SUGGESTED_STOP ){
      if( ! current_event.marker.isHidden() )  displayed_events = displayed_events + 1;
    }
  }
  $('#events-suggested-table-footer-current_number').html(displayed_events);
}


// Filter display of map overlays.  event_type_id 0 is "Everything!"
function filterDisplay(event_type_id, display) {
  var current_event;
  for( var event_index = 0; event_index < events.length; event_index++ ){
    current_event = events[event_index];
    if( (event_type_id == 0) || (current_event.event_type_id == event_type_id ) ){
      if( current_event.marker && current_event.tr ){
        if( display ){
          current_event.marker.show();
          current_event.tr.style.display = '';
        }
        else {
          current_event.marker.hide();
          current_event.tr.style.display = 'none';
        }
      }
    }

    if( event_type_id == 0 ){
      // Check/Uncheck all legend checkboxes.
      for( var index = 0; index < EVENT_TYPE_ID_SUGGESTED_STOP; index++ ){
        document.getElementsByName("display_icon")[index].checked = display;
      }
    }
  }

  updateEventListingFooters();
  stripeTables();
}


// String output for the specified Date.
function dateString(date){
  var output = '';
  output += WEEKDAY_ABBREVIATION[date.getDay()] + ' ';
  output += MONTH_ABBREVIATION[date.getMonth()] + ' ';
  output += date.getDate() + ', ';
  output += date.getFullYear();
  return output;
}


// String output for the specified Event.
function eventString(current_event) {
  var output = '';
  var address = addresses_by_id[addressKey(current_event.address_id)];
  var state = (address.state_id != null) ? states[address.state_id - 1] : null;

  if( current_event.name != null )      output += current_event.name + '<br/>';
  if( current_event.starts_at != null ) output += dateString(current_event.starts_at_date) + '<br/>';
  if( address.address_line_1 != null )  output += address.address_line_1 + '<br/>';
  if( address.city != null )            output += address.city + ', ';
  if( state != null )                   output += state.name + "&nbsp;&nbsp;";
  if( address.zipcode_plus_4 != null )  output += address.zipcode_plus_4;
  output += '<br/>';
  if( current_event.uri != null )      output += '<a href="' + current_event.uri + '">' + current_event.uri + '</a>';

  return output;
}


// String output for the specified Event location.
function eventLocationString(current_event){
  var address = addresses_by_id[addressKey(current_event.address_id)];
  var state = (address.state_id != null) ? states[address.state_id - 1] : null;
  var event_location = '';
  if( address.city != null )                   event_location += address.city;
  if( address.city != null && state != null )  event_location += ', ';
  if( state != null )                          event_location += state.abbreviation;
  return event_location;
}


// Function to perform striping of event listing tables.
function stripeTables(){
  stripe('events-past-table');
  stripe('events-suggested-table');
}

