﻿function DealerMap() {}

DealerMap.prototype.name = 'Map';
DealerMap.prototype.brand = 0;  															// JO Brand (company) to find dealers for
DealerMap.prototype.defaultZoom = 3;  												// Default zoom level of the map, set to show entire world
DealerMap.prototype.mapType = "terrain";											// Type of map to display
DealerMap.prototype.initialLocation = 'Mali'; 								// Center point of the map when it loads
DealerMap.prototype.mapID = 'map_canvas'; 										// ID of the div that will hold the map
DealerMap.prototype.map = null;																// Map variable
DealerMap.prototype.dealerListID = 'dealer_list';							// ID of the dealer list
DealerMap.prototype.dealerSelectedClass = 'SelectedDealer'; 	// CSS class name used to highlight the selected dealer in the dealer list
DealerMap.prototype.featureFilter = null;											// Array of features to limit display of
DealerMap.prototype.urlFeatureID = null;												// Allows limiting URLs for one Feature		
DealerMap.prototype.showFeatureIcons = true;									// Controls display of the Feature icons in the dealer list
DealerMap.prototype.baseURL = $('GeoCodeScript').src.replace('geocode3.js','');
DealerMap.prototype.markerScript = $('GeoCodeScript').src.replace('geocode3.js','dealer_markers3.aspx');
DealerMap.prototype.baseIconURL = '';													// URL of the icon used for markers
DealerMap.prototype.shadowPNG = 'http://maps.gstatic.com/intl/en_us/mapfiles/shadow50.png';
DealerMap.prototype.markers = new Array();										// Used locally to store markers
DealerMap.prototype.infoWindow = null;												// Used locally to track infowindow popus
DealerMap.prototype.dragEvent = null;													// Used locally to track event
DealerMap.prototype.zoomEvent = null; 												// Used locally to track event
DealerMap.prototype.revZoom = {12:10, 11:20, 10:50, 9:100, 8:250, 7:400, 6:750, 5:1500, 4:3000, 3:5000, 2:10000, 1:24000};
DealerMap.prototype.directionsSubmitText = 'Get Directions';	// Text of the get directions button 
DealerMap.prototype.directionsFrameID = 'DirectionsFrame';		// ID of the HTML element that will hold the directions and input form
DealerMap.prototype.mapAndDirectionsContainer = 'MapAndDirections';	// ID of the parent element that will contain the map and directions
DealerMap.prototype.directionsFrameWidth = 200;								// Width in pixels of the directions pane
DealerMap.prototype.mapBorder = 0;														// Width in pixels of the map's border
DealerMap.prototype.directionsService = new google.maps.DirectionsService();	// Used locally to display directions
DealerMap.prototype.directionsDisplay = new google.maps.DirectionsRenderer(); // Used locally to display directions
DealerMap.prototype.DirectionResultsOffset = 30;


/* =====================================================================================================================
 * Takes a distance in Miles and converts it to a GoogleMaps zoom-level appropriate for this app.
 */
DealerMap.prototype.Zoom = function(Miles){
	
	var AdjMiles = 24000;
	var ZoomLevels = {5:12, 10:11, 25:10, 50:9, 100:8, 250:7, 500:6, 1000:5, 2000:4, 4000:3, 8000:2, 24000:1};
	for(var Level in ZoomLevels)
		if(parseInt(Miles) <= Level && AdjMiles >= Level) AdjMiles = ZoomLevels[Level];
	
	return parseInt(AdjMiles);
	
};


/* =====================================================================================================================
 * Loads the map onto the page.  Loads the default location and zooms into the default level.
 */
DealerMap.prototype.loadMap = function(){

	this.showAddress(this.initialLocation, this.revZoom[this.defaultZoom], false);

}

/* =====================================================================================================================
 * Clears the markers from the map and reloads the markers within the viewport 
 */

DealerMap.prototype.ReloadMarkers = function(DMO) {
	
	$(this.dealerListID).childElements().invoke('remove');
	
	for (i = 0; i < DMO.markers.length; i++) // Clear markers
		DMO.markers[i].setMap(null);

	try {
		DMO.infoWindow.close();
	} catch (err) { };

	DMO.addMarkers(new google.maps.LatLng(DMO.map.center.lat(), DMO.map.center.lng()), DMO.revZoom[DMO.map.getZoom()]);
	

}

