/**
 * Dealer Locator Class and Dealer Class.
 * Requires jQuery 1.3+
 * 
 * @author erik.daniel
 * 
 * TODO add omniture tracking to outgoing links
 */


/**
 * Constructor
 * 
 * @param {google.maps.Map} map 
 */
function DealerLocator(map) {
	this.markers = new Array();
	this.dealers = new Array();
	this.pages = new Array();
	this.currentPage = 0;
	this.currentLocation = null;
	this.isDaa = false;
	this.map = map;
	this.model = null;
	this.zipcode = null;
	this.typeControlArray = new Array();
  this.firstRun = true;
	if(map != undefined) {
		setMap(map);
	}
	
}	

DealerLocator.prototype.setMap = function(map) {
	this.map = map;
	var dl = this;
	try{
		google.maps.event.addListener(map, 'zoom_changed', function() {
			dl.panTo(dl.currentLocation);
		});
	
	this.infowindow = this.createInfoWindow();
	this.createControls(); 	
  }
	catch(error){};

}

/**
 * Create map controls.
 */
DealerLocator.prototype.createControls = function() {
	var map = this.map;
  var roadControlDiv = document.createElement('DIV');
  var roadControl = new HomeControl(roadControlDiv, map, 'map', function() { map.setMapTypeId(google.maps.MapTypeId.ROADMAP);});
  roadControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(roadControlDiv);
  
  $('.mapControlUI').addClass('active-type'); 
  var hybControlDiv = document.createElement('DIV');
  var hybControl = new HomeControl(hybControlDiv, map, 'hybrid', function() {map.setMapTypeId(google.maps.MapTypeId.HYBRID);})
  hybControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(hybControlDiv);
  this.typeControlArray.push(hybControl);
  
  var satControlDiv = document.createElement('DIV');
  var satControl = new HomeControl(satControlDiv, map, 'satellite', function() {map.setMapTypeId(google.maps.MapTypeId.SATELLITE);})
  satControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(satControlDiv);
  this.typeControlArray.push(satControl);
  
  var zoomControlDiv = document.createElement('div');
  var zoomControl = new ZoomControl(zoomControlDiv, map);
  zoomControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.TOP_LEFT].push(zoomControlDiv);
	  
}

/**
 * Create info window.
 * Depends on third party InfoBox class.
 */
DealerLocator.prototype.createInfoWindow = function() {
	var iwOptions =   {
		boxStyle: { 
        	background: "transparent"// url('images/infobox-vw-alt.png') no-repeat"
	            ,width: "245px"
	            ,height: "27px"
           }
       ,map: this.map
       ,maxWidth: "333px"
	   ,pixelOffset: new google.maps.Size(-123, -45)   
       ,closeBoxURL: ""
	};

	if(isIE6()) {
		iwOptions.boxStyle.filter = "progid:dximagetransform.microsoft.alphaimageloader(src='images/infobox-vw-alt.png', sizingMethod='fixed')";
	}
	return new InfoBox(iwOptions);
}

/**
 * Set DAA flag.
 * 
 * @param {bool} isDaa
 */
DealerLocator.prototype.setDaa = function(isDaa) {
	this.isDaa = isDaa;
	var msg = 'Enter Zipcode';
	if(isDaa == false){
		msg = 'Enter Dealer Name or Zipcode'
	}
	$('#instructions').text(msg);
}
/**
 * Process raw xml result from successful search.
 * 
 * @param {XML} xml result of search.
 */
DealerLocator.prototype.processResult = function (xml) {	

	$('#results').empty();
	if($(xml).find('dealer').length == 0) {
		$.hideLoader();
		this.showError("This search didn't return any results. Please check your entry and try again.");
	}
	else
	{
		this.setResult(xml);
		this.paginateResults(xml);
		this.initAnimation();
	}
}

/**
 * Pan map to coordinates. Offset from center slightly to 
 * account for search box.
 * 
 * @param ll {google.maps.LatLong} 
 */
DealerLocator.prototype.panTo = function(ll) {
	if(ll === null) {
		ll = new google.maps.LatLng(40, -95);
	}
	this.currentLocation = ll;
	var offset = 0;
	offset = doubler(.0002, (20 - this.map.getZoom()));
	var lng = ll.lng();
	lng += offset;

	var newll = new google.maps.LatLng(ll.lat(), lng, true);
	this.map.panTo(newll);
}

/**
 * Run the initial post-search animation.
 */
