/******************************************************************************
 ** Internaional addresses
 *****************************************************************************/
(function ($) { // protect the queen!

$.widget( "ui.rubyInternational", {
    _init: function () {
	var self = this;

	// Get country, various states and lat/lng
	this.country    = $( '.rtg-country select', this.element );
	this.usState    = $( '.rtg-us_state', this.element );
	this.caState    = $( '.rtg-ca_state', this.element );
	this.gbState    = $( '.rtg-gb_state', this.element );
	this.otherState = $( '.rtg-other_state', this.element );
	this.latitude   = $( '.rtg-latitude input', self.element );
	this.longitude   = $( '.rtg-longitude input', self.element );

	// Change state when country changes
	this.country.bind( 'change.rubyInternational', function (ev) {
	    self._change.call( self, ev );
	} );

	// Change state now
	self._change();

	// Setup any google map
	this.googleMap = $( '.rtg-map', this.element );
	if( this.googleMap.length > 0 )
	    this._initGoogleMap();

	return;
    }, // _init

    destroy: function () {
	this.country.unbind( '.rubyInternational' );

	window.clearInterval( this._getData( 'map_interval_id' ) );

	this.country    = null;
	this.usState    = null;
	this.caState    = null; 
	this.gbState    = null;
	this.otherState = null;

	$.widget.prototype.destroy.apply( this, arguments );
    }, // destroy

    refresh: function () {
	// Get the chosen country
	var countryCode = this.country.val();

	// Hide all states
	this.usState.hide();
	this.caState.hide();
	this.gbState.hide();
	this.otherState.hide();

	// Show appropriate state
	switch( countryCode ) {
	    case 'US':
  	        this.usState.show();
	        break;
	    case 'CA':
  	        this.caState.show();
	        break;
	    case 'GB':
  	        this.gbState.show();
	        break;
   	    default:
	        this.otherState.show();
	        break;
	}
	
	return;
    }, // refresh

    _initGoogleMap : function () {
	var self = this;
	
	// Initialize map to center of the USA
	var map    = new google.maps.Map2( self.googleMap[0] );
	var latLng = new google.maps.LatLng( 38, -97 );
	
	map.addControl( new google.maps.SmallZoomControl() );
	self._setData( 'map', map );

	self._updateMarker( latLng, 2 );
	
	// Recenter/add marker to map based on lat/lng or address input
	self._updateMap();

	// Monitor input fields for changes
	self._setData( 
	    'map_interval_id', 
	    window.setInterval( function() { self._checkForChanges() }, 1100 )
	);

	return;
    }, // _initGoogleMap

    _updateMap : function () {
	var self = this;

	// Get user lat/long input
	var lat = self.latitude.val();
	var lng = self.longitude.val();
	
	// If lat/long look valid
	if( lat != '' && lng != '' ) {
	    var latLng = new google.maps.LatLng( lat, lng );

	    self._updateMarker( latLng );
	}
	else { // if lat/lng do not look valid
	    
	    // Get lat/lng from address
	    var addrStr = self._generateAddressString();
	    self._startGeocode( addrStr );
	}

	return;
    }, // _updateMap

    _updateMarker : function (latLng, zoomLevel) {
	var self   = this;
	var map    = self._getData( 'map' );

	map.clearOverlays(); // remove all markers
	
	map.setCenter( latLng );
	map.setZoom( zoomLevel || 15 );
	
	var mark = new google.maps.Marker( latLng, { draggable : true } );
		
	// Update user lat/lng input when marker is moved
	google.maps.Event.addListener( 
	    mark,
	    'dragend',
	    function (newLatLng) { self._updateLatLng( newLatLng ) }
	);
	
	// Add marker to map
	map.addOverlay( mark );
	
	return;
    },

    _updateLatLng : function (latLng) {
	var self = this;

	// Do nothing if lat/lng hasn't changed
	if( self.latitude.val() == latLng.lat()
	    && self.longitude.val() == latLng.lng() )
	    return;

	// Update monitor info
	var monitorInfo = self._getData( 'address_monitor' );
	if( typeof monitorInfo != "undefined" )
	    monitorInfo.latlng = latLng.lat() + "," + latLng.lng();

	// Change user lat/lng input
	self.latitude.val( latLng.lat() );
	self.longitude.val( latLng.lng() );

	// Do not "flash" lat/long if currently "flashing"
	var animating = self._getData( 'animating_highlight' );
	if( typeof animating === "undefined" )
	    animating = false;

	if( !animating ) {
	    // Turn on animating flag
	    self._setData( 'animating_highlight', true );

	    // Setup function to turn off animating flag
	    var turnOffCounter = 2;
	    var turnOffAniFlag = function () { 
		if( --turnOffCounter == 0 )
		    self._setData( 'animating_highlight', false )
	    };
	    
	    // Flash lat/lng inputs 
	    var bgColor    = self.latitude.css( 'backgroundColor' );
	    var flashColor = { backgroundColor : '#0065A4' };
	    var normColor  = { backgroundColor : bgColor };
	    var flashIn    = 340; // ms
	    var flashOut   = 600; // ms
	    
	    self.latitude.css( 'position', 'relative' );
	    self.latitude.animate( flashColor, flashIn )
		.animate( normColor, flashOut, null, turnOffAniFlag );
	    
	    self.longitude.animate( flashColor, flashIn )
		.animate( normColor, flashOut, null, turnOffAniFlag );
	} // if not animating

	return;
    }, // _updateLatLng

    _startGeocode : function (addr, useExistingGeocoder) {
	var self = this;

	// If geocode is currently running
	var geocoder = self._getData( 'geocoder' );
	if( typeof geocoder === "undefined" )
	    geocoder = null;
	
	if( geocoder && !useExistingGeocoder ) {
	    // Then set a flag to run it again
	    self._setData( 'geocode_again', addr );
	}
	else { // else, no current geocode running

	    // Create geocoder and store it, so we know one is running
	    if( !geocoder ) {
		geocoder = new google.maps.ClientGeocoder();
		self._setData( 'geocoder', geocoder );
	    }

	    // Run geocoder
	    geocoder.getLatLng( 
		addr,
		function (latLng) { // when geocode finishes

		    if( latLng ) {
			// Update marker and user lat/lng inputs
			self._updateMarker( latLng );
			self._updateLatLng( latLng );
		    }
		    
		    // If they want us to geocode again, then do so
		    var geocodeAgain = self._getData( 'geocode_again' );
		    if( typeof geocodeAgain === "undefined" )
			geocodeAgain = null;

		    if( geocodeAgain ) {
			self._setData( 'geocode_again', null );
			self._startGeocode( geocodeAgain, true );
		    } // if do it again
		    else {
			// Clear geocoder so that we know it is done
			self._setData( 'geocoder', null );
		    }
		} // func to execute after geocoding finishes
	    ); // do geocode
	} // if no geocode running

	return;
    }, // _startGeocode

    _checkForChanges : function () {
	var self = this;

	// Get monitor info
	var monitorInfo = self._getData( 'address_monitor' );

	// If no monitor info yet
	if( typeof monitorInfo === "undefined" ) {
	    // Initialize monitor info
	    self._setData( 
		'address_monitor',
		{
		    'address' : self._generateAddressString(),
		    'latlng'  : self._generateLatLng(),
		    'counter' : -1,
		    'type'    : 'latlng'
		}
	    );

	    return;
	} // if no monitor info

	var newAddr   = self._generateAddressString();
	var newLatLng = self._generateLatLng();

	// If lat/lng or address changed
	if( (monitorInfo.address != newAddr && newAddr != '')
	    || (monitorInfo.latlng != newLatLng && newLatLng != '') ) {

	    // Honor lat/lng change before address change
	    if( monitorInfo.latlng != newLatLng && newLatLng != '' )
		monitorInfo.type = 'latlng';
	    else
		monitorInfo.type = 'address';
	    
	    // Update lat/lng and address and reset counter
	    monitorInfo.address = newAddr;
	    monitorInfo.latlng  = newLatLng;
	    monitorInfo.counter = 1;

	}
        // If lat/lng and address did not change and counter is at 0
	else if( monitorInfo.address == newAddr 
		 && monitorInfo.latlng == newLatLng
		 && monitorInfo.counter == 0 ) {
            
	    // "turn off" counter
	    monitorInfo.counter = -1;

	    // Honor lat/lng change before address change
	    if( monitorInfo.type == 'latlng' ) {
		var latLngList = newLatLng.split( /\s*,\s*/ );
		var latLngObj  = new google.maps.LatLng( latLngList[0],
							 latLngList[1] );

		self._updateMarker( latLngObj );
	    }
	    else {
		self._startGeocode( newAddr );
	    }
	}
	// If lat/long and address did not change and counter is above 0
	else if( monitorInfo.address == newAddr 
		 && monitorInfo.latlng == newLatLng
		 && monitorInfo.counter > 0 ) {
	    // Decrement counter
	    monitorInfo.counter--;
	}

	return;
    }, // _checkForChanges

    _generateLatLng : function () {
	var self = this;
	
	var latlng = '';

	var lat = self.latitude.val();
	var lng = self.longitude.val();

	if( lat != '' && lng != '' )
	    latlng = lat + "," + lng;

	return latlng;
    }, // _generateLatLng

    _generateAddressString : function () {
	
	var addr1 = $( '.rtg-address_line_1 input', this.element ).val();
	var addr2 = $( '.rtg-address_line_2 input', this.element ).val();
	var city  = $( '.rtg-city input', this.element ).val();

	var usSt  = $( 'select', this.usState ).val();
	var caSt  = $( 'select', this.caState ).val();
	var gbSt  = $( 'select', this.gbState ).val();
	var otherSt = $( 'input', this.otherState ).val();
	var country = this.country.val();
	var zip   = $( '.rtg-postal_code input', this.element ).val();

	var state = country == 'US' ? usSt
                  : country == 'CA' ? caSt
                  : country == 'GB' ? gbSt
	          :                   otherSt
	          ;
	    
	var addr = $.grep( [ addr1, addr2, city, state, zip, country ],
			   function (n) { return n != ""; } );
	    
	var addrStr = addr.join( ', ' );

	return addrStr;
    }, // _generateAddressString    

    _change: function () {

	this.refresh();
    } // _change

}); // $.widget

$.extend( $.ui.rubyInternational, {
    version: "1.0",
    defaults: {
	
    }
});

})(jQuery); // function ($)

