﻿/***
Get state,city, lantitude and longitude by country code(iso code) and zipcode
API provided by http://www.geonames.org and Google MAP API
required JS file:
jquery.js
common.js
http://maps.google.com/maps?file=api&v=2.x&key={google api key}

Updated:
2009/11/10: Add yahoo services to support China zipcode searching - by alan
***/
var postalcodes;// postalcodes is filled by the JSON callback
var oSelCountries;//a jquery dropdown object to store predetermined countries list
var oTxtZipCode;//a jquery textbox object to accept zipcode
var oSelCities;//a jquery dropdown object list to display cities return by country and zipcode

var oBtnSubmit;//a button to submit current form

var storedTo = "json";//store result to json or txt

var myZipCode,myLati,myLongi,myStateName,myCityName;//jquery object of textbox to store results
var jsonResult;//json object to store results


var geocoder;
var zcodetmp;
function ZipCodeCity(idSelCountries, idTxtZipCode, idSelCities) {
    zcodetmp = this;
    oSelCountries = $("#"+idSelCountries);
    oTxtZipCode = $("#"+idTxtZipCode);
    oSelCities = $("#"+idSelCities);
    
	oTxtZipCode.blur(function(){postalCodeLookup();});
	oTxtZipCode.focus(function(){this.select();oTxtZipCode.css({"color":""});});
	oTxtZipCode.keydown(function(event){return mkeydown(event);});
	function mkeydown(event)
    {
        var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
          if (keyCode == 13) 
          {
            event.keyCode=0;
            oTxtZipCode.blur();
            return false;
          }
    }
	oSelCities.change(function(){storeResult();});
	oSelCountries.change(function(){oTxtZipCode.val("");oSelCities.empty().append("<option value=''>--City(enter zip code first)--</option>");storeResult();});
	 
	try{geocoder = new GClientGeocoder();}catch(err){}
		
	//Scripts to call geonames API
	//loaded after Google API because of the performance of geonames API is unstable.
	AddScriptToHeader("http://ws.geonames.org/export/geonamesData.js");
	AddScriptToHeader("/scripts/jsr_class.js");
	//set default country
	setDefaultCountry();
	
	//Scripts dependency to call Yahoo services
	AddScriptToHeader("http://yui.yahooapis.com/2.8.0r4/build/yahoo/yahoo-min.js");
	AddScriptToHeader("http://yui.yahooapis.com/2.8.0r4/build/get/get-min.js");
	
}
ZipCodeCity.prototype.CallBack = function() { }
//Store result to textbox
ZipCodeCity.prototype.StoreToTxt = function(idZipCode,idLati,idLongi,idStateName,idCityName)
{
    storedTo = "txt";
    myZipCode=$("#"+idZipCode);
    if(idLati) myLati=$("#"+idLati);
    if(idLongi) myLongi=$("#"+idLongi);
    if(idStateName) myStateName=$("#"+idStateName);
    if(idCityName) myCityName=$("#"+idCityName);
}

//store result to JSON object
ZipCodeCity.prototype.StoreToJson = function()
{
    storedTo = "json";
}

//绑定提交按钮
var readySubmit = false;
ZipCodeCity.prototype.BindButton = function(idBtnSubmit) {
    oBtnSubmit = $("#" + idBtnSubmit);
    oBtnSubmit.unbind("click").click(function() {
        if ($.trim(oTxtZipCode.val()) == "" || $.trim(myZipCode.val()) != "")//用户没有输入zipcode或者zipcode已经验证,可以直接提交表单
        {
            if (zcodetmp.CallBack)
                if (zcodetmp.CallBack() == false)
                return false;
            return true;
        }
        else//用户输入zipcode了, 需等待zipcode验证完毕才能提交表单
        {
            readySubmit = true;
            return false;
        }
    });
}
//提交表单前检查zipcode是否有效,有效则提交, 否则提示不提交
function checkAndSubmit()
{
    var zipCodeEnter = $.trim(oTxtZipCode.val()); 
    var zipCodeResult = $.trim(myZipCode.val()); 
    
    if(zipCodeEnter != zipCodeResult)
    {
        readySubmit = false;
        alert('Zip code is incorrect!');
    }
    else {
        if (zcodetmp.CallBack)
            if (zcodetmp.CallBack() == false)
            return false;
        oBtnSubmit.unbind( "click" ).click(function(){return true;}).click();
    }
}

