/**
 * Class to carry out geocoding functions based on:
 * - city
 * - street name
 * - zip code
 *
 * @author: Akshay Bhurtun
 * $Id: geocodeutils.js,v 1.11 2009/02/23 05:55:12 vpulla Exp $
 */


var geocodingTimer = false;
var addressElemNames = new Array("city", "cityDistrict", "street", "houseNumber", "zipcode", "state", "longitude", "latitude");
var cName = "[GeoCoder] ";

function GeoCoder(outputElemId_, form_, inputElement_)
{
   var outputElemId = outputElemId_;
   var form = form_;
   var inputElement = inputElement_;
   var addressValue;
   var geoDataSource = "Australia";
   var locateProperties = {maxResults:10};
   
   var self = this;
   this.geocode = geocode;
   
   function geocode() 
   {
      var fnName = cName + "geocode() ";
      var address = new com.ptvag.mnp.common.Address();
      
      var elements = form.getElementsByTagName("input");

      address.zipcode = XMLUtils.getFormElementByName(elements, form.id + ".zipcode").value;//elements[form.id + ".zipcode"].value;
      address.city = XMLUtils.getFormElementByName(elements, form.id + ".cityDistrict").value;//elements[form.id + ".cityDistrict"].value;
      address.street = XMLUtils.getFormElementByName(elements, form.id + ".street").value;//elements[form.id + ".street"].value;
      address.country = XMLUtils.getFormElementByName(elements, form.id + ".country").value;//elements[form.id + ".country"].value;
      address.cityDistrict = "";
      
      mLocation = new com.ptvag.mnp.location.Location();
      mLocation.locate(address, locateProperties, geoDataSource, Geocode_cb);
   };
   
   this.reverseGeoCode=function reverseGeoCode(realCoordinate, callbackFn)
   {
      var fnName = cName + "reverseGeoCode() ";
      var mLocation = new com.ptvag.mnp.location.Location();
      //var smartCoord = ptvWrapper.getSmartCoordinate(realCoordinate);
      var coord = new com.ptvag.mnp.common.Coordinate();
      coord.CoordType = "GEODECIMAL";
      coord.x = Math.round(realCoordinate.longitude*conf_smartUnitToGeoFactor);
      coord.y = Math.round(realCoordinate.latitude*conf_smartUnitToGeoFactor);
      
      log.debug(fnName, "updated x [" + coord.x + "] [" + coord.y + "]");
      
      var reverseLocationProperties = new com.ptvag.mnp.location.ReverseLocateProperties();
      reverseLocationProperties.tolerance = 100;
      reverseLocationProperties.maxResults = 1;
      
      mLocation.reverseLocate(coord, reverseLocationProperties, geoDataSource, 
         function(geocodeAddressList,exc)
         {
            if (exc) 
            {
               alert("error [" + exc + "]");
               return false;
            }
            
            var reverseGeoCoded = "";
            log.debug(fnName, "number of results [" + geocodeAddressList.addresses.length + "]");
            if(geocodeAddressList != null && geocodeAddressList.addresses.length > 0)
            {
               for(var i=0; i<addressElemNames.length-2; i++)
               {
                  var value = null;
                  eval("value=geocodeAddressList.addresses[0]." + addressElemNames[i]);               
                  if(addressElemNames[i] == "state")
                  {
                     value = toState(geocodeAddressList.addresses[0].country);
                     geocodeAddressList.addresses[0].state=value;
                  }
                  
                  if(i>0)
                     reverseGeoCoded += '|';
                  reverseGeoCoded += value;
               }
               log.debug(fnName, "reverseGeocoded [" + reverseGeoCoded + "]");
               
               realCoordinate.address=geocodeAddressList.addresses[0];
            }
            if(callbackFn != null)
               callbackFn(realCoordinate);
         });
   };
   
   /**
    * This function converts a 2Letter PTV state to a 3 letter version
    *
    * 
    */
   function toState(country)
   {
      var ptvState = country.split("-")[1];
      var result = null;
      if ("VI" == ptvState)
         result = "VIC";
      else if ("SW" == ptvState)
         result = "NSW";
      else if ("QL" == ptvState)
         result = "QLD";
      else if ("TA" == ptvState)
         result = "TAS";
      else if ("AC" == ptvState)
         result = "ACT";
      else  // NT, SA, WA
         result = ptvState;
      return result;
   }
   
   function Geocode_cb(geocodeAddressList,exc)
   {
      var fnName = cName + "Geocode_cb() ";
      geocodingTimer = false;
      if (exc) 
      {
         handleError(exc);
         return false;
      } 
      log.debug(fnName, "list returned");
      var addressArr = geocodeAddressList.addresses;
      
      // hide wait symbol at station again:
      //Effect.Fade($('ajaxloaderstation'+GeocodeStation));
   
      // cache geocode proposal list at station property "geocodelist":
      //getStation(GeocodeStation).geocodelist = addressArr;
      var output = document.getElementById(form.id + ".selection");
      if (addressArr.length==0)
      {
         output.innerHTML = "Address Not found [" + inputElement.value + "]";
      }
      else 
      {
         arr_locations = addressArr;
         var selectoptions = "";
         for (i=0;i<(arr_locations.length);i++)
         {
            if (i%2 == 0) 
               optstyle = "even"
            else
               optstyle = "odd"
   
            /*if (i==0)
               selectedstr = " selected";
            else
               selectedstr = "";*/
                        
            // Serialize address suggest entry:
            // city cityDistrict|street houseNumber|zipCode|longitude|latitude|geoCodeType
            if(addressArr[i].cityDistrict == null || addressArr[i].cityDistrict.length == 0)
               addressArr[i].cityDistrict =addressArr[i].city; 
            addressValue = ""+addressArr[i].city + "|" + addressArr[i].cityDistrict + "|" + 
                           addressArr[i].street + "|" + addressArr[i].houseNumber+ "|" + 
                           addressArr[i].zipcode + "|" + toState(addressArr[i].country) + "|" +
                           (addressArr[i].coordinate.x/conf_smartUnitToGeoFactor) + "|" + (addressArr[i].coordinate.y/conf_smartUnitToGeoFactor) + "|" + addressArr[i].coordinate.coordinateType;
            
            
            // visible option text:
            locationstring = addressArr[i].zipcode + " " +  addressArr[i].city + " " + addressArr[i].cityDistrict + " " + addressArr[i].street + " " + addressArr[i].houseNumber + "<br>";
   
            // add option tag:
            //selectoptions += '<option'+ selectedstr +' class='+ optstyle +' value="'+ addressValue + '">'+ locationstring +'</option>';
            selectoptions += "<div class=\"" + optstyle + "\" onclick=\"GeoCoder.selectAddress('" + addressValue + "', '" + form.id + "')\">" + locationstring + "</div>"
         }
   
         //log.debug(fnName, "<select>" + selectoptions + "</select>");
         //output.innerHTML = '<select style="height:auto" onclick="GeoCoder.selectAddress(this.value, ' + form.name + ')">' + selectoptions + "</select>";
         output.innerHTML = selectoptions;
      }
   };
}