/* =====================================================================================================================
* Loads a location in the map when a location and distance is passed through.
* Distance is passed as a zoom-level.  A drop-down will typically hold the zoom-level in the value and
* miles (or km) in the display.
* Asynchronous request to Google returns location coordinates by passing a location term (not coordinates).
* The call to display the map must be inside the callback otherwise it will execute before the goecode completes.
*/
DealerMap.prototype.showAddress = function(Location, Miles, ShowMarkers) {

	if (ShowMarkers == undefined) ShowMarkers = true;

	var DMO = this;  // Make this object's scope available to the callback in the Google geocoder
	var geocoder = new google.maps.Geocoder();

	geocoder.geocode({ address: Location }, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK && results.length) {
			if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {

				if (DMO.map == null) {

					var myOptions = {
						zoom: DMO.Zoom(Miles),
						center: results[0].geometry.location,
						mapTypeId: DMO.mapType
					};
					DMO.map = new google.maps.Map($(DMO.mapID), myOptions);

				} else {
					for (i = 0; i < DMO.markers.length; i++)
						DMO.markers[i].setMap(null);

					DMO.map.setOptions({ center: results[0].geometry.location, zoom: DMO.Zoom(Miles) });


					try {
						google.maps.event.removeListener(DMO.dragEvent);
					} catch (err) { }
					
					try {
						google.maps.event.removeListener(DMO.zoomEvent);
					} catch (err) { }
					
					DMO.dragEvent = google.maps.event.addListener(DMO.map, 'dragend', function() { DMO.ReloadMarkers(DMO) });
					DMO.zoomEvent = google.maps.event.addListener(DMO.map, 'zoom_changed', function() { DMO.ReloadMarkers(DMO) });

				}

				if (ShowMarkers)
					DMO.addMarkers(results[0].geometry.location, Miles);
			}
		} else
			alert('The location could not be found.');
	});

}

/* =====================================================================================================================
* Embeds the JO dealer locator javascript into the document and loads the dealers within the region.
*/
DealerMap.prototype.addMarkers = function(LatLng, Miles) {

	DealerList = $(this.dealerListID)
	if (DealerList != null) DealerList.innerHTML = ''

	this.DisplayDistributors(LatLng);

	/* 
		Build a querystring and use dynamic JSON to execute a callback.
		A dynamic script tag is created which calls a script that executes a callback with the dealer info in
		JSON format.	
	*/
	var QS = $H({
		cmd: 'AddMarkers',
		lat: LatLng.lat(),
		lng: LatLng.lng(),
		distance: Miles,
		group: this.brand,
		callback: this.name + '.OutputDealers'
	}).toQueryString()

	try { // Remove the existing script tag if it exists.
		$('MarkerScript').remove();
	} catch (e) { }

	// Create the dynamic script tag and embed it into the document HEAD.
	var S = new Element('script', { id: 'MarkerScript', type: 'text/javascript', src: this.markerScript + '?' + QS });
	$$('head')[0].appendChild(S);

}

/* =====================================================================================================================
*  Callback for the Dynamic JSON - [Dealers].
*/
DealerMap.prototype.OutputDealers = function(Response){

	var DMO = this;  // Make this object's scope available to the AJAX callback

	Response.Dealers.each(function(item) {
		DMO.addMarker(item, Response.Features)
	});

}

/* =====================================================================================================================
*  Callback for the Dynamic JSON - [Distributors].
*/

DealerMap.prototype.OutputDistributors = function(Response) {

	if (!Response.Distributors) return;

	var DMO = this;  // Make this object's scope available to the AJAX callback

	Response.Distributors.each(function(item) {
		DMO.addMarker(item, Response.Features, true)
	});

}

/* =====================================================================================================================
 * Adds a marker to the map.  Paramater is an array of dealer details, including Lat & Lng, names, URLs, etc.
 */
