
// ------------------------------------------------------
// Javascript code for dealer search form
//
// Version information:
//
// Dec 08 - written by Matt Meighan, Evergreen Software
//          matt@egreensoftware.com
// ------------------------------------------------------

// ------------------------------------------------------
// Global variables
// ------------------------------------------------------
var directions=null; // GDirections object

var debug=false;     // set to true for debug output
var starttime;       // debugging variable for timing searches
var args;            // array of GET variables the page was called with
var searchtype;      // 'distance', 'state' or 'country'

   
// ------------------------------------------------------
// init - called on page load. 
// ------------------------------------------------------

function init() 
{
   // create GDirections object for GeoCoding from location
   directions = new GDirections(null, null);

   // get the passed-in args 
   args = getUrlVars();

   // list deales based on the args that are set
   // from & miles - do distance search
   // state - state list
   // country - country list 
   if (typeof(args["miles"]) != 'undefined' 
         || typeof(args["from"]) != 'undefined')  {
      // from and miles are set, then do a distance search
      maxmiles = parseInt(args["miles"]);
      from     = urldecode(args["from"]);
      searchtype="distance";
      dosearch(from, maxmiles);
   }
   else if (typeof(args["state"]) != 'undefined') {
      searchtype="state";
      stateDealers(args["state"]);
   }
   else if (typeof(args["country"]) != 'undefined') {
      searchtype="country"
      countryDealers(args["country"]);
   }
   else {
      alert("Sorry, dealer_search called without required parameters");
      window.location="dealer_index.html";
   }
}



// ------------------------------------------------------
// Read a page's GET URL variables and return them as an associative array.
// ------------------------------------------------------
function getUrlVars()
{
   var href=window.location.href;
   var vars = [], hash;
   var hashes = href.slice(href.indexOf('?')+1).split('&');
       
   for(var i = 0; i < hashes.length; i++) {
      hash = hashes[i].split('=');
      vars.push(hash[0]);
      vars[hash[0]] = hash[1];
   }
       
   return vars;
}


// ------------------------------------------------------
// validates entered location, then gets and displays 
// dealers within maxmiles of from location
// ------------------------------------------------------
function dosearch(from, maxmiles)
{
   // debug - save start time of search
   if (debug) {
      var start=new Date();
      starttime=start.getTime();
   }

   // make sure from location is recognized by google maps 
   var geocoder = new GClientGeocoder();
   geocoder.getLatLng(from,
            function(point) {
               if (!point) {
                  alert("Sorry, location " + from + " not recognized");
                  window.location="dealer_index.html";
               } 
               else {
                  // display array of dealers that meet the search criteria
                  getDealers(point, maxmiles, "", "");
               }
             });

   return;
}

// --------------------------------------------------------
// display all the dealers for a state (no distance search)
// --------------------------------------------------------
function stateDealers(state)
{
   // display dealers array
   getDealers(null, -1, state, "");

}

// --------------------------------------------------------
// display all the dealers for a country (no distance search)
// --------------------------------------------------------
function countryDealers(country)
{
   // display dealers array
   getDealers(null, -1, "", country);

}