/**
 * Static function that is invoked when the user enters data for the address
 *
 */
GeoCoder.tryGeoCode=function tryGeoCode(formName, currentElement)
{
   var fnName = cName + "tryGeoCode() ";
   
   if(currentElement.value.length <= 3)
      return;
   if(!geocodingTimer)
   {
      geocodingTimer = true;
      document.getElementById(formName + ".selection").innerHTML = "<img src='" + conf_geocodeLoadingImg +"'/>"; 
      setTimeout("GeoCoder.performGeoCode('" + formName + "', '" + currentElement.name + "')", 1000);
      //setTimeout("alert('hey hey')", 1000);
   }
}

GeoCoder.performReverseGeoCode=function performReverseGeoCode(realCoordinate, callbackFn)
{
   var geoCoder = new GeoCoder();
   geoCoder.reverseGeoCode(realCoordinate, callbackFn);
};

/**
 * Function that is invoked by tryGeoCode function after a delay
 * 
 */
GeoCoder.performGeoCode=function performGeoCode(formName, currentElementName)
{
   var fnName = cName + "performGeoCode() ";
   var currentForm = document.getElementById(formName);
   
   var inputs = currentForm.getElementsByTagName("INPUT");
   var currentElement = XMLUtils.getFormElementByName(inputs, currentElementName);
   //alert("currentElement [" + currentElementName + "] [" + XMLUtils.getFormElementByName(inputs, currentElementName) + "]");
   log.debug(fnName, "geocoding [" + currentElement.value + "]");
   
   var geoCoder = new GeoCoder("output", currentForm, currentElement);
   geoCoder.geocode();
}

