//****************************************************
//                         Global Variables
//****************************************************
var map = null;                           // GMap2 object
var kLocs = new Array();                  // Array of kennel objects
var dir;                                  // Directions object
var dirErr = new Array();                 // Array of error text for direction failure
var gCoder;                               // GGeoCoder object
var dest;                                 // Marker holding vacation destination
var defaultCenter;                        // Center map to this location on errors
var dIcon;
var kIcon;
var globKID = 0;
var isPrivate = false;

//****************************************************
//                         Object definitions
//****************************************************

function kennel(k)
{
   // These first variables correspond directly to fields in the database
   this.lat         = k.getAttribute("lat");
   this.lng         = k.getAttribute("lng");
   this.kName       = k.getAttribute("name");
   this.descr       = k.getAttribute("descr").substr(0, 128);     // Truncate description at 128 chars
   this.id          = k.getAttribute("id");
   this.add1        = k.getAttribute("add1");
   this.add2        = k.getAttribute("add2");
   this.city        = k.getAttribute("city");
   this.state       = k.getAttribute("state");
   this.country     = k.getAttribute("country");
   this.countryName = k.getAttribute("countryName");
   this.zip         = k.getAttribute("zip");
   this.phone       = k.getAttribute("phone");
   this.phone2      = k.getAttribute("phone2");
   this.fax         = k.getAttribute("fax");
   this.email       = k.getAttribute("email");
   this.web         = k.getAttribute("web");
   this.sleds       = k.getAttribute("sleds");
   this.carts       = k.getAttribute("carts");
   this.skijor      = k.getAttribute("skijor");
   this.kts         = k.getAttribute("kts");
   this.len1        = k.getAttribute("len1");
   this.len2        = k.getAttribute("len2");
   this.Drive       = k.getAttribute("drive");
   this.est         = k.getAttribute("est");
   this.guests      = k.getAttribute("guests");
   this.start       = k.getAttribute("start");
   this.level       = k.getAttribute("level");
   this.contact     = k.getAttribute("contact");
   this.skiname     = k.getAttribute("skiname");
   this.skidist     = k.getAttribute("skidist");
   this.low_price   = k.getAttribute("low_price");
   this.high_price  = k.getAttribute("high_price");
   this.email_count = k.getAttribute("email_count");
   this.adminPriv   = k.getAttribute("adminPriv");
   this.userPriv    = k.getAttribute("userPriv");
   this.lastLog     = k.getAttribute("lastLog");

   this.onMap = false;
   this.dist = 0;          // Distance to the users location
   this.tText = '<div class="kMarker"><h1>'+this.kName+'</h1>\n<p>'+this.descr+'...</p></div>';
   // Only create a marker if it makes sense to create one
   if( (Math.abs(this.lat) + Math.abs(this.lng)) > 1)
   {
      if(isPrivate)
         this.marker = createKMarker(new GLatLng(this.lat, this.lng), this.tText, { title:this.kName, icon: kIcon, draggable: true });
      else
         this.marker = createKMarker(new GLatLng(this.lat, this.lng), this.tText, { title:this.kName, icon: kIcon });
   }
   else
      this.marker = null;

   this.addToMap = addToMap;
   this.removeFromMap = removeFromMap;
}

function addToMap()
{
   if(this.marker)
   {
      if(!this.onMap)
      {
         map.addOverlay(this.marker);
         this.onMap = true;
      }
   }

   return this.onMap;
}

function removeFromMap()
{
   if(this.marker)
   {
      if(this.onMap)
      {
         map.removeOverlay(this.marker);
         this.onMap = false;
      }
   }

   return this.onMap;
}

//****************************************************
//                Kennel Object Support functions
//****************************************************
function findIndexByID(id)
{
   var len = kLocs.length;
   for(var i=0; i<len; i++)
   {
      if(kLocs[i].id == id)
         return i
   }

   return -1;
}

function sortByDist(a, b)
{
   return ((a.dist < b.dist) ? -1 : ((a.dist > b.dist) ? 1 : 0));
}

function sortByName(a, b)
{
   return ((a.kName < b.kName) ? -1 : ((a.kName > b.kName) ? 1 : 0));
}

function removeKennelMarkers(start)
{
   var len = kLocs.length;

   for(var i=start; i<len; i++)
      kLocs[i].removeFromMap();
}