// ------------------------------------------------
// display the dealers in the specified array
// 
// The content div is replaced
// ------------------------------------------------
function displayDealers(dealers)
{
   var currentCity="";
   var currentState="";

   // debug code - calculate search time
   if (debug) {
      var end = new Date();
      var duration = end.getTime() - starttime;
      var seconds = duration  / 1000;
   }

   results = "<p>&nbsp;</p>\n" ;
  
   // search header
   results += "<div id='crumbs'>\n" 
		     +  "<p><a href='dealer_index.html' " 
           + " title='Return to the Dealer Locator page.'>"
           + "Dealer Locator </a> &raquo; ";

   // add second part of header depending on type of search
   if (searchtype == "distance") {
      results += " within " + args["miles"] + " miles of " 
              + urldecode(args["from"]);
   }
   else if (searchtype == "state") {
      results += states[args["state"]] + ", " + args["country"];   
   }
   else if (searchtype == "country") {
      results += "All " + args["country"] + " Dealers";   
   }

   results += "</p>\n" ;

   // debug code - show search time
   if (debug){
      results += "<p>search time: " + seconds + " seconds</p>";
   }

	results += "</div>\n";

   results += "<div id='box6'>\n";

   // handle zero results case
   if (dealers.length == 0) {
      results +=  "<blockquote>\n"
   
      results += "<p>Sorry, no dealers matched your request.</p>"
		         + "<p><a href='dealer_index.html' " 
               + " title='Return to the Dealer Locator page.'>"
               + "Try a new search</a></p>";
   }

   // convert dealers array into html content
   for (i=0; i < dealers.length; i++) {
      var d= dealers[i];

      // display state header if need be
      if (searchtype=="country" && d["state"] != currentState) {
         currentState = d["state"];
         results += "<h2 class=\"text1\">";
         results += states[currentState];
         results += "</h2>";
      }

      // display city header if need be
      if (d["city"] != currentCity) { 
         if (currentCity.length > 0) {
            results += "</blockquote>\n";
         }
         currentCity = d["city"];
         results += "<blockquote>\n"
                 + "<h4>" + currentCity ;

         if (searchtype == "distance") {
            results+= ", " + d["state"];
         }

         results += "</h4>\n"
                 + "<p>&nbsp;</p>\n";
      }

      results +=  "<blockquote>\n"
              + "<h5>" + d["name"]  + "</h5>"
              +  d["address"]    + "<br>"
              +  d["city"]       + ", "
              +  d["state"]      + " "
              +  d["zip"]        + "<br>";

      if (typeof(d["miles"]) != 'undefined') {
         results+= "<br>" + d["miles"] + " miles<br>";
      }

      results += "<br>Phone: " + d["phone"]      + "<br>";

      if (d["url"].length > 0) {
         results += "<br>Website: <a href='http://" + d["url"]  
                 +  "' target='_blank'> " + d["url"] + "</a>"
                 +  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n";
      }

      // link to google map

      var googlelink="http://maps.google.com/maps?q="
                    + urlencode(d["address"] + ","  + d["city"]
                    + ","  + d["state"] + "  " + d["zip"])
                    + "&z=10";
     
      results += "<a href='" + googlelink + "' target='_blank'>"
              + "map</a>" + "<br>";

      results +=  "</blockquote>\n";
               
   }

   results += "</blockquote>\n<\div>\n";

   // set content into div
   var target=document.getElementById("content");
   target.innerHTML = results;
}

