// Google Map Maker Javascript Library
// Copyright (C) 2006 - 2008 Stephen Cohen. All rights reserved.
//
// 7/12/08

    // Global variables accessible from web page - values defined here are defaults
var mapdiv = "map";       // ID of division containing the Google map
var markerLinkDiv = "listmarkers";    // ID of "sidebar" division containing links to markers on map
var mapInfoDiv = "mapinfo";  // ID of division containing map setup and author marker point coords
  // 2-4-08 allow minimal map format
var largeMapMode = "Y";  // include controls (large map movement, zoom, etc.) and generate list div: 
                         // M (medium) for small map control only (no zoom, map type, or overview controls)
                         // N (no controls) for small mode (any value other than Y or M is taken as N) - good for embedding within a page


var gmarkers = [];
var htmls = [];


var markerTypeTag = [];
var markerTypeHdgHtml = [];
var markerTypeImage = [];  // Marker icon image file
var markerTypeImageWidth = [];  // Marker icon image width
var markerTypeImageHeight = [];  // Marker icon image height

var markerTypeIcon = [];

// authoring globals used for interactive marker placement
var authorInteract = 0;   // if on (1), a pointer can be placed on the map by clicking
var centerAtPointer = 0;  // if interactive mode is on, map is centered at placed pointer if on (1)
var savedmap;
var savedpoint;
var savedpointhtml;
var issavedpoint = 0;
var savedmarker;
var moveableicon = new GIcon();
moveableicon = G_DEFAULT_ICON;       // for now, use Google's default icon


       // Global variables local to stgmapslib.js library functions
var first = 1;
// **** add checkbox selection for marker display ******
// must define enough entries for maximum number of marker types; 
//        1=checked, 0=not checked ; library sets all to 1 when map page first loads
var maxMarkerTypes = 256;
var stCheckState = [];

var marker_default_imgpath = "/maps/images/";   // must include ending slash - COTSWOLDER image location
var marker_stCity_image = "mm_20_red.png";
var marker_stTown_image = "mm_20_purple.png";
var marker_stVillage_image = "mm_20_blue.png";
var marker_stSight_image = "st_sights_gr.png";

var marker_default_image = "mm_20_red.png";
var marker_default_iconSize = new GSize(12,20);
var marker_default_iconAnchor = new GPoint(6,20);
var marker_default_infoWindowAnchor = new GPoint(5,1);

// define default marker object
var default_marker = new GIcon();
default_marker.image = marker_default_imgpath + marker_default_image;
default_marker.iconSize = marker_default_iconSize;
default_marker.iconAnchor = marker_default_iconAnchor;
default_marker.infoWindowAnchor = marker_default_infoWindowAnchor;

var stMarkerNo = 0;

  // The following arrays define standard marker types for Slow Travel Google maps
  // The recognized xml tags are in stGmapMarkerType; associated values are in the corresponding
  // position in the following arrays
var nStMarkerTypeDefs;   // following set of arrays defined from xml

var stGmapMarkerTypeTag = 
// 0       1        2          3
//  ["city", "town", "village", "sight", "monument"];
// ["city", "a-monument", "town", "village", "sight"];
   [];

var stGmapMarkerTypeHdgHtml = 
//       0                     1                 2                      3
// ["Large Towns", "Towns", "Villages", "Sights", "Ancient Monument"];
// ["Large Towns", "Ancient Monuments", "Towns", "Villages", "Sights"];
 [];

var stGmapMarkerTypeImage = [];  // Marker icon image file
var stGmapMarkerTypeImageWidth = [];  // Marker icon image width
var stGmapMarkerTypeImageHeight = [];  // Marker icon image height


function stGmapsetupMarkers()
{
   var i, j, nmpage, nmmaster, found;

   nmpage = markerTypeTag.length;
//    nmmaster = stGmapMarkerTypeTag.length;  // *** now read from xml
   nmmaster = nStMarkerTypeDefs;

   for (i=0; i<maxMarkerTypes; ++i)
       markerTypeIcon[i] = default_marker;
   for (i=0; i<nmpage; ++i) {  // for markers in page data
      markerTypeIcon[i] = getstGIcon(markerTypeTag[i]);
      found = 0;
      for (j=0; j<nmmaster; ++j) {  // find index in master list
         if (markerTypeTag[i] == stGmapMarkerTypeTag[j]) {
           found = 1;   // note match
             // define entries for current marker in position i of page list
            markerTypeHdgHtml[i] = stGmapMarkerTypeHdgHtml[j];
            markerTypeImage[i] = stGmapMarkerTypeImage[j];
            markerTypeImageWidth[i] = stGmapMarkerTypeImageWidth[j];
            markerTypeImageHeight[i] = stGmapMarkerTypeImageHeight[j];
            markerTypeIcon[i] = getstGIcon(markerTypeTag[i]);   // uses values defined just above
         }
      }
      if (found == 0)
         alert("Marker type " + markerTypeTag[i] + " not valid in ST list!");
   }
}
      