DealerLocator.prototype.initAnimation = function() {
	// move the search box
  if(this.firstRun) {
    var mapWidth = $('div#map-holder').width();
    var searchBoxWidth = $('div#searchBox').width();
    var startX = (mapWidth / 2) - ( searchBoxWidth / 2);
    var x = mapWidth  - searchBoxWidth + 110;
    var $searchBox = $('div#searchBox');
    $("form#searchForm").addClass("bottom-hr");
    $searchBox.css({'left':startX});
    $searchBox.animate({'top': 20},{queue: false, duration: 900})
    .animate({'left': x},{queue: false, duration: 900});
     this.firstRun = false;
  }
}
	
/**
 * Create the request url. Also sets daa handling vars.
 * 
 * @return {String} url for search request
 */
DealerLocator.prototype.getUrl = function() {
	var url = '/dealer/DealerSearch.do?';
  if(	$('#searchEntry').val() !== null) {
    var entry = $('#searchEntry').val(); 
  }
	
	// some basic validation
	// if the length is 5 and its a number, search by zip
	if(entry.length == 5 && entry == parseInt(entry, 10)){
		this.zipcode = entry;
		url += 'searchBy=zip&distance=100&zipCode=' + entry;
	}// else search by name
	else if (entry.length > 3) {
		url += 'searchBy=name&distance=100&name=' + entry.toUpperCase();
	}
	else {
		// throw an invalid entry error
		this.showError('Invalid entry. Please check your entry and try again.');
		return false;
	}
	
	// handle daa session here
	if(window.daasession != undefined && window.daasession.daaID != undefined) {
		this.isDaa = true;
		url = '/global/services/daa/DAADealerSearch.php?daaCode=' + window.daasession.daaID + '&zipCode=' + entry;
		$('#instructions').text('Enter Zip Code');
	}
	url += '&crm=false';
	return url;
}
	
	
/**
 * Create an array of dealer objects for the results.
 * Add markers to the map for each dealer.
 * 
 * @param {XML} xml result of the ajax call
 */
DealerLocator.prototype.setResult = function(xml){
	
	var count = 0;
	var dealers = new Array();
	var dl = this;
	
	$(xml).find('dealer').each(function(){
		var lat = jQuery.trim($(this).find('latitude').text());
		var long = jQuery.trim($(this).find('longitude').text());
		
		var dealer = new DealerObject(
				jQuery.trim($(this).find('id').text()),
				count + 1,
				jQuery.trim($(this).find('name').text()),
				jQuery.trim($(this).find('address1').text()), 
				jQuery.trim($(this).find('city').text()), 
				jQuery.trim($(this).find('state').text()), 
				jQuery.trim($(this).find('zip').text()),
				jQuery.trim($(this).find('phone').text()),
				jQuery.trim($(this).find('url').text()),
				lat,
				long,
				jQuery.trim($(this).find('participant').text())
				
		);
		
		// avoid duplicates
			if(!dealers.contains(dealer)){
				if(dl.map != undefined){
					dl.createMarker(dealer, count);
				}
				dealers.push(dealer);
			}
		if(dl.map != undefined) {	
			if(count == 0){ 
				dl.currentLocation = dealer.ll;
				dl.map.setZoom(8);
				//dl.panTo(dealer.ll);
				
			}
		}
		count++;
	}); //close each
	
	if(this.isDaa) {
		this.handleDaa(xml);
	}
	
	this.dealers = dealers;
	$.hideLoader();
}
	
/**
 * Add a marker to the map.
 * 
 * @param {Dealer} dealer Dealer Object
 */
DealerLocator.prototype.createMarker = function(dealer, count) {
	var dl = this;
	
	 var image = new google.maps.MarkerImage('images/pushPin.png',
		      new google.maps.Size(42, 42),
		      new google.maps.Point(0,0),
		      new google.maps.Point(21, 42));
	  var shadow = new google.maps.MarkerImage('images/msmarker.shadow.png',
	      new google.maps.Size(77, 42),
	      new google.maps.Point(0,0),
	      new google.maps.Point(21, 42));
	  var shape = {
		      coord: [10, 1, 40, 1, 40, 30, 10 , 30],
		      type: 'poly'
		  };
	  var marker = new google.maps.Marker({
		  	position:dealer.ll,
	        map: dl.map,
	        shadow: shadow,
	        icon: image,
	        shape: shape,
	        title:dealer.name
	    });
	  
	  google.maps.event.addListener(marker, 'click', function() {
		  dl.infowindow.open(dl.map,marker);
		  dl.infowindow.setContent(dl.createInfoWindowContent(dealer));
		  dl.panTo(dealer.ll);
		  dl.showListingFromMarker(count);
		});
	  
	dealer.marker = marker;
	
	this.markers.push(marker);
	
}