// ------------------------------------------------
// browser-independent XMLHttpRequest
// ------------------------------------------------
function getXMLHTTPRequest() {
   try {
      req = new XMLHttpRequest();
   } catch(err1) {
      try {
      req = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (err2) {
          try {
          req = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (err3) {
              req = false;
          }
      }
   }
   return req;
}


// -----------------------------------------------------------
// returns a  dealer object created
// from an XML dealer element
//
// attributes: 
// name, address, city, state, zip, county, phone, url
// -----------------------------------------------------------
function dealerFromXML(dealerNode)
{
   // array of dealer attributes that are always present
   var attribs = ["name", "address", "city", "state", "zip", 
                  "country", "phone", "url"];

   // if xml contains 'miles' attribute, add it to the list
   if (dealerNode.getElementsByTagName("miles").length > 0) {
      attribs[attribs.length] = "miles";
   }

   // create new dealer object
   var dealer= new Object();


   // set each attribute to value of matching tag in the XML
   for (i=0; i < attribs.length; i++) {
      dealer[attribs[i]] = xmlTagContent(dealerNode, attribs[i]);
   }

   return dealer;
}

// ------------------------------------------------------
// get content value of the first specified tag from the specified 
// xml node
//
// This function is only useful if there is one and only one of the 
// specified tags in the node
// 
// Returns nodeValue of the content node of the specified tag node,
// or "" if nodeValue is undefined
// ------------------------------------------------------
function xmlTagContent(node, tagname)
{
   value = "";     // default return value
 
   // get first node in the nodelist nodelist of all tagname nodes
   elementNode = node.getElementsByTagName(tagname)[0];

   if (elementNode) {
      // get the node's first child, which will be its content
      contentNode = elementNode.firstChild;
 
      // if contentNode is non-null and has a non-null nodeValue, 
      // return the nodeValue
      if (contentNode != null && typeof(contentNode.nodeValue) 
               != 'undefined' && contentNode.nodeValue != null) {
         value = contentNode.nodeValue;
      }
   }
 
   return value;
}

// ------------------------------------------------------
// AJAX method to 
// get and display list of dealers and return them in an array. 
//
// This method takes four parameters:
//
// GLatLng - the starting point for a distance search
// maxmiles - the max number of miles from GLatLng
// state 
// country
//
// If both GLatLng and maxmiles are set, then a distance search
// is performed.
// Otherwise, if state is set, a state search is performed
// Otherwise, if country is set, a country search is performed
// If GLatLng, state & country are all null, all dealers are returned 
//
// This method calls dealerlist.php; the only difference for the
// difference searchs is the parameter list to dealerlist.php
//
// Each array element is an object representing one dealer
// ------------------------------------------------------
function getDealers(GLatLng, maxmiles, state, country)
{
   var http = getXMLHTTPRequest();

   dealers=new Array();

   // send synchronous request 
   rand = parseInt(Math.random()*999999999999999);
  
   var url = "dealerlist.php?rand=" + rand ;

   if (GLatLng != null && maxmiles >= 0) {
      url += "&lat="   + GLatLng.lat()
          +  "&lng="   + GLatLng.lng()
          +  "&miles=" + maxmiles;
   }
   if (state.length > 0) {
      url += "&state=" + state ;
   }
   if (country.length > 0) {
      url += "&country=" + country ;
   }

   // for debug alert(url);

   // set callback function
   http.onreadystatechange = function() {
	   if(http.readyState == 4) {
          if (http.status == 200) {
             if (http.responseXML==null) {
                // dealerlist.php file did not return valid xml - probably
                // displaying a php or mysql erorr messge
                alert("Error getting dealers "); 
             }
             else {
                dealerNodes=http.responseXML.getElementsByTagName("dealer"); 
                for (var i=0; i < dealerNodes.length; i++) {
                   dealers[i]=dealerFromXML(dealerNodes[i]);
                }
                // call display function
                displayDealers(dealers);
             }
          } 
          else {
             // http error
             alert("HTTP Error getting dealers: " + http.status);
	       }
       }
   }

   // make ASYNC http call
   http.open("GET", url, true);
   http.send(null);

   return ;
}

// ------------------------------------------------------
// check validity of search form inputs. 
// Display message for any problem inputs.
// return true if all inputs valid, false if not all valid
// ------------------------------------------------------
function validateInput()
{
   var miles = parseInt(document.getElementById("miles").value); 
   var from  = trim(document.getElementById("from").value); 

   if (isNaN(miles) || from.length == 0) {
      alert("Sorry, both miles and location must be filled in"
           + " and miles must be a number. Please try your search again.");
      return false;
   }

   return true;
}


// ------------------------------------------------------
// trim whitespace from beginning and end of str
// ------------------------------------------------------
function trim(str)
{
   return str.replace(/^\s*|\s*$/g,"");
}

// ------------------------------------------------------
// urldecode 
//
// http://kevin.vanzonneveld.net
// original by: Philip Peterson
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// note: info on what encoding functions to use from: 
// http://xkr.us/articles/javascript/encode-compare/
// ------------------------------------------------------
function urlencode( str ) 
{
                                     
    var histogram = {}, histogram_r = {}, code = 0, tmp_arr = [];
    var ret = str.toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urldecode.
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    
    // Begin with encodeURIComponent, which most resembles 
    // PHP's encoding functions
    ret = encodeURIComponent(ret);
    
    for (search in histogram) {
        replace = histogram[search];
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }
    
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
    
    return ret;
}

// ------------------------------------------------------
// urldecode 
//
// http://kevin.vanzonneveld.net
// original by: Philip Peterson
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// ------------------------------------------------------
function urldecode( str ) {
    
    var histogram = {}, histogram_r = {}, code = 0, str_tmp = [];
    var ret = str.toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urlencode.
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    
    for (replace in histogram) {
        search = histogram[replace]; // Switch order when decoding
        ret = replacer(search, replace, ret) // Custom replace. No regexing   
    }
    
    // End with decodeURIComponent, which most resembles PHP's functions
    ret = decodeURIComponent(ret);
 
    return ret;
}