function getstGIcon(markerType)
{
   var p = marker_default_imgpath;
   var gicon = new GIcon;
   var giconsize;
   gicon.image = default_marker.image;
   gicon.iconSize = default_marker.iconSize;
   gicon.iconAnchor = default_marker.iconAnchor;
   gicon.infoWindowAnchor = default_marker.infoWindowAnchor;
          // define icon object from corresponding attributes for marker
   for (var i=0; i<markerTypeTag.length; ++i) {
      if (markerTypeTag[i] == markerType) {
         gicon.image = p + markerTypeImage[i];

         giconsize = new GSize(markerTypeImageWidth[i], markerTypeImageHeight[i]);
         gicon.iconSize = giconsize;
      }
   }

   return gicon;
}


// FUNCTION This function creates a marker with a label for each point created below
function createMarker(point, icon, info, label) 
{
//    var marker = new GMarker(point, icon);
   var marker = new GMarker(point, {title:label,icon:icon});
   GEvent.addListener(marker, "click", function() {
      marker.openInfoWindowHtml(info);}
     );

   return marker;
}

// FUNCTION This function creates a link and saves display info for a gmap marker
//          in a specified division
function createMarkerLink(marker, linktext, info, linkdiv) 
{
   // Add html to marker link division to link to marker
   gmarkers[stMarkerNo] = marker;
   htmls[stMarkerNo] = info;
   if (linktext != "") {
         document.getElementById(linkdiv).innerHTML += 
           '<p><a href="javascript:findmarker(' + stMarkerNo + ')">' + linktext + '</a></p>';
        stMarkerNo++;
   }
}

// FUNCTION This function picks up the click and opens the corresponding info window
function findmarker(i) {
   savedmap.setCenter(gmarkers[i].getPoint());
   gmarkers[i].openInfoWindowHtml(htmls[i]);
}


// FUNCTION This function defines the innerHTML for a division
function setHtmlInDiv(division, html)
{
   if (html)
      document.getElementById(division).innerHTML = html;
   else
      document.getElementById(division).innerHTML = "";
}

// FUNCTION This function defines the innerHTML for a division
function addHtmlToDiv(division, html)
{
      document.getElementById(division).innerHTML += html;
}


// FUNCTION add one or more lines defined in passed xml collection to map
//          for paths with the checkbox for their path type currently checked
function stGmapDrawLines(stGmap, xmlLineElementList) 
{
         // process each line element and point subelements
   for (var i=0; i < xmlLineElementList.length; ++i) {
         // determine path types checkbox index and whether checked or unchecked
      var pchecked = 0;
      for (var p=0; p<markerTypeTag.length; ++p) {
         if (markerTypeTag[p] == xmlLineElementList[i].getAttribute("ptype"))
            pchecked = stCheckState[p];
      }

      if (pchecked) {  // generate path if checkbox for path type is selected
            // get attributes applicable to line
         var color=xmlLineElementList[i].getAttribute("color");
         var width = parseFloat(xmlLineElementList[i].getAttribute("width"));
            // get points defined for line
         var points = xmlLineElementList[i].getElementsByTagName("point");
         var point = [];
         for (var j=0; j<points.length; ++j){
            point[j] = new GLatLng(parseFloat(points[j].getAttribute("lat")), 
                                   parseFloat(points[j].getAttribute("lng")));
         }
         stGmap.addOverlay(new GPolyline(point,color,width));
      }
   }
}