//Store resut to textboxes
function storeResult()
{
    var supportZip = oSelCountries.find("option:selected").attr("SupportZipCode");//get whether the country supports zip code
    var selectedOption = oSelCities.find("option:selected");

    if(storedTo == "txt")
    {           
        if(typeof(supportZip)!="undefined" && supportZip.toLowerCase()=="false")//对于没有zipcode的国家,设置该国中心的经纬度为用户所在位置.
        {
            myLati.val(oSelCountries.find("option:selected").attr("Latitude"));
            myLongi.val(oSelCountries.find("option:selected").attr("Longitude"));
            oTxtZipCode.parent().hide();
        }
        else
        {
            oTxtZipCode.parent().show();        
            if(typeof(selectedOption.attr("zipcode"))=="undefined" || selectedOption.attr("zipcode")=="")
            {
                myZipCode.val("");
                if(myLati) myLati.val("");
                if(myLongi) myLongi.val("");
                if(myStateName) myStateName.val("");
                if(myCityName) myCityName.val("");
                if($.trim(oTxtZipCode.val())!="") 
                {
                    oTxtZipCode.val(oTxtZipCode.val()+" not found").css({"color":"#cccccc"});
                    oTxtZipCode.next("span").remove();
                    oTxtZipCode.after("<span id='idZMsg' class='error'>&nbsp;</span>");
                    setTimeout(function(){oTxtZipCode.next("span").remove();},3000);
                }
            }
            else
            {
                myZipCode.val(selectedOption.attr("zipCode")=="undefined"?"":selectedOption.attr("zipCode"));
                if(myLati) myLati.val(selectedOption.attr("latitude")=="undefined"?"":selectedOption.attr("latitude"));
                if(myLongi) myLongi.val(selectedOption.attr("longitude")=="undefined"?"":selectedOption.attr("longitude"));
                if(myStateName) myStateName.val(selectedOption.attr("stateName")=="undefined"?"":selectedOption.attr("stateName"));
                if(myCityName) myCityName.val(selectedOption.attr("value")=="undefined"?"":selectedOption.attr("value"));
                oTxtZipCode.val(myZipCode.val());
                oTxtZipCode.next("span").remove();
                oTxtZipCode.after("<span id='idZMsg' class='sucess'>&nbsp;</span>");
                setTimeout(function(){oTxtZipCode.next("span").remove();},3000);
            }
        }
    }
    else
    {
        if(typeof(supportZip)!="undefined" && supportZip.toLowerCase()=="false")//对于没有zipcode的国家,设置该国中心的经纬度为用户所在位置.
        {
            jsonResult = {"zipCode":"","latitude":oSelCountries.find("option:selected").attr("Latitude"),"longitude":oSelCountries.find("option:selected").attr("Longitude"),"stateName":"","cityName":""};
            oTxtZipCode.parent().hide();
        }
        else
        {
            oTxtZipCode.parent().show();
            if(typeof(selectedOption.attr("zipcode"))=="undefined" || selectedOption.attr("zipcode")=="")
            {
                jsonResult={};
                if($.trim(oTxtZipCode.val())!="") 
                {
                    oTxtZipCode.val(oTxtZipCode.val()+" not found").css({"color":"#cccccc"});
                    oTxtZipCode.next("span").remove();
                    oTxtZipCode.after("<span id='idZMsg' class='error'>&nbsp;</span>");
                    setTimeout(function(){oTxtZipCode.next("span").remove();},3000);
                }
            }
            else
            {
                jsonResult = {"zipCode":selectedOption.attr("zipCode")=="undefined"?"":selectedOption.attr("zipCode"),
                    "latitude":selectedOption.attr("latitude")=="undefined"?"":selectedOption.attr("latitude"),
                    "longitude":selectedOption.attr("longitude")=="undefined"?"":selectedOption.attr("longitude"),
                    "stateName":selectedOption.attr("stateName")=="undefined"?"":selectedOption.attr("stateName"),
                    "cityName":selectedOption.attr("value")=="undefined"?"":selectedOption.attr("value")};
                oTxtZipCode.val(jsonResult.zipCode);
                oTxtZipCode.next("span").remove();
                oTxtZipCode.after("<span id='idZMsg' class='sucess'>&nbsp;</span>");
                setTimeout(function(){oTxtZipCode.next("span").remove();},3000);
            }
        }
    }
    
}

    
// this function will be called by our JSON callback from geonames.org
// the parameter jData will contain an array with postalcode objects
function getLocation(jData) {
  if (jData == null) {
    // There was a problem parsing search results
    return;
  }

  // save place array in 'postalcodes'
  setLocation(jData.postalcodes);  
      
  //表单需要zipcode才能提交, 此时表明zipcode已经获取完毕,提交表单
  if(readySubmit && readySubmit==true)
    checkAndSubmit();
}


