// ----------------------------------------------------------------------------
// Copyright - J. C. Parker 2007 - 2010
// ----------------------------------------------------------------------------

var map = null;
var urlBase = 'http://www.bigyak.net.au/vicbiketrails/vicbiketrails.php';

// array to hold a copy of the markers and its index
var gmarkers   = [];
var markerIndx = 0;

var dataLoadingEnabled = true;
var infoWindowWasOpen  = false;

// the default permalink variables
// Melbourne's GPO is located at Australian Map Grid (AMG) 320 725 E, 5812 900 N, Zone 55
var mapCenterLat = -37.8135784679527;  // set the default to Melbourne's GPO
var mapCenterLng = 144.963341474327;   // set the default to Melbourne's GPO
var mapZoom      = 8;
var mapType      = G_PHYSICAL_MAP;
var mapTypeText  = "p";

var pullDownListIdx = 0;  // equivalent to no selection
var trailIdx        = 0;

// ----------------------------------------------------------------------------

var trailLocations = [];

// the array index is the value of the pulldown list
// the array index is the value used in the slct2 var (not used by the permalink)
// the value is mapped to the pull down list index using this arrray
// Using the value allows us to swap things around in the pull down
// list without stuffing up existing links utlising slct2 var
// note javascript allows the array elements to be declared in any order
// the array index is permanently assigned to a particular trail
// the pull down list is altered as new trails are added in, so that it is always in order
//                
//   Value--->"U"      0<---Pull down list idx
trailLocations[0]   = "1,-37.832715,145.071588,13";     // Anniversary Trail
trailLocations[1]   = "2,-37.97013897,145.0117894,13";  // Bayside Trail
trailLocations[2]   = "3,-37.9104153,145.3524713,13";   // Belgrave Rail Trail
trailLocations[3]   = "4,-37.86804071,145.2488134,13";  // Blind Creek Trail
trailLocations[4]   = "5,-37.63525282,144.9233079,13";  // Broadmeadows Valley Trail
trailLocations[5]   = "6,-37.80753806,145.1316746,13";  // Bushy Creek Trail
trailLocations[6]   = "7,-37.79831121,144.9363681,13";  // Capital City Trail
trailLocations[7]   = "8,-37.58422042,144.9409911,13";  // Craigieburn Bypass Trail
trailLocations[8]   = "9,-37.95669207,145.2337833,13";  // Dandenong Creek Trail
trailLocations[9]   ="10,-37.71084361,145.0345801,13";  // Darebin Creek Trail - lower
trailLocations[10] = "11,-37.66527308,145.0364122,13";  // Darebin Creek Trail - upper
trailLocations[11] = "12,-37.67973214,145.1506214,13";  // Diamond Creek Trail
trailLocations[12] = "13,-37.981885,145.194236,12";     // East Link Trail
trailLocations[13] = "14,-37.92657102,145.1227448,13";  // East Malvern Station to Centre Rd Trail
trailLocations[14] = "15,-37.67520697,145.0076293,13";  // Edgars Creek Trail
trailLocations[15] = "16,-37.83572911,144.7883258,13";  // Federation Trail
trailLocations[16] = "17,-37.85621644,145.0733651,13";  // Ferndale Park Trail
trailLocations[17] = "18,-37.89565081,145.2695482,13";  // Ferny Creek Trail
trailLocations[18] = "19,-37.84940157,145.0490636,13";  // Gardiners Creek Trail
trailLocations[19] = "20,-37.80866963,145.1015209,13";  // Gawler Chain Trail
trailLocations[20] = "21,-37.75499336,145.1636546,13";  // Greengully Trail
trailLocations[21] = "22,-38.02570715,145.3189835,13";  // Hallam Bypass Trail
trailLocations[22] = "23,-38.052175,145.319813,13";     // Hallam Main Drain Trail
trailLocations[23] = "24,-37.64126258,145.0691806,13";  // Hendersons Road Drain Trail
trailLocations[24] = "25,-37.87222477,144.9032438,13";  // Hobsons Bay Coastal Trail
trailLocations[25] = "26,-37.79697361,145.1413401,13";  // Koonung Creek Trail
trailLocations[26] = "27,-37.85627447,144.837549,13";   // Kororoit Creek Trail - lower
trailLocations[27] = "28,-37.78934549,144.8265364,13";  // Kororoit Creek Trail - upper
trailLocations[28] = "29,-37.86286845,144.7819702,13";  // Laverton Creek Trail
trailLocations[29] = "30,-37.77490619,144.8609416,13";  // Maribyrnong River Trail
trailLocations[30] = "31,-37.69287236,145.168295,13";   // Maroondah Aqueduct Trail
trailLocations[31] = "32,-37.71262098,144.9788313,13";  // Merri Creek Trail
trailLocations[32] = "33,-37.71744169,144.9059362,13";  // Moonee Ponds Creek Trail
trailLocations[33] = "34,-37.77405488,145.1892559,13";  // Mullum Mullum Creek Trail - lower
trailLocations[34] = "35,-37.78553782,145.2608895,13";  // Mullum Mullum Creek Trail - upper
trailLocations[35] = "36,-37.71619937,145.1133252,13";  // Plenty River Trail
trailLocations[36] = "37,-37.73810236,145.0802142,13";  // River Gum Walk Trail
trailLocations[37] = "38,-37.76253207,145.1271756,13";  // Ruffey Creek Trail
trailLocations[38] = "39,-37.83317101,144.9431119,13";  // Sandridge Trail
trailLocations[39] = "40,-37.89082562,145.1037163,13";  // Scotchmans Creek Trail
trailLocations[40] = "41,-37.87434827,144.7444235,13";  // Skeleton Creek Trail
trailLocations[41] = "42,-37.7372095,145.0002378,13";   // St Georges Rd Trail
trailLocations[42] = "43,-37.74334799,144.8824807,13";  // Steele Creek Trail
trailLocations[43] = "44,-37.86198748,145.1547416,13";  // Syndal Heatherdale Pipe Reserve Trail
trailLocations[44] = "45,-37.80632263,145.2798675,13";  // Tarralla Creek Trail
trailLocations[45] = "46,-37.70408279,144.7950161,13";  // Taylors Creek Trail
trailLocations[46] = "47,-37.675834,144.593079,13";     // Toolern Creek Trail
trailLocations[47] = "48,-37.75213156,144.9622173,13";  // Upfield Rail Trail
trailLocations[48] = "49,-37.875500,145.122736,13";     // Waverley Rail Trail
trailLocations[49] = "50,-37.767754,144.744595,13";     // Wellness Trail
trailLocations[50] = "51,-37.91042571,144.6527058,13";  // Werribee River Trail
trailLocations[51] = "52,-38.316037,145.186908,12";     // Western Port Bay Trail
trailLocations[52] = "53,-37.6930293,144.9419142,12";   // Western Ring Road Trail
trailLocations[53] = "54,-37.84356377,145.1552386,13";  // Wurundjeri Walk Trail
trailLocations[54] = "55,-37.76815039,145.0713698,13";  // Yarra River Trail
//            "-"     56
trailLocations[56] = "57,-38.164267,144.350092,14";     // Barwon River Trail
trailLocations[57] = "58,-38.143312,144.361901,14";     // Corio Bay Trail
trailLocations[58] = "59,-38.124340,144.330753,14";     // Geelong Cement Works Rail Trail
trailLocations[59] = "60,-38.060372,144.412514,14";     // Hovell Creek Trail
trailLocations[60] = "61,-38.089037,144.327281,13";     // Ted Wilson Trail
trailLocations[61] = "62,-38.197840,144.324484,14";     // Waurn Ponds Trail
//            "-"     63
trailLocations[63] = "64,-38.191007,144.578136,11";     // Bellarine Peninsula Rail Trail
trailLocations[64] = "65,-38.409781,142.979888,11";     // Coast to Crater Rail Trail
trailLocations[65] = "66,-37.708968,147.835187,11";     // East Gippsland Rail Trail
trailLocations[66] = "67,-38.600535,146.047489,11";     // Great Southern Rail Trail
trailLocations[67] = "68,-36.173218,147.035217,11";     // High Country Rail Trail
trailLocations[68] = "69,-37.798178,147.925789,11";     // Mississippi Creek Trail
trailLocations[69] = "70,-36.647017,146.866421,11";     // Murray to the Mountains Rail Trail
trailLocations[70] = "71,-36.38075,146.681744,11";      // Murray to the Mountains - Beechworth spur
trailLocations[71] = "72,-37.769556,145.632565,11";     // The Centenary Trail
trailLocations[72] = "73,-38.308626,145.196751,11";     // Western Port Bay Trail