// FUNCTION This is the main function called from a Slow Travel page to open
//          a Google map based on a passed XML file
function stGmapLoad(stGmapXmlSource, stGmapCenterLat, stGmapCenterLng, stGmapZoom, stGmapType) 
{

   if (!GBrowserIsCompatible()) {
      alert("Your browser doesn't support Google maps!");
      return;
   }

   if (first) {
      first = 0;   // create map on load, reuse on subsequent calls

   for (var i=0; i < maxMarkerTypes; ++i)
      stCheckState[i] = 1;

//   stGmap = new GMap2(document.getElementById(mapdiv));
           // pointer instead of hand cursor
   stGmap = new GMap2(document.getElementById(mapdiv), {draggableCursor: 'default'}); 

   savedmap = stGmap;  // for access by authoring interactive functions
// if in interactive mode, add event to map to allow adding a marker 
// at a clicked point (clicking on an added marker removes it)

if (authorInteract) {

   GEvent.addListener(stGmap, 'click', function(marker, point) { 
      if (marker) {
         if (issavedpoint) {
            if (marker == savedmarker) {
               savedmap.removeOverlay(marker);
               issavedpoint = 0;
            }
         }

      } else {
        issavedpoint = 1;
        var tm = createTempMarker(point);
        savedmarker = tm;
        savedmap.addOverlay(tm);
      }
      show_mapinfo();
   });

   GEvent.addListener(savedmap, 'zoomend',  
                   function(oldzoom, newzoom) {show_mapinfo();}
   );

}


        // Set map controls
        // 6-12-08 small map control only if "medium" mode (no zoom, overview, map type controls)
   if (largeMapMode == "M") {
      stGmap.addControl(new GSmallMapControl());
   }

        // 2-4-08 suppress all controls for small map mode
   if (largeMapMode == "Y") {
      stGmap.addControl(new GLargeMapControl());
      stGmap.addControl(new GMapTypeControl());
      stGmap.addControl(new GScaleControl());
//       stGmap.addControl(new GOverviewMapControl());   // 7-10-08 fix error caused by newest google map API
      if (authorInteract == 0)                           // 7-12-08 additional fix for pointer page
         window.setTimeout("stGmap.addControl(new GOverviewMapControl());",500);
   }

   // determine type of map: Normal (G_NORMAL_MAP), satellite (G_SATELLITE_MAP) or hybrid (G_HYBRID_MAP)
   // User call may specify this last parameter as "M", "S", or "H"; if missing the map
   // type defaults to G_MAP_TYPE
   var gMapType, mapTypeAbbrev;
   if (stGmapType == null)
      mapTypeAbbrev = "M";
   else
      mapTypeAbbrev = stGmapType;
   if (mapTypeAbbrev == "S") {
//      gMapType = G_SATELLITE_TYPE;   // fix 10-31-08
      gMapType = G_SATELLITE_MAP;

   }
   else {
      if (mapTypeAbbrev == "H")
//         gMapType = G_HYBRID_TYPE;   // fix 10-31-08
         gMapType = G_HYBRID_MAP;
      else
//         gmapType = G_MAP_TYPE;   // fix 10-31-08
         gmapType = G_NORMAL_MAP;   // fix 10-31-08
   }
 
        // Set center of map, scale, type of map
   stGmap.setCenter(new GLatLng(stGmapCenterLat,stGmapCenterLng), stGmapZoom, gMapType);


        // if in interactive mode, do initial map settings display
   if (authorInteract)
      show_mapinfo();
        
// *** move to xml reading section below:   stGmapsetupMarkers();

   }  // if first
   else 
      stGmap.clearOverlays();

       // if no xml file to load, exit here
   if (stGmapXmlSource == "noxml")
      return;


        // Download the data in xml file
   GDownloadUrl(stGmapXmlSource, function(data, responseCode) {
   var xml = GXml.parse(data);

   var locations = xml.documentElement.getElementsByTagName("locations");

   nStMarkerTypeDefs = getSTMarkerTypeDefs(xml)
   var nmtypes = getPageMarkerTypes(locations[0]);

   stGmapsetupMarkers();

   if (largeMapMode == "Y")   // 2-4-08
      setHtmlInDiv(markerLinkDiv, "");

           // following moved to fixed html 9-26-06
//    addHtmlToDiv(markerLinkDiv, '<h2>List of Markers</h2>');
//    addHtmlToDiv(markerLinkDiv, '<p>Use checkbox to show/hide markers</p>');

   for (var mtype = 0; mtype < nmtypes; ++mtype) {

// ************ checkbox ******************************************************
      var checkStateHtml = " ";
      if (stCheckState[mtype])
         checkStateHtml = ' checked ';

         if (largeMapMode == "Y")   // 2-4-08
            addHtmlToDiv(markerLinkDiv, 
                    '<h3>'
                    + '<input type="checkbox" name="stShowItype'
                    + mtype 
                    + '"'
                    + checkStateHtml
                    + 'value="' + mtype + '"'
                    + 'onclick="toggleMarkerType('
                    + mtype
                    + ')"'
                    + ' />'
                    + ' ' 
// ************ end checkbox ******************************************************

                     + '<img border="0" src="' 
//                     + marker_default_imgpath
					 + markerTypeIcon[mtype].image 
                     + '" > '
                     + markerTypeHdgHtml[mtype]
                     + '</h3>');

    if (stCheckState[mtype]) {
     // Get data from xml file for selected location type
     var markers = locations[0].getElementsByTagName(markerTypeTag[mtype]);
     var icon = markerTypeIcon[mtype];
        // Write sidebar heading
//      addHtmlToDiv(markerLinkDiv, markerTypeHdgHtml[mtype]);
          // Loop through entries for this marker type
     for (var i = 0; i < markers.length; i++) {
//       var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
//                         parseFloat(markers[i].getAttribute("lng")));
      var xmllat = markers[i].getAttribute("lat");
      var xmllng = markers[i].getAttribute("lng");
      var islatlng = 1;
      if (xmllat == "" || xmllng == "") 
         islatlng = 0;

       if (islatlng) {
         var point = new GLatLng(parseFloat(xmllat),
                         parseFloat(xmllng));
         var info = markers[i].getAttribute("info");
         var linkref = markers[i].getAttribute("lname");
         var lmarker = createMarker(point, icon, info, linkref);
         stGmap.addOverlay(lmarker);
         if (largeMapMode == "Y")   // 2-4-08
            createMarkerLink(lmarker, linkref, info, markerLinkDiv);
       }
           // could add else to list marker name with no link here

     }
    }
   }
      
      // Add any polygonal lines defined in XML file to map
   stGmapDrawLines(stGmap, xml.documentElement.getElementsByTagName("line"));
   });

   return stGmap;
} 