/** 
 * Open the correct dealer listing when a marker 
 * is clicked.
 * 
 * @param {String} index number of selected dealer.
 */
DealerLocator.prototype.showListingFromMarker = function(index) {
	// is it in the current set?
	var id = 0;
	for(var i = 0; i < this.pages[this.currentPage].length; i++) {
		if(this.dealers[index] == this.pages[this.currentPage][i]) {
			$('#results').accordion("activate", id);
			break;
			return;
		}
		id++;
	}
	// if it isn't we need to find the right page
	for( var j = 0; j < this.pages.length; j++) {
		// skip the current page, already checked
		if(j == this.currentPage){
			continue;
		}
		var temp = this.pages[j];
		id = 0;
		for(var i = 0; i < temp.length; i++) {
			if(this.dealers[index] == temp[i]) {
				this.currentPage = j;
				this.displayResults(this.pages[j], id);
				
				break;
				return;
			}
			id++;
		}
	}
}
	
/**
 * Generate infowindow content.
 * 
 * @param {Dealer} dealer object
 * 
 * @return {String} InfoWindow HTML content
 */
DealerLocator.prototype.createInfoWindowContent = function(dealer) {
		var contentString = '<div id="info-' + dealer.id + '" class="infowindow">' + 
							'<h3>' + dealer.name + '</h3>' + 
							'</div>';
		return contentString;
	}

/**
 * Display selected page of results.
 * 
 * @param {Array} set Array containing current page of dealer objects.
 */
DealerLocator.prototype.displayResults = function(set, id){
	var dl = this; // because this is a recursive method
					// reference the main instance
	dl.clearResults();
	var total = dl.dealers.length;
	var start = dl.currentPage * 5;

	// create the dealer listings
	for(var i = 0; i < set.length; i++) {
		dl.createDealerListing(set[i]);
	}
	// reset the accordion
	$('#results').accordion('destroy').accordion({collapsible: true, autoHeight: false, active: false});
	$( "#results" ).bind( "accordionchangestart", function(event, ui) {
		 $('.get-directions').hide(); // fix IE6/7 issues 
		});
	if(id == undefined){
		id = 0
	}
	$('#results').accordion("activate", id);
	
	// pagination text and links
	if(total > 5) {
		var paginationDiv = document.createElement('div');
		paginationDiv.id = 'pagination';
		$('#results').append(paginationDiv);
		$('#pagination').html('<p>' + (start + 1) + '-' + (set.length + start) + ' of ' + this.dealers.length + ' matches </p>');	
		
		if(dl.currentPage - 1 >= 0) {
			$('#pagination p').prepend('<a id="prevpage" href="#"><img src="images/spacer.gif" alt="previous" /></a>');
			$('#prevpage').click(function(event) {
				event.preventDefault();
				dl.displayResults(dl.pages[--dl.currentPage]);
			});
		}

		if(dl.pages[dl.currentPage + 1] != undefined) {
			$('#pagination p').append('<a id="nextpage" href="#"><img src="images/spacer.gif" alt="next" /></a>');
			$('#nextpage').click(function(event) {
				event.preventDefault();
				dl.displayResults(dl.pages[++dl.currentPage]);
			});
		}
	}
	else
	{
		$('#pagination').empty();
	}

}

/**
 * Create pagination.
 * 
 * @param {XML} xml Raw xml from ajax call.
 */
DealerLocator.prototype.paginateResults = function (xml) {
	var dealers = this.dealers;
	var total = dealers.length;
	var pages = this.pages;
	var pageCount = 0;
	pages[pageCount] = new Array();
	for(var i = 0; i < dealers.length; i++) {
		if(i > 0 && i % 5 == 0) {
			pageCount++;
			pages[pageCount] = new Array();
		}
		pages[pageCount].push(dealers[i]);
	}
	// display the first set
	this.displayResults(pages[0]);
};

/**
 * Remove results from dealer list.
 */
DealerLocator.prototype.clearResults = function (){
	$('#results').empty();
};
	
/**
 * Create listing for dealer in search results box.
 * 
 * @param {Dealer} dealer Dealer Object.
 */