//****************************************************
//                         Other Functions
//****************************************************
function initPublic(id)
{
   if(GBrowserIsCompatible())
   {
      defaultCenter = new GLatLng(40.4360054452,-86.911708832);
      map = new GMap2(document.getElementById("mapDIV"));
      map.setCenter(defaultCenter, 4);
      map.setUIToDefault();

      dir = new GDirections(map, document.getElementById("directionsDIV"));
      gCoder = new GClientGeocoder();

      kIcon = new GIcon(G_DEFAULT_ICON, "http://www.dogsledrides.com/images/hunting.png");
      kIcon.shadow = "http://www.dogsledrides.com/images/shadow.png";
      dIcon = new GIcon(kIcon, "http://www.dogsledrides.com/images/house.png");

      globKID = id;
      loadAllKennels();
      loadErrorMessages()

      // === catch Directions errors ===
      GEvent.addListener(dir, "error", function() {
        var code = dir.getStatus().code;
        var reason = "Code "+code;
        if (dirErr[code]) {
          reason = dirErr[code]
        } 

        alert("Failed to obtain directions, "+reason);
      });
   }
}

function initPrivate(id)
{
   if(GBrowserIsCompatible())
   {
      defaultCenter = new GLatLng(40.4360054452,-86.911708832);
      map = new GMap2(document.getElementById("mapDIV"));
      map.setCenter(defaultCenter, 4);
      map.setUIToDefault();

      kIcon = new GIcon(G_DEFAULT_ICON, "http://www.dogsledrides.com/images/hunting.png");
      kIcon.shadow = "http://www.dogsledrides.com/images/shadow.png";
      dIcon = new GIcon(kIcon, "http://www.dogsledrides.com/images/house.png");

      globKID = id;
      isPrivate = true;
      loadAllKennels();

      GEvent.addListener(map, "click", function(o, l, ol) {
         // Map clicked, find out where, move kLoc to that location, show coords in save form
         var ind = findIndexByID(globKID);
         if(kLocs[ind].marker)
            kLocs[ind].marker.setLatLng(l);
         else
         {
            kLocs[ind].marker = createKMarker(new GLatLng(l.lat(), l.lng()), kLocs[ind].tText, { title:kLocs[ind].kName, icon: kIcon, draggable: true });
            kLocs[ind].addToMap();
         }
         document.getElementById("lat").value = l.lat();
         document.getElementById("lng").value = l.lng();
      });
   }
}

function loadAllKennels()
{
   var args = 'q=la&o=xml';

	asProcess('/dsr_util.php', args, 'Loading all kennels...', handleLoadKennels, "messageDIV");
}

function handleLoadKennels()
{
	if(xmlHttp.readyState == 4)
	{
		var xmlDoc = xmlHttp.responseXML;
		var r = xmlDoc.getElementsByTagName("result");
      var errorCount = r[0].getAttribute("error") * 1;

      if(errorCount > 0)
      {
         map.setCenter(defaultCenter, 4);
         document.getElementById("messageDIV").innerHTML = r[0].getAttribute("errorText");
      }
      else
      {
   		var kDoc = xmlDoc.getElementsByTagName("kennel");
         var len = kDoc.length;
         for(var i=0; i<len; i++)
            kLocs[i] = new kennel(kDoc[i]);

         if(isPrivate)
            showKennelPrivate(globKID);
         else
         {
            if(globKID > 0)
               showKennel(globKID);
            else
               doMapKennels();
         }
      }
   }
}