// 2-4-08 alternative main function to display map in small mode
function stGmapLoadSmall(stGmapXmlSource, stGmapCenterLat, stGmapCenterLng, stGmapZoom, stGmapType) 
{
largeMapMode = "N";  // set global to suppress controls and marker list division
stGmapLoad(stGmapXmlSource, stGmapCenterLat, stGmapCenterLng, stGmapZoom, stGmapType);
}


function toggleMarkerType(i)
{
   if (stCheckState[i] == 0)
      stCheckState[i] = 1;
   else
      stCheckState[i] = 0;
   load();
}


function getSTMarkerTypeDefs(xml)
{
   var nMtypeDefs;
   var mTypeDefs, mTypeDef;
   mTypeDefs = xml.documentElement.getElementsByTagName("stmarkerdefs");
   mTypeDef = mTypeDefs[0].getElementsByTagName("markerdef");
   
   for (var i=0; i < mTypeDef.length; ++i) {
      stGmapMarkerTypeTag[i] = mTypeDef[i].getAttribute("name");
      stGmapMarkerTypeHdgHtml[i] = mTypeDef[i].getAttribute("label");
      stGmapMarkerTypeImage[i] = mTypeDef[i].getAttribute("image");
      stGmapMarkerTypeImageWidth[i] = mTypeDef[i].getAttribute("width");
      stGmapMarkerTypeImageHeight[i] = mTypeDef[i].getAttribute("height");
   }

   return mTypeDef.length;
}


function getPageMarkerTypes(l)
{
   var nMtypesInXml;
   nMtypesInXml = 0;

   for (var i=0; i < stGmapMarkerTypeTag.length; ++i) {
      stmtype = stGmapMarkerTypeTag[i];
            // see if locations on page include current marker type

      if (l.getElementsByTagName(stmtype).length > 0) {
         markerTypeTag[nMtypesInXml] = stmtype;
         ++nMtypesInXml;
      }
   }
   return nMtypesInXml;
}


// interactive authoring functions
// helper create function for creating an on-the-fly deleteable marker

function createTempMarker(point) {
var tpoint = point;
savecoords(tpoint);

   if (savedmarker)
      savedmap.removeOverlay(savedmarker);

  var marker = new GMarker(point, {icon: moveableicon, title: point});

  return marker;
}



function savecoords(point)
{
//    savedpointhtml = point.y;
   savedpointhtml = point.lat();
//   savedpointhtml += "<br />" + point.x;
   savedpointhtml += "<br />" + point.lng();
   savedpoint = point;
}


function setAuthorInteract(flag)
{
   authorInteract = flag;
   setCenterAtPointer(1);   // by default, center map at placed pointer
   
}

function setCenterAtPointer(flag)
{
   centerAtPointer = flag;
}