// ----------------------------------------------------------------------------

   var baseIcon = new google.maps.Icon();
   baseIcon.iconSize         = new google.maps.Size(32,32);
   baseIcon.shadowSize       = new google.maps.Size(56,32);
   baseIcon.iconAnchor       = new google.maps.Point(16,32);
   baseIcon.infoWindowAnchor = new google.maps.Point(16,0);

   var navigationIcon = new google.maps.Icon(baseIcon, "http://maps.google.com/mapfiles/kml/pal3/icon35.png");
   var interestsIcon  = new google.maps.Icon(baseIcon, "http://maps.google.com/mapfiles/kml/pal4/icon17.png");
   var coffeeIcon     = new google.maps.Icon(baseIcon, "http://maps.google.com/mapfiles/kml/pal2/icon55.png");
   var trailNamesIcon = new google.maps.Icon(baseIcon, "http://maps.google.com/mapfiles/kml/shapes/target.png");

// ----------------------------------------------------------------------------
// A function to create the marker and set up the event window
// ----------------------------------------------------------------------------

function createMarker(point, icon, name, description)
{
   var marker = new google.maps.Marker(point, {icon:icon, title:name});

   google.maps.Event.addListener(marker, "click", function()
      {
      var htmlCode = '<p><b>' + name + '</b></p>' + description;
      var divStyle = '<div class="gmapinfowindow">';
      htmlCode = divStyle + htmlCode + '</div>';

      marker.openInfoWindowHtml(htmlCode, {maxHeight:500,autoScroll:true});
      //alert (htmlCode);
      }
   );

   // save the info we need to use later
   gmarkers[markerIndx] = marker;

   markerIndx++;

   return marker;
}