DealerLocator.prototype.createDealerListing = function(dealer) {
	var infowindow = this.infowindow;
	var map = this.map;
	var dl = this;
	var createInfoWindowContent = this.createInfoWindowContent;
	var dealerdiv = '<div id="div-' + dealer.id + '"><address>' + dealer.street + '<br />' +
		dealer.city + ', ' +dealer.state + ' ' + dealer.zip + '<br />' + 
		dealer.phone + 
		'</address>' +
		'<a href="' + dealer.url + '">Launch Dealer Site</a>';
		if(dealer.participant == 'true') {
      if(this.model != null && this.model != 'dealerlocator') {
         dealerdiv += '<a href="/' + this.model + '/quote/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + '">Get a Quote</a>' +
          '<a href="/' + this.model + '/contactadealer/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + '">Contact Dealer</a>' +
          '<a href="/' + this.model + '/joyride/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + '">Schedule a Test Drive</a>';
       }
       else
       {
        dealerdiv += '<a href="/quote/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + this.getModelSuffix() + '">Get a Quote</a>' +
          '<a href="/contactadealer/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + this.getModelSuffix() + '">Contact Dealer</a>' +
          '<a href="/joyride/en/us/?zipCode=' + dealer.zip + '&dealerID=' + dealer.id + this.getModelSuffix() + '">Schedule a Test Drive</a>';
        }  
      }
		dealerdiv += '<a href="#" id="get-directions' + dealer.id + '">Get Directions</a>' +
		'<div class="get-directions">' + 		
			'<form id="form-dir-' + dealer.id + '">' +
			'<p>Starting address</p>' +
			'<div class="get-directions-container">' + 
			'<input type="text" name="from-text" class="directions-input" id="from-text-' + dealer.id + '" />' + 
			'</div>' + 
			'<input type="image" src="/dealerlocator/en/us/images/go.gif" class="directions-submit" value="Submit" id="form-dir-' + dealer.id +'"  />' + 
			'</form>' + 
		'</div>' + 
	'</div>';


	$('#results').append('<h3 id="' + dealer.id + '"><div class="listing-num">' + dealer.divid + '</div><a>' + dealer.name +  '</a></h3>');
	$('#' + dealer.id)
		.after(dealerdiv)
		.click(function(){
			if(map != undefined){
				
				infowindow.open(map,dealer.marker);
				infowindow.setContent(createInfoWindowContent(dealer));
				dl.panTo(dealer.ll);
			}
		});
	$('#div-' + dealer.id + ' a').prepend('<span class="ui-icon ui-icon-triangle-1-e"></span>');
	
	$('#get-directions' + dealer.id).click(function(event) {
		event.preventDefault();
		var $next = jQuery(event.target).next('.get-directions');
		$next.effect('slide',{},500);
	});
	
	this.handleGetDirections(dealer);

	return this;
}

DealerLocator.prototype.getModelSuffix = function () {
	var suffix = "";
	if(this.model != null && this.model != 'dealerlocator') {
		suffix += '&model=' + this.model;
	}
	return suffix;
}
/**
 * Handle "Get directions" submit.
 * 
 * @param {DealerObject} dealer
 */

DealerLocator.prototype.handleGetDirections = function (dealer){
	$('#form-dir-'+ dealer.id).submit(function(event){
		event.preventDefault();
		var saddr = jQuery(event.target).find('#from-text-' + dealer.id).val();
		if(saddr != '' && saddr != 'Enter starting address.'){
			var google = 'http://maps.google.com/maps?';
			var daddr = dealer.street + ' ' + dealer.city + ' ' + dealer.state + ' ' + dealer.zip;
			var saddr = jQuery(event.target).find('#from-text-' + dealer.id).val();
			google += 'saddr=' + saddr + '&daddr=' + daddr + '(' + dealer.name + ')';
			window.open(google);
		}
		else
		{
			jQuery(event.target).find('#from-text-' + dealer.id).val('Enter starting address.');
		}
	});
}

/**
 * Handle DAA request.
 * 
 * @param xml {XML}
 */
DealerLocator.prototype.handleDaa = function(xml) {
	

	
	var zipValidForDaa = $(xml).find("dealers").attr("ZIPValidForDAA");
	
	if(zipValidForDaa == "false") {
		this.showError("We're sorry, but the zip code you entered is not a part of our Association. Please see our list of participating dealers below.");
	}
}
	
/**
 * Remove all markers from map.
 */
DealerLocator.prototype.clearMarkers =  function() {
	if(this.map != undefined){
		this.infowindow.close()
		for(var i = 0; i < this.markers.length; i++) {
			this.markers[i].setMap(null);
		}
		this.markers = new Array();
	}
}

/**
 * Show search error.
 * 
 * @param {String} err Error message.
 */
DealerLocator.prototype.showError = function(err) {
	err = '<p>' + err + '</p>';
	$('#searchError').css("display","block").html(err);
	window.setTimeout(function(){$('#searchError').fadeOut('slow');}, 5000);
}

