// Declare variables for later use
var map;
var geoXml;
var markers = new Array();
var sidebar;
var kmlUrl;
var geocoder;
var view;
var legend;
var mapDiv;
var filter;

// Cookies (used for filtering) to expire in one year
var cookieExpire = cookieDate(new Date(Number(new Date()) + 365 * _mSecPerDay));

// Attach handlers for window events
addEventHandler(window, 'load',   loadPage);
addEventHandler(window, 'unload', unloadPage);
addEventHandler(window, 'resize', resizePage);

function loadPage()
{
  // loadPage: initialize the API and load the map onto the page
  
  // Get handles to various page elements we'll need later
  view = document.getElementById('view');
  sidebar = document.getElementById('search_result_list');
  legend = document.getElementById('legend');
  mapDiv = document.getElementById('map');
  filter = document.getElementById('filter_large');

  // Initialize the page layout
  if (document.body)
    document.body.scroll = 'no';    // Hide vertical scrollbar on body in IE
  resizePage();

  // Confirm browser compatibility with the Maps API
  if (!GBrowserIsCompatible())
  {
    mapDiv.innerHTML = 'Sorry, your browser isn\'t compatible with Google Maps.';
  }
  else
  {
    var urlAddress = '';
    var startLocation;

    // Check for a starting location or search address in URL
    var hash = location.hash.replace('#', '');
    if (hash != '')
    {
      if (hash.substring(0, 8) == 'address:')
        urlAddress = hash.substring(8);
      else
        startLocation = hash;
    }

    // No starting location in URL - check for a browser cookie
    if (startLocation == null)
      startLocation = getCookie('lastLocation');

    if (startLocation != null)
    {
      // Found starting location - parse the coordinates & zoom from it
      var viewport = startLocation.split(',');
      var latitude  = parseFloat(viewport[0]);
      var longitude = parseFloat(viewport[1]);
      var zoom      = parseInt(viewport[2]);
      var type      = getMapType(viewport[3]);
    }

    // Initialize the core map object
    var options = {backgroundColor: '#D7D5E3', 
      mapTypes: [G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP, G_PHYSICAL_MAP]};
    map = new GMap2(mapDiv, options);

    if (!isNaN(latitude + longitude + zoom))
      // Starting location supplied
      map.setCenter(new GLatLng(latitude, longitude), zoom, type);
    else
      // Default starting location
      map.setCenter(new GLatLng(39.8, -98.5), 4, G_PHYSICAL_MAP);

    // Init other map options
    map.enableContinuousZoom();

    // Add the standard map controls
    map.addControl(new GLargeMapControl());
    map.addControl(new GScaleControl());
    map.addControl(new GOverviewMapControl());
    map.addControl(new GMapTypeControl());

    // Initialize the KML processor
    options = {createmarker: addDataPoint, nozoom: true};
    geoXml = new EGeoXml(map, null, options);

    // Initialize the geocoder object
    geocoder = new GClientGeocoder();

    // Attach events to refresh the marker display whenever the map moves
    GEvent.addListener(map, 'moveend', mapMoveEnd);
    GEvent.addListener(map, 'zoomend', mapZoomEnd);

    if (urlAddress != '')
    {
      // A search address was supplied in the URL, so geocode it (and do other init)
      document.getElementById('address').value = urlAddress;
      geocode();
      setUrl();
      summarizeFilter();
    }
    else
      // No search address => the applyFilter will refresh the map view
      applyFilter();
  }
};

function unloadPage()
{
  // Save the current map viewport in a browser cookie
  var lastLocation = map.getCenter().toUrlValue() + ',' + map.getZoom() + ',' +
                     map.getCurrentMapType().getUrlArg();
  document.cookie = 'lastLocation=' + lastLocation + ';path=/';

  // Finalize the Maps API
  if (map != null)
    GUnload();
};

function resizePage()
{
  // resizePage: maintain the full-screen layout by dynamically resizing elements

  var height = windowHeight() - getTop(document.getElementById('primary')) - 1;

  // Map area and sidebar column
  document.getElementById('primary').style.height = height + 'px';
  document.getElementById('secondary').style.height = height + 'px';
  sidebar.style.height = (windowHeight() - getTop(sidebar) - 1) + 'px';

  // Map container and legend
  mapDiv.style.height = (height - elementHeight(legend)) + 'px';
  legend.style.top    = (height - elementHeight(legend)) + 'px';
  
  // GMap object
  if (map != null)
    map.checkResize();
};