// display current map settings and authoring marker coordinates
function show_mapinfo()
{
        // if an author pointer is defined and automatic centering is set, center map at pointer
   if (issavedpoint) {
      if (centerAtPointer)
         savedmap.setCenter(savedpoint);
   }

   setHtmlInDiv(mapInfoDiv, "");
   addHtmlToDiv(mapInfoDiv, '<h2>Define a Marker</h2>');
   addHtmlToDiv(mapInfoDiv, '<p>Click to place the marker; the marker information is displayed below. Cut and paste to the input form.</p>');

   var xp = "<p><strong>Marker (latitude/longitude):</strong>";
   if (issavedpoint)
      xp += "<br />" + savedpointhtml;
   else
      xp += "<br />" + "(none)";

   xp += "</p>";

   addHtmlToDiv(mapInfoDiv, xp);
   addHtmlToDiv(mapInfoDiv, '<p><strong>Zoom Level:</strong> ' + savedmap.getZoom() + '</p>');
}

var winObj;

// function to open a new window containing a slow view: used from a marker's infowindow in a map
function openSvWin(url)
{ 
   if (winObj) {
      if (!winObj.closed)
        winObj.close();
   }
    winobj = window.open(url,"svWin","left=10,top=10,width=800,height=805,resizable=yes,location=no,menubar=yes,scrollbars=yes,toolbar=no"); 
    winobj.focus();
    return false;
}


// ************** Google geocoding **************************

var geocoder;      // global variable for geocoder object
var geocoderInputAddress;


    // instantiate geocoder - also initialize Google search object used as adjunct address search
function geo_load() {
  geocoder = new GClientGeocoder();
  initSearchControl();
}


    // function called from application page to handle address data field entered in form
function showAddressOnPointerPage(address)
{
   geocoderInputAddress = address;   // make address being geocoded accessible to helper functions
   geocoder.getLocations(address, putAddressOnMap);
}


    // putAddressOnMap() is called when the geocoder returns an
    // answer.  It adds a marker to the map at the determined point and
    // centers the map at the marker. It also adjusts the zoom level:
    // if the current setting is less than 15 it is changed to 15,
    // otherwise the current zoom level stays unchanged.
function putAddressOnMap(response) {
   if (!response || response.Status.code != 200) {

        // if geocoding fails, try local google search
     searchControl.execute(geocoderInputAddress);

//     alert("Unable to find a location \nfor the address input.");
   }
   else {  // retrieve geocoded point, place marker, and update map and location info
     place = response.Placemark[0];
     point = new GLatLng(place.Point.coordinates[1],
                         place.Point.coordinates[0]);
         // emulate user clicking the map at a point in interactive map mode
     putPointOnMap(point);
   }
}


   // emulate user clicking the map at a point in interactive map mode
function putPointOnMap(point) {
     var tm = createTempMarker(point);
     savedmarker = tm;
     savedmap.addOverlay(tm);
     setCenterAtPointer(1);
     savecoords(point);
     issavedpoint = 1;

     if (savedmap.getZoom() < 15)
        savedmap.setZoom(15);

     show_mapinfo();

}

// ===== UK extension for geocoding: try Google Ajax API for addresses not in standard geocoding API ====
   // global variable for Google Search API object
var searchCtlDiv="searchcontrol";      // division id to contain search control
var searchControl;     // Google search control object

function initSearchControl() {
      // Create a search control
   searchControl = new GSearchControl();
      // hide the interactive search input and results used by the control 
      // since our use is all automated
   hideElement(searchCtlDiv);  
      // limit to local search only
   var localSearch = new GlocalSearch();
   searchControl.addSearcher(localSearch);

         // Set the Local Search center point for the UK (no visible effect - helps search speed)
   localSearch.setCenterPoint("new GLatLng(54.70235509327093, -3.2080078125)");

           // draw search control and provide id of division to contain it
   searchControl.draw(document.getElementById("searchcontrol"));
   searchControl.setSearchCompleteCallback(this, onSearchComplete);

      // execute an inital search
//      searchControl.execute("Painswick");
 
}


function onSearchComplete(sc, searcher) {
      // if we have local search results, extract coordinates; 
      // there will be either no results or one with lat/lng coordinates
   if ( searcher.results && searcher.results.length > 0) {
      var result = searcher.results[0];
      var point=new GLatLng(parseFloat(result.lat), parseFloat(result.lng));
      putPointOnMap(point);
   }
   else {
     alert("Unable to find a location \nfor the address input.");
   }
}


function hideElement(id) {
   var elem = document.getElementById(id);
   if (elem){
         elem.style.display = 'none';
         elem.style.visibility = 'hidden';
   }
}


// ==== end UK extension to geocoding ===== //



// ****************************************************************