function loadErrorMessages()
{
   // === Array for decoding the failure codes ===
   dirErr[G_GEO_SUCCESS]            = "Success";
   dirErr[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
   dirErr[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
   dirErr[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
   dirErr[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
   dirErr[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
   dirErr[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
   dirErr[G_GEO_BAD_REQUEST]        = "A directions request could not be successfully parsed.";
   dirErr[G_GEO_MISSING_QUERY]      = "No query was specified in the input.";
   dirErr[G_GEO_UNKNOWN_DIRECTIONS] = "The GDirections object could not compute directions between the points.";
}

function createKMarker(point, html, opts)
{
   var marker = new GMarker(point, opts);
   GEvent.addListener(marker, "click", function()
   {
      marker.openInfoWindowHtml(html);
   });
   return marker;
}

// Public side function to pull the kennel info to be displayed on the public map
function showKennel(id)
{
   var err = '';
   removeKennelMarkers(0);
   var ind = findIndexByID(id);
   if(ind > 0)
   {
      if(kLocs[ind].addToMap())
      {
         map.setCenter(kLocs[ind].marker.getLatLng(), 13);
         document.getElementById("kName").innerHTML = kLocs[ind].kName;
      }
      else
         err = kLocs[ind].kName + " is not mapped.";
   }
   else
      err = "This kennel does not exist.";

   if(err)
   {
      document.getElementById("messageDIV").innerHTML = err;
      map.setCenter(defaultCenter, 4);
   }
}

function showKennelPrivate(id)
{
   var err = '';
   removeKennelMarkers(0);
   var ind = findIndexByID(id);
   if(ind > 0)
   {
      if(kLocs[ind].addToMap())
      {
         map.setCenter(kLocs[ind].marker.getLatLng(), 13);
         GEvent.addListener(kLocs[ind].marker, "dragend", function(l) {
            document.getElementById("lat").value = l.lat();
            document.getElementById("lng").value = l.lng();
         });
         document.getElementById("lat").value = kLocs[ind].marker.getLatLng().lat();
         document.getElementById("lng").value = kLocs[ind].marker.getLatLng().lng();
      }
      else
         err = kLocs[ind].kName + " is not mapped.";
   }
   else
      err = "This kennel does not exist.";

   if(err)
   {
      document.getElementById("messageDIV").innerHTML = err;
      map.setCenter(defaultCenter, 4);
   }
}

// This is used in the admin site to keep track of the selected kennel in the lat lng form
function changeKennel()
{
   var id = getSelectValue("kID");
   document.getElementById("id").value = id;
   showPrivateKennel(id);
}

function getDirections()
{
   // ==== set the start and end locations ====
   var saddr = document.getElementById("saddr").value
   var daddr = kLocs[0].marker.getLatLng().lat()+","+kLocs[0].marker.getLatLng().lng();
   dir.load("from: "+saddr+" to: "+daddr);
}

                  // Public side function to pull the kennel info to be displayed on the public map
function mapKennels()
{
   if(!map)
      initPublic(0);
   else
      doMapKennels();
}

function doMapKennels()
{
   var c = getSelectValue('countrySelect');
   var s = getSelectValue('stateSelect');

   removeKennelMarkers(0);
   var bounds = new GLatLngBounds();
   var len = kLocs.length;
   for(var i=0; i<len; i++)
   {
      if((kLocs[i].country == c) && (kLocs[i].state == s) && kLocs[i].marker)
      {
         kLocs[i].addToMap();
         bounds.extend(kLocs[i].marker.getLatLng());
      }
   }

   if(bounds.isEmpty())
   {
      document.getElementById("messageDIV").innerHTML = "There are no mapped kennels in this region.";
      map.setCenter(defaultCenter, 4);
   }
   else
   {
      map.setZoom(map.getBoundsZoomLevel(bounds));
      map.setCenter(bounds.getCenter());
   }
}

function getDestination()
{
   var saddr = document.getElementById('saddr').value;

   // ====== Perform the Geocoding ======        
   gCoder.getLocations(saddr, handleGeoCoder);
}

function handleGeoCoder(result)
{
      // If that was successful
      if(result.Status.code == G_GEO_SUCCESS)
      {
         // How many resuts were found
         document.getElementById("mapResults").innerHTML = "Found " +result.Placemark.length +" results";
         // Loop through the results, placing markers
         for (var i=0; i<result.Placemark.length; i++)
         {
            var p = result.Placemark[i].Point.coordinates;
            var addr = result.Placemark[i].Point.address;
            dest = new GMarker(new GLatLng(p[1],p[0]), { title: addr, icon: dIcon } );
            map.addOverlay(dest);
            // Right now we are only going to care about the first result
            break;
         }
         calculateDistance();
         var bounds = showClosest(5);
         bounds.extend(dest.getLatLng());
         map.setZoom(map.getBoundsZoomLevel(bounds));
         map.setCenter(bounds.getCenter());
      }
      // ====== Decode the error status ======
      else
      {
         var reason = "Code " + result.Status.code;
         if(dirErr[result.Status.code])
         {
           reason = dirErr[result.Status.code]
         } 
         alert('Could not find "'+saddr+ '" ' + reason);
      }
}

function calculateDistance()
{
   var len = kLocs.length;

   for(var i=0; i<len; i++)
   {
      if(kLocs[i].marker)
         kLocs[i].dist = Math.floor(dest.getPoint().distanceFrom(kLocs[i].marker.getPoint()) / 1609.344 );
      else
         kLocs[i].dist = 15000;
   }
   kLocs.sort(sortByDist);
}

function showClosest(num)
{
   var len = kLocs.length;
   num = Math.min(len, num);
   var out = '<p>The '+num+' closest kennels to you are:</p><ol>';
   var bounds = new GLatLngBounds();

   for(var i=0; i<num; i++)
   {
      if(kLocs[i].web)
         out += '<li><a href="http://'+ kLocs[i].web + '">'+ kLocs[i].kName + '</a>';
      else
         out += "<li>"+ kLocs[i].kName;
      out += ' is ' + kLocs[i].dist + ' miles away.<button type="button" onclick="getDirections('+kLocs[i].id+')">Get Directions</button></li>';
      kLocs[i].addToMap();
      bounds.extend(kLocs[i].marker.getLatLng());
   }
   out += '</ol><p>NOTE: These distances are "as the crow flies" distances and not driving distances.  Driving distances may be significantly different.</p>';

   removeKennelMarkers(num);

   document.getElementById("mapResults").innerHTML = out;

   return bounds;
}