DealerMap.prototype.addMarker = function(Dealer, Features, Distributor) {

	if (Distributor == undefined) Distributor = false;

	var DMO = this;

	// Filter out features if filter is set
	
	if (this.featureFilter != undefined && this.featureFilter.length) {
		var Passed = false;
		Dealer.Features.each(function(item) {

			var i = item;
			$A(DMO.featureFilter).each(function(item) { if (i == item) Passed = true; });

		});

		if (!Passed) return false;

	}

	// Build a point object with the Lat/Long of the dealer
	if (Distributor) {
		var latlng = new google.maps.LatLng(this.map.center.lat(), this.map.center.lng());
	} else
		var latlng = new google.maps.LatLng(Dealer.Lat, Dealer.Lng);

	// Create a new icon object based on the default icon
	image = (this.baseIconURL != undefined) ? this.baseIconURL : '';

	// Check the last feature for an icon
	if (Dealer.Features != null && Dealer.Features.length > 0){
		try{
			if (Features[Dealer.Features[Dealer.Features.length - 1]].IconURL.length)
			image = Features[Dealer.Features[Dealer.Features.length - 1]].IconURL
		}catch(err){}
	}

	var marker = new google.maps.Marker({
		position: latlng,
		map: this.map,
		icon: image,
		shadow: this.shadowPNG,
		flat: false
	});



	this.markers.push(marker);

	google.maps.event.addListener(marker, 'click', function() {
		try {
			DMO.infoWindow.close();
		} catch (err) { };
		DMO.infoWindow = new google.maps.InfoWindow({ content: DMO.DealerInfoHTML(Dealer) });
		DMO.infoWindow.open(DMO.map, marker);

		try{
			$(DMO.dealerListID).getElementsBySelector('.DealerInfo').each(function(item) {
				item.removeClassName(DMO.dealerSelectedClass)
			});
	
			$(DMO.dealerListID).getElementsBySelector('.Dealer_' + Dealer.ID).each(function(item) {
				item.addClassName(DMO.dealerSelectedClass);
				item.scrollIntoView()
			});
		}catch(err){}
				
		try{
			var Vals = [Dealer.Str1, Dealer.Str2, Dealer.City, Dealer.State, Dealer.Zip];
			DealerLocator.Cookie.set('ToAddress', Vals.join(' '));
			try{$('DirectionsTo').value = Vals.join(' ');}catch(e){};
		}catch(err){};
		
		
		

	});

	this.AddToDealerList(Dealer, Features, marker);

}

/* =====================================================================================================================
 * Builds the content of the info bubble for the marker on the map
 */
DealerMap.prototype.DealerInfoHTML = function(Dealer) {

var OuterDiv = new Element('div', { className: 'DealerInfo Dealer_' + Dealer.ID });

	var DealerItems = ['Comp', 'Str1', 'Str2', 'City', 'State', 'ZIP', 'Tel', 'FAX', 'TollFree',
										 'Email', 'URLs', 'Opt1', 'Opt2'];
	for (i = 0; i < DealerItems.length; i++) {

		if (Dealer[DealerItems[i]] == undefined) continue;
		if (Dealer[DealerItems[i]].length == 0) continue;

		var Ele = new Element('p');

		Ele.className = DealerItems[i];

		if (DealerItems[i] == 'Email') {
			Ele.appendChild(new Element('a', { href: 'mailto:' + Dealer[DealerItems[i]] }).update(Dealer[DealerItems[i]]));
		} else if (DealerItems[i] == 'City') {
			Ele.update(Dealer[DealerItems[i]] + ',&nbsp;');
		} else if (DealerItems[i] == 'State') {
			Ele.update(Dealer[DealerItems[i]] + '&nbsp;');
		} else if (DealerItems[i] == 'URLs' && Dealer.URLs.length) {
			Ele.appendChild(this.getURLs(Dealer));
		} else
			Ele.update(Dealer[DealerItems[i]]);

		OuterDiv.appendChild(Ele);
	}
	OuterDiv.appendChild(new Element('br', { style: 'clear:both' }));

	return OuterDiv;
}

/* =====================================================================================================================
 * Takes an array of URLs and returns the most specific
 */
DealerMap.prototype.pickURL = function(URLs){
	
	var DMO = this;
	var URL = null;
	
	if(this.featureFilter != null && this.featureFilter.length){
		$(URLs).each(function(item){
			if(item.IDGroup	== DMO.brand && DMO.in_array(item.IDFeature, DMO.featureFilter)){
				URL = item;
				return item;
			}
		});
	}
	
	if(URL != null ) return URL;
	
	
	$(URLs).each(function(item){
		if(item.IDGroup	== DMO.brand){
			URL = item;
			return item;
		}
	});
	
	if(URL != null ) return URL;
	
	return URLs[0];
	
}

/* =====================================================================================================================
 * Emulates PHP's in_array function
 */

DealerMap.prototype.in_array = function(what,where){
	var a=false;
	for(var i=0;i<where.length;i++){
		if(what == where[i]){
			a=true;
			break;
		}
	}
	
	return a;
}


/* =====================================================================================================================
 * Gets URLs
 */