function mapMoveEnd()
{
  //  mapMoveEnd: refresh the marker display after the map has moved

  // Get the map boundary coordinates
  var mapBounds = map.getBounds();

  // Parameterize the geodata URL based on those boundaries 
  geoXml.urls = [kmlUrl + 'BBOX=' + 
                 mapBounds.getSouthWest().lng().toFixed(6) + ',' +
                 mapBounds.getSouthWest().lat().toFixed(6) + ',' +
                 mapBounds.getNorthEast().lng().toFixed(6) + ',' +
                 mapBounds.getNorthEast().lat().toFixed(6)];

  // Load the KML - new markers will get added when it returns
  geoXml.parse();

  // Remove markers from display that are no longer visible
  for (var m = markers.length - 1; m >= 0; m--)
    if (!mapBounds.contains(markers[m].getPoint()))
      removeDataPoint(m);

  // Also clear starting location out of the URL
  location.hash = '#';
};

function mapZoomEnd(oldZoom, newZoom)
{
  // mapZoomEnd: remove most map markers when zoom changes

  for (var m = markers.length - 1; m >= 0; m--)
  {
    // The only markers we don't remove are individual cmapgrounds when zooming in
    if (markers[m].isCluster || (oldZoom > newZoom))
      removeDataPoint(m);
  }
};

function getMapType(urlArg)
{
  switch (urlArg) 
  {
    case 'm': return G_NORMAL_MAP;
    case 's': return G_SATELLITE_MAP;
    case 'h': return G_HYBRID_MAP;
    default:  return G_PHYSICAL_MAP;
  }
};

function getAnchor(iconUrl)
{
  // getAnchor: return the infoWindowAnchor property for the given icon image URL
  if (iconUrl.indexOf('bus') > -1)
    return new GPoint(16, 0);
  else if (iconUrl.indexOf('trailer') > -1)
    return new GPoint(19, 10);
  else
    return new GPoint(16, 6);
};

function addDataPoint(coordinates, name, description, style)
{
  // addDataPoint: display a placemark found by the KML processor 

  // Check to see if this placemark is already displayed, and stop if it is
  for (var m = markers.length - 1; m >= 0; m--)
  {
    if (markers[m].getPoint().equals(coordinates))
      return;
  }
  
  // Create and initialize the icon from the style in the KML
  var myIcon = new GIcon();
  myIcon.image      = geoXml.styles[style].image;
  myIcon.iconSize   = new GSize(32, 32);
  if (myIcon.image.indexOf('circle') > -1)
  {
    // It's a cluster placemark
    myIcon.shadow     = '/images/icons/circle_shadow.png';;
    myIcon.shadowSize = new GSize(40, 40);
    myIcon.iconAnchor = new GPoint(13, 13);
    myIcon.infoWindowAnchor = new GPoint(13, 0);
  }
  else
  {
    // Not a cluster => an individual campground
    if (map.getZoom() < 5)
      return;
    myIcon.shadow     = geoXml.styles[style].shadow;
    myIcon.shadowSize = geoXml.styles[style].shadowSize;
    myIcon.iconAnchor = new GPoint(16, 28);
    myIcon.infoWindowAnchor = getAnchor(myIcon.image);
  }

  // Create a marker for this data point
  var options = {icon: myIcon, title: name};
  var thisMarker = new GMarker(coordinates, options);
  markers.push(thisMarker);

  // Some different handling for clusters and campgrounds
  if (myIcon.image.indexOf('circle') > -1)
  {
    // Cluster
    thisMarker.isCluster = true;

    GEvent.addListener(thisMarker, 'click', 
      function ()
      {
        // Clicking on a cluster zooms the map on its location
        map.setCenter(coordinates, map.getZoom() + 2);
      });
  }
  else
  {
    // Individual campground
    thisMarker.isCluster = false;

    // Attach infowindow to the marker with content from the KML
    options = {maxWidth: 350};
    thisMarker.bindInfoWindowHtml('<div id="infowindow"><h3>' + name + '</h3>' + 
      description + '</div>', options);

    // Also create a sidebar entry (alongside the map) with the icon, name, & descr
    var sidebarRow = document.createElement('div');
    sidebarRow.id = coordinates.toUrlValue();
    sidebarRow.className = 'sidebar_row';
    sidebarRow.innerHTML = 
      '<img width="32" height="32" src="' + myIcon.image + '" /><h3>' + name + 
      '</h3>' + description;
    sidebar.appendChild(sidebarRow);

    sidebarRow.onclick = 
      function ()
      {
        // A click on the sidebar entry triggers a click on its associated marker
        GEvent.trigger(thisMarker, "click")
      };
  }

  // Add the marker to the map 
  map.addOverlay(thisMarker);
};