function setLocation(jPostalCodes)
{
    postalcodes = jPostalCodes;
     oSelCities.empty().append("<option value=''>--Select a city--</option>");
      if (postalcodes.length > 1) {
        // we got several places for the postalcode
        // iterate over places and build options for cities dropdownlist
        for (i=0;i< postalcodes.length;i++) {
          oSelCities.append("<option value='"+postalcodes[i].placeName+"' zipCode='"+postalcodes[i].postalcode+"' latitude='"+postalcodes[i].lat+"' longitude='"+postalcodes[i].lng+"' stateName='"+postalcodes[i].adminName1+"' "+(i==0?"selected":"")+">" + (postalcodes[i].placeName==""?oSelCountries.find("option:selected").text():postalcodes[i].placeName)+"</option>");
            
        }
      } else {
        if (postalcodes.length == 1) {
          // exactly one place for postalcode
          oSelCities.append("<option value='"+postalcodes[0].placeName+"' zipCode='"+postalcodes[0].postalcode+"' latitude='"+postalcodes[0].lat+"' longitude='"+postalcodes[0].lng+"' stateName='"+postalcodes[0].adminName1+"' selected>" + (postalcodes[0].placeName==""?oSelCountries.find("option:selected").text():postalcodes[0].placeName)+"</option>");
        }
        
      }
      //call store function to initilize result
      storeResult();        
}


// this function is called when the user leaves the postal code input field
// it call the geonames.org JSON webservice to fetch an array of places 
// for the given postal code 
function postalCodeLookup() {

  var country = oSelCountries.val();
  var postalcode = oTxtZipCode.val();

  if($.trim(postalcode).length==0 || $.trim(country).length==0)
  {
    oSelCities.val("");
    myZipCode.val("");
    if(myLati) myLati.val("");
    if(myLongi) myLongi.val("");
    if(myStateName) myStateName.val("");
    if(myCityName) myCityName.val("");
    return;
    }

  //display 'loading' in dropdown list of cities
  oSelCities.empty().append("<option value=''>loading...</option>");

  if (typeof(geonamesPostalCodeCountries)=="undefined" || geonamesPostalCodeCountries.toString().search(country) == -1) {
      // selected country not supported by geonames. call Google Map API to retrieve address
    gMapGetLocation(postalcode,country);
  }
  else
  {
      request = 'http://www.geonames.org/postalCodeLookupJSON?postalcode=' +escape(postalcode)  + '&country=' + country  + '&callback=getLocation';

      // Create a new script object
      aObj = new JSONscriptRequest(request);
      // Build the script tag
      aObj.buildScriptTag();
      // Execute (add) the script tag
      aObj.addScriptTag();
  }
}



// set the country of the user's ip (included in geonamesData.js) as selected country 
// in the country select box of the address form
function setDefaultCountry() {
    try{
        if(oSelCountries.val()=="")
            oSelCountries.val(geonamesUserIpCountryCode);
  }
  catch(e){}
}