GeoCoder.selectAddress=function selectAddress(data, formDiv)
{
   var fnName = cName + "selectAddress() ";
   log.debug(fnName, "geocoder [" + data + "]");
   
   var addressElems = data.split("|");
   
   log.debug(fnName, "Number of elems [" + addressElems.length + "]");
   /*for(var i=0; i<addressElems.length; i++)
   {
      log.debug(fnName, "[" + i + "] - [" + addressElems[i] + "]");
   }*/
   var formInputElements = document.getElementById(formDiv).getElementsByTagName("input");
   var formSelectElements = document.getElementById(formDiv).getElementsByTagName("select");
   
   for(var i=0; i<addressElemNames.length; i++)
   {
      //var formElement = formInputElements[formDiv + "." + addressElemNames[i]];
      var formElement = XMLUtils.getFormElementByName(formInputElements, formDiv + "." + addressElemNames[i]); 
      
      if(formElement == null)
         formElement = XMLUtils.getFormElementByName(formSelectElements, formDiv + "." + addressElemNames[i]);
         //formElement = formSelectElements[formDiv + "." + addressElemNames[i]];
      
      if(formElement != null)
         formElement.value = addressElems[i];
      
   }
}

/**
 * Util function to clear the input elements in an address field form
 * @param formId - the form with ID formId to be cleared
 * @param excludeElems - map of elements in the form to be excluded from being cleared
 *                       format {foo:true} will cause element with name "foo" to be
 *                       cleared in the form  
 */
GeoCoder.clearForm=function clearForm(formId, excludeElems)
{
   var formElements = document.getElementById(formId).getElementsByTagName("input");
   for(var i=0; i<formElements.length; i++)
   {
      if(formElements[i].type == "text" || formElements[i].type == "hidden")
      {
         var doExclude = false;
         if(excludeElems != null)
         {
            var name = formElements[i].name;
            eval("doExclude = excludeElems" + name.substring(name.lastIndexOf("."), name.length));
         }
         if(!doExclude)
            formElements[i].value = "";
      }
   }
   
   var formSelectElements = document.getElementById(formId).getElementsByTagName("select");
   
   for(var i=0; i<formSelectElements.length; i++)
   {
      formSelectElements[i].selectedIndex=0;
   }
}

GeoCoder.currentMarker = null;

/**
 * Util function to display an address onto a map
 */

GeoCoder.displayMap=function displayMap(formId, currentMap)
{
   var fnName = cName + "displayMap() ";
   
   var currentForm = document.getElementById(formId);
   var formElements = currentForm.getElementsByTagName("input");
   var longitude = parseFloat(formElements[formId + ".longitude"].value);
   var latitude = parseFloat(formElements[formId + ".latitude"].value);
   
   var smartCoordinate = ptvWrapper.getSmartCoordinate({longitude:longitude,latitude:latitude});
   
   if(currentMap == null)
      currentMap = map;
   currentMap.setCenter(smartCoordinate);
   
   if(GeoCoder.currentMarker != null)
      currentMap.getLayer("vector").removeElement(GeoCoder.currentMarker);
   
   GeoCoder.currentMarker = currentMap.getLayer("vector").addElement(new com.ptvag.webcomponent.map.vector.ImageMarker(smartCoordinate.x, smartCoordinate.y, conf_defaultMarkerImg, 65));
   currentMap.setViewToPoints([smartCoordinate], false, false);
   log.debug(fnName, "Longitude [" + longitude + "] latitude [" + latitude + "]");
}