function removeDataPoint(m)
{
  // Remove the marker from the map
  map.removeOverlay(markers[m]);

  // Find and remove the sidebar entry  
  var id = markers[m].getPoint().toUrlValue();
  var sidebarRow = document.getElementById(id);
  if (sidebarRow)
    sidebar.removeChild(sidebarRow);

  // Remove the marker from our own array
  markers.splice(m, 1);
};

function setUrl()
{
  // setUrl: refresh the geodata URL to use based on the user's preference
  var selected = view.options[view.selectedIndex].value;
  if (selected == 'all')
    kmlUrl = '/services/all_campgrounds.php?';
  else if (selected == 'recent')
    kmlUrl = '/services/recent_campgrounds.php?type=kml&';
  else
    kmlUrl = '/services/top_campgrounds.php?sort=' + selected + '&';
  
//  // Save the selected data type in a cookie for use next time user visits this page
//  setCookie('view', selected)
};

function viewChange()
{
  // viewChange: event handler called when the user has changed the type of data

  // Refresh the URL to use when retrieving geodata
  setUrl();

  // Remove all current markers from display  
  for (var m = markers.length - 1; m >= 0; m--)
    removeDataPoint(m);

  // Trigger a refresh of the map to load new data
  mapMoveEnd();
};

function geocode()
{
  // geocode: Call the Google geocoder with the address supplied by the user
  var address = document.getElementById('address').value;
  geocoder.getLocations(address, afterGeocode);
};

function afterGeocode(response)
{
  // afterGeocode: Callback function for the geocoder, moving the map to the coords
  if (response && 
      (response.Status.code == 200))
  {
    // Address was found - extract the map coordinates from the response
    var place = response.Placemark[0];
    var coordinates = new GLatLng(place.Point.coordinates[1], 
                                  place.Point.coordinates[0]);

    // Move the map there, zooming further in for more accurate results
    map.setCenter(coordinates, place.AddressDetails.Accuracy + 5);
  }
  else
    alert('Address not found. Please try again.');
};

function showFilter()
{
  filter.style.display = 'block';
};

function hideFilter()
{
  filter.style.display = 'none';
};

function setCookie(name, value)
{
  // setCookie: helper function to set a browser cookie to the supplied name & value
  if (value == '')
    document.cookie = name + '=;expires=Sunday, 24-Apr-05 00:00:00 GMT;path=/'
  else
    document.cookie = name + '=' + value + ';expires=' + cookieExpire + ';path=/';
};

function clearFilter()
{
  // Reset the onscreen elements to their default (unfiltered) values
  document.getElementById('nHookups0').checked  = '1';
  document.getElementById('nCGRating1').checked = '1';
  document.getElementById('nSatLon').value      = '';

  // Clear the filter cookies
  setCookie('nHookups',  '');
  setCookie('nCGRating', '');
  setCookie('nSatLon',   '');

  // Refresh the display  
  applyFilter();
};

function summarizeFilter()
{
  // summarizeFilter: generate onscreen text for the current filter

  var summary = [siteAttributes.hookups[getCookie('nHookups')],
                 siteAttributes.rating[getCookie('nCGRating')],
                 siteAttributes.satellite[getCookie('nSatLon')]];

  if (summary.join('') == '')
    document.getElementById('filter_summary').innerHTML = 'none';
  else
  {
    var descr = [];
    if (summary[0] != null)
      descr.push(summary[0] + ' hookups');
    if (summary[1] != null)
      descr.push(summary[1] + ' coverage');
    if (summary[2] != null)
      descr.push(summary[2]);

    document.getElementById('filter_summary').innerHTML = descr.join(', ');
  }
};

function applyFilter()
{
  // applyFilter: when filter has changed, apply the new values to the display

  // Refresh the small-version description of the new filter  
  summarizeFilter();
  
  // That description may have changed size, so readjust the sidebar
  resizePage();
  
  // Finally, refresh the map with the new filter.
  viewChange();
};