// ----------------------------------------------------------------------------
// Populate the map with the KML data
// ----------------------------------------------------------------------------

function getData()
{
   //GLog.write(dataLoadingEnabled);
   if (!dataLoadingEnabled)
      return;

   // output the "Loading" message
   //var loadingMsgHTML = '<img src="http://www.bigyak.net.au/gmaps/spinner.gif" alt="Spinner"/>Loading .....';
   //document.getElementById("loadingMsg").innerHTML = loadingMsgHTML;

   // start setting the ajax call
   var bounds = map.getBounds();
   var SW = bounds.getSouthWest();
   var NE = bounds.getNorthEast();

   // get the values as strings with 6 decimal places
   var SWlat = SW.toUrlValue().split(',')[0];
   var SWlng = SW.toUrlValue().split(',')[1];
   var NElat = NE.toUrlValue().split(',')[0];
   var NElng = NE.toUrlValue().split(',')[1];

   // East must always be greater than west, so when the BBox straddles the dateline
   // the BBox east has 360 degrees added to it, to make it greater than west.
   // Here we adjust east so it matches Google Earth's understanding of east
   var adjEast = NE.lng();
   if (SW.lng() > adjEast) adjEast += 360.0;

   // BBOX is formatted as WSEN
   var uri = urlBase + "?BBOX=" + SWlng + "," + SWlat + "," + adjEast + "," + NElat + "&uap=gm";

   uri = encodeURI(uri);
   //GLog.write(uri);

   google.maps.DownloadUrl(uri, function(data, responseCode)
   {
      // check status code for success or HTTP errors
      if (responseCode == 200)
      {
         for (var j = 0; j < gmarkers.length; j++)
            map.removeOverlay(gmarkers[j]);

         gmarkers   = [];
         markerIndx = 0;

         // get all the placemarks 
         var xmlDoc = google.maps.Xml.parse(data);
         var placemarks = xmlDoc.documentElement.getElementsByTagName("Placemark");

         // process the placemarks 
         for (var i = 0; i < placemarks.length; i++)
         {
            // placemarks do not necessarily contain markers
            // markers have a 'Point' tag
            if (placemarks[i].getElementsByTagName("Point").length > 0)
            {
               var point  = placemarks[i].getElementsByTagName("Point")[0];
               var coords = point.getElementsByTagName("coordinates")[0].childNodes[0].nodeValue;
               coords     = coords.split(",");
               var name   = placemarks[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;

               // placemarks don't have to have descriptions
               var description = "";
               if (placemarks[i].getElementsByTagName("description").length > 0)
                  description = placemarks[i].getElementsByTagName("description")[0].childNodes[0].nodeValue;

               // placemarks don't have to have a styleUrl
               var styleUrl = "";
               var icon = new google.maps.Icon(G_DEFAULT_ICON);
               if (placemarks[i].getElementsByTagName("styleUrl").length > 0)
               {
                  styleUrl = placemarks[i].getElementsByTagName("styleUrl")[0].childNodes[0].nodeValue;

                  // map the styles to the icons
                  if (styleUrl == '#sty_Nav')
                     icon = navigationIcon;
                  else if (styleUrl == '#sty_PofI')
                     icon = interestsIcon;
                  else if (styleUrl == '#sty_CandC')
                     icon = coffeeIcon;
                  else if (styleUrl == '#sty_TN')
                     icon = trailNamesIcon;
               }

               // create the marker and it point
               var latLng = new google.maps.LatLng (parseFloat(coords[1]), parseFloat(coords[0]));
               var marker = createMarker(latLng, icon, name, description);
               map.addOverlay(marker);
            }

         }  // end for all the points

         // cancel the "Loading" message
         //document.getElementById("loadingMsg").innerHTML = '';

      }     // end response code OK   
      else if (responseCode == -1)
      {
         alert ("Data request timed out. Please try later.");
      } 
      else
      {
         alert ("Request resulted in an error. Check file is retrievable.");
      }

   });   // end google.maps.DownloadUrl function definition
}

// ----------------------------------------------------------------------------
// Close the about window
// ----------------------------------------------------------------------------

function aboutMsgCloseBtnClick()
{
   var aboutMsg = document.getElementById("aboutMsg");
   aboutMsg.style.visibility = "hidden";

   // setting hidden was not enough - in Firefox a shimmering shadow remained
   aboutMsg.style.width  = "0px"; 
   aboutMsg.style.height = "0px";
}

// ----------------------------------------------------------------------------
// Focus on the trail selected in the pulldown list
// ----------------------------------------------------------------------------

function jumpToTrail()
{
   pullDownListIdx = document.getElementById("trailOptions").selectedIndex;
   trailIdx        = document.getElementById("trailOptions").value;

   // if the selected trail is unknown ie 'U' or a spacer '-'
   // then no action is required
   if ((trailIdx == 'U') || (trailIdx == '-'))
      return;

   trailIdx = parseInt(trailIdx,10);

   // get the coordinates and zoom level for the selected trail
   if (trailIdx >= 0)
   {
      var trailView  = trailLocations[trailIdx].split(",");
      var idxInArray = parseInt  (trailView[0],10);
      mapCenterLat   = parseFloat(trailView[1]);
      mapCenterLng   = parseFloat(trailView[2]);
      mapZoom        = parseFloat(trailView[3]);

      // sanity check
      if (pullDownListIdx != idxInArray)
      {
         alert("Mismatch in array trailLocations: pull down list idx = " + pullDownListIdx + " but array says idx is " + idxInArray);
         return;
      }

      // ready map center
      var mapCenter = new google.maps.LatLng(mapCenterLat, mapCenterLng);

      // update the map centre and zoom level
      map.setCenter(mapCenter, mapZoom, mapType);

      // at this point the 'moveend' event is fired
   }
}

// ----------------------------------------------------------------------------
// Focus on the trail selected in the pulldown list
// ----------------------------------------------------------------------------

function upDateMap()
{
   if (infoWindowWasOpen)
   {
      dataLoadingEnabled = true;
      infoWindowWasOpen  = false;
      return;
   }

   var newCenter = map.getCenter();
   var latLngStr = newCenter.toUrlValue();
   var latLng    = latLngStr.split(",");
   mapCenterLat  = parseFloat(latLng[0]);
   mapCenterLng  = parseFloat(latLng[1]);

   /* How the google.maps.XmlHttp request object works is a bit confusing until you realize that 
   it doesn't execute inline. Once you call the request object, control returns to the
   next line in the code while the "get" happens in the background. The request object
   waits patiently for the server to return the results (the onreadystate = 4) and 
   then acts on the received data. */

   getData();

   updatePermaLink();
}

// ----------------------------------------------------------------------------
// Extract the parms from the URL
// ----------------------------------------------------------------------------

function parseParms()
{
   // get the URL and attempt to split it
   var urlParms = window.location.href.toLowerCase();
   urlParms = urlParms.split("?");

   // did the URL contain any parameters?
   if (urlParms.length > 1)
   {
      // get the parm(s) and attempt to split them
      var parms = urlParms[1].split("&");

      // for all the key value pairs
      for (var i=0; i<parms.length; i++)
      {
         // get the key value pairs and attempt to split them up
         var keyValue = parms[i].split("=");

         // the parms must come in key value pairs else the url is malformed
         if (keyValue.length != 2)
            break;

         // is this the lat/lng parameter?
         if (keyValue[0] == 'll')
         {
            // break up the value into lat and lng
            var latLng = keyValue[1].split(",");

            // the lat/lng must come as a pair else the url is malformed
            if (latLng.length != 2)
               break;

            mapCenterLat = parseFloat(latLng[0]);
            mapCenterLng = parseFloat(latLng[1]);
         }

         // is this the zoom parameter?
         if (keyValue[0] == 'z')
            mapZoom = parseInt(keyValue[1],10);

         // is this the map type parameter?
         if (keyValue[0] == 't')
         {
            mapTypeText = keyValue[1];
            if      (mapTypeText == "p") { mapType = G_PHYSICAL_MAP;  }
            else if (mapTypeText == "k") { mapType = G_SATELLITE_MAP; }
            else if (mapTypeText == "h") { mapType = G_HYBRID_MAP;    }
            else                         { mapType = G_NORMAL_MAP; mapTypeText = "m"; }
         }

         // is this the trail selection parameter? This trail selection parameter,
         // if present, overrides any lat,lng parameters in the URL. The permalink
         // does not save the trail selection. It saves the lat,lng in which case
         // the lat,lng receives priority in the absence of the selection parm.
         // Note that slct1 is already used by other similar code so this uses slct2
         if (keyValue[0] == 'slct2')
         {
            // get the trail array mappings and the pulldown list index
            trailIdx = parseInt(keyValue[1],10);

            var trailView = trailLocations[trailIdx].split(",");
            pullDownListIdx = parseInt(trailView[0],10);
         }
      }
   }
}

// ----------------------------------------------------------------------------
// Build a permanent URL link to the current view
// ----------------------------------------------------------------------------

function updatePermaLink()
{
   // triggers whenever the map is moved or zoomed. Also manually
   // invoked when the feed is first created to initially populate the feed
   // make a link to the current view and display it
   // get the URL and attempt to split it

   var urlParms = window.location.href.toLowerCase();
   urlParms = urlParms.split("?");
   //GLog.write('URL  = '+ urlParms);

   // note that trailIdx is specifically excluded from this permalink
   if (urlParms.length >= 1)
   {
      document.getElementById("linkToThisView").innerHTML = '<a href="' + urlParms[0]
         + '?ll='    + mapCenterLat +','+ mapCenterLng
         + '&z='     + mapZoom
         + '&t='     + mapTypeText
         + '">Permalink to this view</a>';

      //GLog.write('PermaLink = '+ document.getElementById("linkToThisView").innerHTML);
   }
}

// ----------------------------------------------------------------------------
// Don't name this 'onload' as it's a reserved word in Firefox
// ----------------------------------------------------------------------------

function load()
{
   // any parameters in the URL will override defaults
   parseParms();

   // no option is selected in the pulldown list or the URL selection (if present) is used
   document.getElementById("trailOptions").selectedIndex = pullDownListIdx;

   if (google.maps.BrowserIsCompatible())
   {
      // output the "Loading" message
      var loadingMsgHTML = '<img src="http://www.bigyak.net.au/gmaps/spinner.gif" alt="Spinner"/>Loading .....';
      document.getElementById("loadingMsg").innerHTML = loadingMsgHTML;

      map = new google.maps.Map2(document.getElementById("mapDiv"));

      // ready map center
      var mapCenter = new google.maps.LatLng(mapCenterLat,mapCenterLng);

      // got the center and zoom level so set it
      map.setCenter(mapCenter, mapZoom, mapType);

      // set up the UI controls on the map
      map.setUIToDefault();
      map.addMapType(G_SATELLITE_3D_MAP);

      google.maps.Event.addListener(map, "moveend", upDateMap);

      google.maps.Event.addListener(map, "zoomend", function(oldLevel, newLevel)
      {
         // the zoom level changed - save it
         mapZoom = newLevel;
         updatePermaLink();
      });

      google.maps.Event.addListener(map, "maptypechanged", function()
      {
         // the map type changed - save it
         mapType     = map.getCurrentMapType();
         mapTypeText = mapType.getUrlArg();
         updatePermaLink();
      });

      google.maps.Event.addListener(map, "infowindowopen", function()
      {
         // the map moves when the infowindow opens - later
         // on we'll stick it back to where it came from
         dataLoadingEnabled = false;
         map.savePosition();
      });

      google.maps.Event.addListener(map, "infowindowclose", function()
      {
         infoWindowWasOpen = true;

         // the map moves when the infowindow opens
         // we'll stick it back to where it came from
         map.returnToSavedPosition();

         // at this point the 'moveend' event is fired
      });

      // get the routes
      var kmlRoutes = new google.maps.GeoXml("http://www.bigyak.net.au/vicbiketrails/kml/vicbiketrailsroutesgmap.kmz", function() {
      if (kmlRoutes.loadedCorrectly())
        {
            // cancel the "Loading" message
            document.getElementById("loadingMsg").innerHTML = '';
        }
      });

      map.addOverlay(kmlRoutes);

      jumpToTrail();
      upDateMap();
   }
   else
      alert("Sorry, the Google Maps API is not compatible with this browser");
}

// execute this
window.onload   = load;

window.onunload = google.maps.Unload;

// ----------------------------------------------------------------------------