DealerMap.prototype.getURLs = function(Dealer){
	
	var DMO = this;
	
	
	URL = this.pickURL(Dealer.URLs);
	
	var SPAN = new Element('span');
	
		if(URL.IDGroup == DMO.brand){
			if(DMO.urlFeatureID == null || (DMO.urlFeatureID && (DMO.urlFeatureID == URL.IDFeature))){
				SPAN.appendChild(A = new Element('a', { href: URL.URL, className: 'URL' }).update(URL.URL.substring(0,30) + ((URL.URL.length > 30) ? '...' : '') ))
				A.observe('click', function(event) { window.open(this.href); event.stop(); });
			}
		}
	
	return SPAN
}

/* =====================================================================================================================
 * Load the dealer list if it exists
 */
DealerMap.prototype.AddToDealerList = function(Dealer, Features, marker) {

	// Verify the dealer list exists on the page (it is optional)
	var DealerList = $(this.dealerListID);
	if (DealerList == null) return;

	// Get the formatted HTML dealer object
	var Listing = this.DealerInfoHTML(Dealer)

	// Add the feature icons to the listing
	if(this.showFeatureIcons == true){
		var S = new Element('span', { className: 'Icons' });
	
		Dealer.Features.each(function(item) {
			try{
				if (Features[item].IconURL.length) {
					var Img = new Element('img', { src: Features[item].IconURL });
					S.appendChild(Img);
				}
			}catch(err){}
		});
	
		Listing.insert({top: S});
	}

	var DMO = this; // Access "this" inside the observer below

	/* Add the click event to the listing to popup the related info window on the map and 
	set the proper coloring for the dealer listings */
	Listing.observe('click', function() {
		try {
			DMO.infoWindow.close();
		} catch (err) { };
		DMO.infoWindow = new google.maps.InfoWindow({ content: DMO.DealerInfoHTML(Dealer) });
		DMO.infoWindow.open(DMO.map, marker);

		$(DMO.dealerListID).getElementsBySelector('.DealerInfo').each(function(item) {
			item.removeClassName(DMO.dealerSelectedClass)
		});

		this.addClassName(DMO.dealerSelectedClass);
		
		try{
			var Vals = [Dealer.Str1, Dealer.Str2, Dealer.City, Dealer.State, Dealer.Zip];
			DealerLocator.Cookie.set('ToAddress', Vals.join(' '));
			$('DirectionsTo').value = Vals.join(' ');
		}catch(err){};

	});

	// Add the dealer to the listings
	DealerList.appendChild(Listing);

	// Show the listings element in case it is hidden
	DealerList.style.display = 'block';
}



/* =====================================================================================================================
 * Retrieves the 2-letter country code from a LatLng and uses XHR to put an marker for a distributor
 */
DealerMap.prototype.DisplayDistributors = function(LatLng) {

	var DMO = this;  // Make this object's scope available to the AJAX callback

	// Get the country of the lookup
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({ 'latLng': LatLng }, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK) {
			$A(results[0].address_components).each(function(item) {
				item.types.each(function(type) {
					if (type == 'country') {
						CountryCode = item.short_name;


						/* 
						Build a querystring and use dynamic JSON to execute a callback.  A dynamic script tag is created 
						which calls a script that executes a callback with the dealer info in JSON format.	
						*/
						var QS = $H({
							cmd: 'GetDistributors',
							country: CountryCode,
							group: DMO.brand,
							callback: DMO.name + '.OutputDistributors'
						}).toQueryString()

						try { // Remove the existing script tag if it exists.
							$('DistributorScript').remove();
						} catch (e) { }

						// Create the dynamic script tag and embed it into the document HEAD.
						var S = new Element('script', { id: 'DistributorScript', type: 'text/javascript', src: DMO.markerScript + '?' + QS });
						$$('head')[0].appendChild(S);
					
					}
				});
			});
		}
	});
	
}

/* =====================================================================================================================
 * Displays the directions frame next to the map, the input form and resizes the map to share space
 */  
