﻿//var pendingGeoReqs = new Array(); // array that keeps ref to the geocoding requests
var GeocodeAddress = Class.create({
    initialize: function(freeTxt, addressType) {
        this.freeTxt = freeTxt;
        this.addressType = addressType;
        this.foundMatch = false;
        this.geocoded = false;        
        this.latitude = 0.0;
        this.longitude = 0.0;
        
        this.streetAddress = null;
        this.city = null;
        this.postalCode = null;
        this.country = null;
        
        this.alternativeResults = null;
    },
    googleGeocode: function(countryCode, callBackSuccess, callBackFailure) {
        
        // TODO: we got 15k geocode tickers
        // check if the address has been already geocoded against our database
        // if not build and kick-off the google geocoding request
        var addr = this;
        
        if (true) {
            var srchReq = new google.search.LocalSearch();
            srchReq.setSearchCompleteCallback(null, function() {			
    			
			    // response came back, therefore remove the request obj from the processing array
			    addr.geocoded = true;
    			addr.alternativeResults = srchReq.results;
    			//console.dir(srchReq.results);
    			
			    if (srchReq.results[0] && srchReq.results[0].country.toUpperCase() == countryCode.toUpperCase()) {	
				    addr.latitude = srchReq.results[0].lat;
				    addr.longitude = srchReq.results[0].lng;
				    
				    addr.streetAddress = srchReq.results[0].streetAddress;
                    addr.city = srchReq.results[0].city;
                    addr.postalCode = srchReq.results[0].postalCode;
                    addr.country = srchReq.results[0].country;
				    
				    var point = new GLatLng(addr.latitude, addr.longitude);
				    addr.foundMatch = true;
				    callBackSuccess(addr);
			    } else callBackFailure(addr);
		    });	
    	    
	        // kick off the request	
	        srchReq.execute(this.freeTxt + ',' + countryCode);
	    }
    }   
});


function GeocodeAddrRequest(addrTxt, callBackFunction) {
    
    // TODO: we got 15k geocode tickers
    //       check if the address has been already geocoded against our database
    //       if not build and kick-off the google geocoding request
    
    if (true) {
    
        var srchReq = new google.search.LocalSearch();
        srchReq.setSearchCompleteCallback(null, function() {			
			
			// response came back, therefore remove the request obj from the processing array
			pendingGeoReqs.pop();
			
			if (srchReq.results[0]) {	
			
			    console.log('Local search results');
			    console.dir(srchReq.results);
				
				var resultLat = srchReq.results[0].lat;
				var resultLng = srchReq.results[0].lng;
				var point = new GLatLng(resultLat,resultLng);
				callBackFunction(point);
			} else console.log("Address not found!");
		});	
    		
	    // add the req reference to the array
	    pendingGeoReqs.push(srchReq);
	    
	    // kick off the request	
	    srchReq.execute(addrTxt + ',' + countryCode);
	    console.log('Kick-off geocode req for: ' + addrTxt);
	}
}

function ReverseGeocodeAddrResponse(point) {
    console.log('Reverse geocode the address: ' + point.lat() + ',' + point.lng()); 
    
    // we've received the point coords, therefore to get the address details we need to do the point -> point directions
    var pointDir = new google.maps.Directions();
    
    GEvent.addListener(pointDir, "load", function() {
        RevGeoOnDirectionsLoad(pointDir, point);
    });
    GEvent.addListener(pointDir, "error", function() {
        RevGeoOnDirectionsErrors(pointDir);
    });
    
    // kick-off the directions request
    pointDir.load("from: " + point.lat() + "," + point.lng() + " to: " + point.lat() + "," + point.lng(), { "locale": dirLocale, getPolyline: false, getSteps: true});
}

function RevGeoOnDirectionsLoad(pointDirObj, point){ 
    
    console.log('Rev geo directions response for: ' + point.lat() + ',' + point.lng());
    
    // if the direction request been successfull and we've got the directions
    if (pointDirObj.getNumRoutes() > 0) {
        
        var route = pointDirObj.getRoute(0);
        
        if (route.getNumSteps() > 0) {
            // get the screet name from the step
            var step = route.getStep(0);
            var street = GetStreetFromDescrHTML(step.getDescriptionHtml()) + ' ' + countryCode;
            
            console.log('Last step for: ' + point.lat() + ',' + point.lng() + '(street name:' + street + ')');
            var geoClient = new google.maps.ClientGeocoder();
            geoClient.getLocations(street, function(response) {
                RefineDirectionsGeocodeResponse(point, response);
            });
        }
        
    } else alert('Rev geo directions error!');
}

function RefineDirectionsGeocodeResponse(point, response) {
    if (!response || response.Status.code != 200) {
        alert("Sorry, we were unable to geocode that address");
    }
    else {
        console.log('Refine directions for: ' + point.lat() + ',' + point.lng());
        
        var addressMatch = GetBestMatchingPlacemark(point, response);
        console.log('Best matched placemark for: ' + point.lat() + ',' + point.lng());
        if (addressMatch) console.dir(addressMatch);
        else {
            console.log('No accurate match found, possible alternatives:');
            console.dir(response);
        }
    }
}

function RevGeoOnDirectionsErrors(pointDirObj) {
    if (pointDirObj.getStatus().code == G_GEO_UNKNOWN_ADDRESS) alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + pointDirObj.getStatus().code);
    else if (pointDirObj.getStatus().code == G_GEO_SERVER_ERROR) alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + pointDirObj.getStatus().code);	   
    else if (pointDirObj.getStatus().code == G_GEO_MISSING_QUERY) alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + pointDirObj.getStatus().code);
    //   else if (pointDirObj.getStatus().code == G_UNAVAILABLE_ADDRESS)  <--- Doc bug... this is either not defined, or Doc is wrong	//     alert("The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.\n Error code: " + pointDirObj.getStatus().code);
    else if (pointDirObj.getStatus().code == G_GEO_BAD_KEY) alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + pointDirObj.getStatus().code);
    else if (pointDirObj.getStatus().code == G_GEO_BAD_REQUEST) alert("A directions request could not be successfully parsed.\n Error code: " + pointDirObj.getStatus().code);
    else alert("An unknown error occurred.");
}

// cuts out the street from the step.getDescriptionHtml()
// If the street is a highway the surrounding tags are <wbr> instead of <b>
function GetStreetFromDescrHTML(str){
    var street = str.substring(str.lastIndexOf("<b>")+3,str.lastIndexOf("</b>"));
    if (street.lastIndexOf("/<wbr/>") > 0) {
        street = street.substring(0, street.lastIndexOf("/<wbr/>"));
    }
    return street;
}

function GetBestMatchingPlacemark(destPoint, response){
  var minDist = 15;
  var i = 0;
  var j = -1;
  
  // the result should be at least within 1 km.
  for (i = 0; i < response.Placemark.length; i++) {
    var place = response.Placemark[i];
    var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
    var temp = destPoint.distanceFrom(point);
    
    console.log('Point [' + i + '] distance: ' + temp);
    if (temp < minDist) {
      j = i;
      minDist = temp;
    }
  }
  if(j < 0 ) return null;
  return response.Placemark[j];
}