/*****************
*  EO DEALERLOCATOR
*****************/

/*****************
 * DEALER OBJECT
 ****************/

/**
 * Object to holder dealer information
 */
function DealerObject(id,divid, name, street, city, state, zip, phone, url, lat, long, part) {
	this.id = id;
	this.divid = divid;
	this.name = name;
	this.street = street;
	this.city = city;
	this.state = state;
	this.zip = zip;
	this.phone = formatPhoneNumber(phone);
	this.url = url;
	this.participant = part;
	try{
		this.ll = new google.maps.LatLng(lat, long, true);
	}
	catch(error){}
	
	this.marker = null;
	
	this.toString = function() {
		var str = Array("id: " + id,
		           "name: " + name,
		           "ll: " + ll
		           ).join("\n");
		return str;
	}
}

/*****************
 * EO DEALER OBJECT
 *****************/

/*****************
 * CUSTOM CONTROLS
 *****************/


/**
 * Controls to set the google map type.
 */
function HomeControl(controlDiv, map , label, callback) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.paddingBottom = '20px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.className = label + 'ControlUI';

  controlUI.title = 'Set Map Type';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.id = label + 'ControlText';
  controlText.innerHTML = label;
  
  controlUI.appendChild(controlText);
  
  $(controlUI).hover(
		  function() {
			  $(this).addClass('control-hover');
		  },
		  function() {
			  $(this).removeClass('control-hover');
		  }
  );
  
  $(controlUI).click(function() {
	 $('.hybridControlUI').removeClass('active-type'); 
	 $('.satelliteControlUI').removeClass('active-type'); 
	 $('.mapControlUI').removeClass('active-type'); 
	 $(this).addClass('active-type');
  });
  
  if(label == 'map'){
	$(controlUI).addClass('active-type');  
  }
  
  google.maps.event.addDomListener(controlUI, 'click', function() {
	  callback();
  });
}

/**
 * Zoom control for google map.
 * @param zoomDiv {DOM element} 
 * @param map {google.map}
 */
function ZoomControl(zoomDiv, map) {
	zoomDiv.style.padding = '10px';
	zoomDiv.style.paddingTop = '325px';
	
	var zoomContent = document.createElement('DIV');
	zoomContent.id = 'zoomSlider';
	zoomContent.style.height = '180px';
	
	zoomDiv.appendChild(zoomContent);
	
	// events on this control will be handled by jQuery
	$(zoomContent).slider({
		orientation: "vertical",

		value:4,
		min: 2,
		max: 20,
		step: 1,
		slide: function(event, ui) {
			map.setZoom(ui.value);
		
		}
	});
	
	// sync the maps zoom with the slider
	google.maps.event.addListener(map, 'zoom_changed', function() {
		if(map.getZoom() < 2) {
			map.setZoom(2);
		}
		$(zoomContent).slider("value", map.getZoom());
	});
	
	var zoomTop = document.createElement('DIV');
	zoomTop.id = 'zoomTop';
	
	$(zoomTop).click(function() {
		map.setZoom(map.getZoom() + 1);
	});
	
	var zoomBottom = document.createElement('DIV');
	zoomBottom.id = 'zoomBottom';
	
	$(zoomBottom).click(function() {
		map.setZoom(map.getZoom() - 1);
	});
	$(zoomDiv).prepend(zoomTop);
	$(zoomDiv).append(zoomBottom);
}


/*******************
 * UTILITY
 ******************/

/**
 * Extend array class. Check if a dealer is in the dealer array.
 * 
 * @param {DealerObject} dealer
 */
Array.prototype.contains = function (dealer) {
	for( var i = 0; i < this.length; i++) {
		if(dealer.id == this[i].id) {
			return true;
		}
	}
	return false;
}	


/**
 * Format phone number string.
 * @param {string} phone
 * @return {string} formatted phone number.
 */
function formatPhoneNumber(phone) {
	var fPhone = '(' + phone.substring(0,3) + ')' + phone.substring(3,6) + '-' + phone.substring(6,11);
	return fPhone;
}

/**
 * Detect the awfulness.
 */
function isIE6() {
	 var ua = navigator.userAgent.toLowerCase(); 
	 var isIE = (ua.indexOf('msie') != -1 );
	 var versionMajor = parseInt(parseFloat( ua.substring( ua.indexOf('msie ') + 5 ))); 
	 if( isIE && versionMajor == '6') {
		 return true;
	 }
	 else
	 {
		 return false;
	 }
}

function doubler(num, count) {
	for(var i = 0; i < count; i ++){
		num *= 2;
	}
	return num;
}