//Get location through Google Map API
function gMapGetLocation(zipCode,countryCode) 
{
    var keyValue = "";
  geocoder.getLocations(
    escape(zipCode)+","+countryCode,
    function(response) 
    {
        var jPostalCodes=[];
        if (!response || response.Status.code!=200) 
        {}
        else 
        {
            for(var i=0;i<response.Placemark.length;i++)
            {
                var _zipCode = getKeyValue(response.Placemark[i].AddressDetails,"PostalCodeNumber");
                var _countryCode = getKeyValue(response.Placemark[i].AddressDetails,"CountryNameCode");//alert(_zipCode+"==="+_countryCode);
                //found matched place by zipcode and countrycode
                //then push found postal code to "postalcodes"
                if(_zipCode && _countryCode==countryCode)
                {
                    var stateName = getKeyValue(response.Placemark[i].AddressDetails,"AdministrativeAreaName");
                    var cityName = getKeyValue(response.Placemark[i].AddressDetails,"LocalityName");
                    var lng = response.Placemark[i].Point.coordinates[0];
                    var lat = response.Placemark[i].Point.coordinates[1];
                    var newPostalCode = {"postalcode":_zipCode,"countryCode":_countryCode,"lng":lng,"placeName":cityName,"lat":lat,"adminName1":stateName};
                    jPostalCodes.push(newPostalCode);
                }
            } 
        }
        
        if(jPostalCodes.length>0)
        {
            setLocation(jPostalCodes);
            //表单需要zipcode才能提交, 此时表明zipcode已经获取完毕,提交表单
            if(readySubmit && readySubmit==true)
                checkAndSubmit();   
        }
        else
             yMapGetLocation(zipCode,countryCode);//提交YAHOO SERVICES查询
    }
  );
  
  //return value after search through all objects
  function getKeyValue(obj,keyName)
  {
    findKey(obj,keyName);
    var _value = keyValue;
    keyValue="";
    return _value;
  }
  //search through all objects and properties of a JSON object and set value of matched property to 'keyValue'
    function findKey(obj,keyName)
    {
      for(var key in obj){
           if(typeof(obj[key]) =="string" && key.toString()==keyName){
              keyValue = obj[key];
           }
           else if(typeof(obj[key]) =="object"){
              findKey(obj[key],keyName);
           }
        }
    }
  
}

  
//Call back of yahoo services
function getYQLDataCallback(data)
{
    var jPostalCodes=[];
    if(data.query.results!=null && data.query.results.place.postal!=null)
    {
        var countryCode = data.query.results.place.country.code;
        if(countryCode.toUpperCase()==oSelCountries.val().toUpperCase())
        {
            var zipCode=oTxtZipCode.val();
            var stateName = data.query.results.place.admin1.content;
            var cityName=data.query.results.place.admin2.content;
            var lat=data.query.results.place.centroid.latitude;
            var lng=data.query.results.place.centroid.longitude;
            var newPostalCode = {"postalcode":zipCode,"countryCode":countryCode,"lng":lng,"placeName":cityName,"lat":lat,"adminName1":stateName};
            jPostalCodes.push(newPostalCode);
        }
    }
    setLocation(jPostalCodes);
    //表单需要zipcode才能提交, 此时表明zipcode已经获取完毕,提交表单
    if(readySubmit && readySubmit==true)
        checkAndSubmit();  
}

//use Yahoo SERVICES to get location
function yMapGetLocation(zipCode,countryCode)
{
    //public YQL query URL
    var yqlPublicQueryURL = "http://query.yahooapis.com/v1/public/yql?";

    //YQL Query
    var sQuery = 'select * from geo.places where text="'+zipCode+', '+countryCode+'"';

    //prepare the URL params for YQL query
    var sURL = yqlPublicQueryURL + "q=" + encodeURI(sQuery) + "&format=json&callback=getYQLDataCallback";

    //make GET request to YQL with provided query
    var transactionObj = YAHOO.util.Get.script(sURL, {
        onSuccess : function(data){}
        //onFailure : onYQLReqFailure,
       // scope : this
    });
}