DealerMap.prototype.DisplayDirectionsInput = function(){
	
	if($(this.directionsFrameID) != null) return;
		
	var DirectionsDiv = new Element('div',{id: this.directionsFrameID});
	DirectionsDiv.appendChild(DirectionsForm = new Element('form',{id: 'DirectionsForm', method: 'post', action: '#'}));
	DirectionsForm.appendChild(Line1 = new Element('p',{id: 'DirectionsFromP'}));
	Line1.appendChild(DirectionsFrom = new Element('textarea',{id: 'DirectionsFrom', name: 'DirectionsFrom'}));
	DirectionsForm.appendChild(Line2 = new Element('p',{id: 'DirectionsToP'}));
	Line2.appendChild(DirectionsTo = new Element('textarea',{id: 'DirectionsTo', name: 'DirectionsTo'}));
	DirectionsForm.appendChild(Line3 = new Element('p',{id: 'DirectionsSubmitP'}));
	Line3.appendChild(DirectionsSubmit = new Element('input',{type: 'submit', value: this.directionsSubmitText}));
	Line3.appendChild(CloseImage = new Element('img',{src: this.baseURL + 'close_directions.png', alt: 'Close Directions', title: 'Close Directions', id: 'CloseDirections'}));
	DirectionsDiv.appendChild(DirectionsResults = new Element('div',{id: 'DirectionsResults'}));
	
	try{
		if(DealerLocator.Cookie.get('FromAddress') != null)
			DirectionsFrom.value = DealerLocator.Cookie.get('FromAddress');
	}catch(err){}
	
	try{
		if(DealerLocator.Cookie.get('ToAddress') != null)
			DirectionsTo.value = DealerLocator.Cookie.get('ToAddress');
	}catch(err){}
	
	var DMO = this;
	
	DirectionsForm.observe('submit', function(Event){
		Event.stop();
		DMO.DisplayDirections();
	});
	
	CloseImage.observe('click', function(){DMO.HideDirections()});

	$('map_canvas').style.width = $('map_canvas').getWidth() - this.mapBorder - this.directionsFrameWidth + 'px';
	DirectionsDiv.style.height = $('map_canvas').getHeight() + 'px';
	$(this.mapAndDirectionsContainer).insert({top: DirectionsDiv});
	DirectionsResults.style.height = DirectionsDiv.getHeight() - DirectionsForm.getHeight() - this.DirectionResultsOffset + 'px';

}

/* =====================================================================================================================
 * Submits a directions request to GoogleMaps, displays results
 */

DealerMap.prototype.DisplayDirections = function(){
	
	var DMO = this;
	
	DealerLocator.Cookie.set('FromAddress',$('DirectionsFrom').value);
	
	this.directionsDisplay.setMap(this.map);
  this.directionsDisplay.setPanel($('DirectionsResults'));

	var request = {
			origin:$('DirectionsFrom').value, 
			destination:$('DirectionsTo').value,
			travelMode: google.maps.DirectionsTravelMode.DRIVING
	};
	this.directionsService.route(request, function(response, status) {
		if (status == google.maps.DirectionsStatus.OK) {
			DMO.directionsDisplay.setDirections(response);
		}
	});
	
};

/* =====================================================================================================================
 * Hides the directions panel, clears the directions from the map
 */  

DealerMap.prototype.HideDirections = function(){
	
	this.directionsDisplay.setMap(null);
	$('DirectionsFrame').remove();
	$('map_canvas').style.left = '0';
	$('map_canvas').style.width = $('map_canvas').getWidth() - this.mapBorder + this.directionsFrameWidth + 'px';
	
	
}


/*
 *======================================================================================================================
 * DeealerLocator Namespace - relies on prototype.js
 *======================================================================================================================
*/

var DealerLocator = {}


/*====================================================================================================================== 
	DeealerLocator.Cookies ******************************************************************************************************
=======================================================================================================================*/

DealerLocator.Cookie = {
  
  get: function( name ) {
    var start = document.cookie.indexOf( name + "=" );
    var len = start + name.length + 1;
    if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
      return null;
    }
    if ( start == -1 ) return null;
    var end = document.cookie.indexOf( ';', len );
    if ( end == -1 ) end = document.cookie.length;
    return unescape( document.cookie.substring( len, end ) );
  },

  set: function( name, value, expires, path, domain, secure ) {
    var today = new Date();
    today.setTime( today.getTime() );
    if ( expires ) {
      expires = expires * 1000 * 60 * 60 * 24;
    }
    var expires_date = new Date( today.getTime() + (expires) );
    document.cookie = name+'='+escape( value ) +
      ( ( expires ) ? ';expires=' + expires_date.toGMTString() : '' ) + //expires.toGMTString()
      ( ( path ) ? ';path=' + path : '' ) +
      ( ( domain ) ? ';domain=' + domain : '' ) +
      ( ( secure ) ? ';secure' : '' );
  },

  del: function( name, path, domain ) {
    if ( SubGear.Cookie.get( name ) ) document.cookie = name + '=' +
        ( ( path ) ? ';path=' + path : '') +
        ( ( domain ) ? ';domain=' + domain : '' ) +
        ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
  }
}
