﻿var mazdaDealersMap = {
	mapDiv: 'mapDiv',
	isDealerLocator: false,
	useAjaxHandler: false,
	getDirectionsText: 'Get directions',
	viewDetailsText: 'View details',
	testDriveText: 'Arrange a test drive with this dealer',
	clearDirectionsText: 'Close directions',
	inputLocationText: 'Your address',
	submissiontype: 'testdrive',
	totalDistanceText: 'Total distance',
	selectDealerText: 'Select dealer',
	hourText: 'hr',
	minuteText: 'min',
	kmText: 'km',
	mileText: 'miles',
	fromText: 'From:',
	toText: 'To:',
	telText: 'Tel:',
	servicenumberText: 'Numero de taller:',
	faxText: 'Fax:',
	emailText: 'Email:',
	websiteText: 'Website:',
	formurl: null,
	getDirectionsLink: '<li class="directions"><a href="{formurl}step=2&amp;dealerid={dealerId}&amp;showdirectiondetails=true">{directionText}</a></li>',
	viewDetailsLink: '<li class="details"><a href="{formurl}step=2&amp;dealerid={dealerId}">{detailText}</a></li>',
	testDriveLink: '<li class="testdrive"><a href="{testDriveUrl}">{testdriveText}</a></li>',
	selectDealerLink: '<li class="selectdealer"><a href="#selectDealer" onclick="javascript:dealers.select({dealerId}); $(\'.primary input\').click(); return false;">{selectText}</a></li>',
	pushpinTemplate: '<img src="{src}" class="dealerIcon" rel="{dealerId}" />',
	inputLatLon: null,
	inputAddressString: null,
	singleDealerDetails: false,
	locs: null,
	data: [],
	culture: '',
	pushpinUrls: ['/images/markers/home.gif', '/images/markers/red_{letter}.gif', '/images/markers/start.gif', '/images/markers/end.gif', '/images/markers/red.gif'],
	map: null,
	radius: null,
	showDirections: false,
	shortestRouteOption: 'time', 	// values: time or distance
	routeOption: null, 				// values: roundTrip or reverseTrip
	dataLayer: new VEShapeLayer(),
	userLayer: null,
	defaultWidth: 590,
	defaultHeight: 400,
	maxWidth: 948,
	maxHeight: 490,
	initZoomLevel: 5,
	autoInteraction: false,
	viewportThreshold: 1280,
	allowResizing: function() {
		if (!$('#mapResize').length) {
			$('#' + mazdaDealersMap.mapDiv).append('<a href="#" id="mapResize" onclick="mazdaDealersMap.toggleSize(); return false;"></a>'); // append map resize control
			$('.dealerLocator, .formwizard').css('overflow', 'visible'); // set overflow visible to allow for map resizing
			mazdaDealersMap.map.AttachEvent('onresize', mazdaDealersMap.onMapResize);
			mazdaDealersMap.toggleSize(cookie.get('mazdaMapSize'));
		}
	},
	disallowResizing: function() {
		if ($('#mapResize').length) {
			$('#mapResize').remove(); // remove the map resize control
			$('.dealerLocator, .formwizard').css('overflow', 'hidden'); // hide map overflow
			mazdaDealersMap.map.DetachEvent('onresize', mazdaDealersMap.onMapResize);
		}
	},
	loadMap: function() {
		this.locs = [];
		this.map = new VEMap(this.mapDiv);
		this.map.SetDashboardSize(VEDashboardSize.Normal);
		this.map.LoadMap(this.inputLatLon, 8, VEMapStyle.Road, false);
		this.map.Resize(this.defaultWidth, this.defaultHeight);

		// Map Resizing Behaviour
		if (!$('body.ie6, body.ie7').length) {
			var viewport = $(window);

			// onload
			if (viewport.width() >= mazdaDealersMap.viewportThreshold) {
				mazdaDealersMap.allowResizing();
			}

			// onresize
			viewport.bind('resize', function() {
				if (viewport.width() >= mazdaDealersMap.viewportThreshold) {
					mazdaDealersMap.allowResizing();
				} else {
					mazdaDealersMap.disallowResizing();
				}
			});
		}

		if (this.data != null && this.inputLatLon != null && this.inputAddressString != null) {
			var inputLocation = new VEShape(VEShapeType.Pushpin, this.inputLatLon);

			var customIcon = (this.showDirections === true) ? '<img src="' + this.pushpinUrls[2] + '" />' : '<img src="' + this.pushpinUrls[0] + '" />';
			inputLocation.SetCustomIcon(customIcon);
			//inputLocation.SetTitle(this.inputLocationText);
			//inputLocation.SetDescription(this.inputAddressString);

			this.userLayer = new VEShapeLayer();
			this.userLayer.AddShape(inputLocation);
			this.map.AddShapeLayer(this.userLayer);
		}

		var market = {
			'en-IE': 6,
			'nl-BE': 7,
			'fr-BE': 7,
			'nl-NL': 7
		};

		this.initZoomLevel = market[this.culture] || 5;

		if (this.data != null) {
			var initView = new VEMapViewSpecification(this.inputLatLon, this.initZoomLevel);

			this.dataLayer = this.addLocationsLayer(this.data, this.locs, false);
			this.map.AddShapeLayer(this.dataLayer);
			if (this.radius != null) {
				if ($('.noResults').length == 0) this.map.AddShape(this.createRadiusLayer());
			} else if (this.singleDealerDetails) {
				this.setView(10);
			} else {
				this.setView(this.initZoomLevel);
			}
			dealers.init();

			if ($('.noResults').length > 0) {
				this.hideEachShape();
				this.map.SetMapView(initView);
			}

		} else {
			this.map.SetMapView(initView);
		}

		if (! $('#summaryArea .dealerSearchFieldset').length && ! $('.summaryDirections').length && ! $('.noResults').length) {
			var that = mazdaDealersMap,
				correctCulture = true;

			if (cookie.get('mapSearchData') != null) {
				// cookie = mkt | lat | lon | zoom | radius
				mapSearchData = cookie.get('mapSearchData').split('|');

				// is the culture correct?
				if (mapSearchData[0] !== that.culture) correctCulture = false;

				if (correctCulture) {
					that.autoInteraction = true;

					var mapSearchLatLon = new VELatLong(mapSearchData[1], mapSearchData[2]),
						radius = parseInt(mapSearchData[4], 10);

					that.map.SetCenterAndZoom(mapSearchLatLon, parseInt(mapSearchData[3], 10));

					$.getJSON('/services/dealerajaxservice.ashx', { culture: that.culture, submissiontype: submissiontype, latlon: mapSearchLatLon, distance: radius }, function(json) {
						that.updateMap(json);
						that.autoInteraction = false;
					});
				}
			}
		}

		if (this.useAjaxHandler != null && this.useAjaxHandler == true && this.data.length == 0) this.map.AttachEvent('onchangeview', this.interactionHandler);

		if (this.showDirections && this.data.length && this.inputLatLon != null && this.inputAddressString != null) this.getDirections(this.data[0].lat, this.data[0].lon);
	},
	toggleSize: function(sizeParam) {
		var sizeParam = sizeParam || 'setByUser', mapSize;

		if (sizeParam == 'setByUser') {
			cookie.kill('mazdaMapSize');

			if ($('#mapResize').attr('href') == '#expandMap') {
				mapSize = 'large';
				cookie.set('mazdaMapSize', 'large', 7);
			} else {
				mapSize = 'normal';
				cookie.set('mazdaMapSize', 'normal', 7);
			}
		} else {
			if (sizeParam == null || sizeParam == 'normal') {
				mapSize = 'normal';
			} else {
				mapSize = 'large';
			}
		}

		var w = this.defaultWidth, h = this.defaultHeight, cssObj = { width: w + 'px', height: h + 'px', borderRightWidth: '0px', borderTopWidth: '0px', marginTop: '0px' };

		if (mapSize == 'large') {
			w = this.maxWidth;
			h = this.maxHeight;

			cssObj.width = w + 'px';
			cssObj.height = h + 'px';
			cssObj.borderRightWidth = '22px';
			cssObj.borderTopWidth = '22px';
			cssObj.marginTop = '-18px';
		}

		$('#' + this.mapDiv).animate(cssObj, 250, function() {
			mazdaDealersMap.map.Resize(w, h);
		});
	},
	onMapResize: function() {
		var currWidth = $('#' + mazdaDealersMap.mapDiv).width(),
			el = $('#mapResize');

		if (currWidth == mazdaDealersMap.defaultWidth) {
			el.attr('href', '#expandMap');
			el.css('background-image', 'url(/images/icons/map_expand.gif)');
		} else {
			el.attr('href', '#contractMap');
			el.css('background-image', 'url(/images/icons/map_contract.gif)');
		}
	},
	interactionHandler: function(e) {
		var that = mazdaDealersMap;

		if (that.autoInteraction) return false;

		if (that.map.GetZoomLevel() > that.initZoomLevel && that.map.GetZoomLevel() <= 13) {
			var center = that.map.GetCenter(),
			radius = 30,
			scaleArray = $('.MSVE_ScaleBarLabelFg').text().split(' ');
			if (scaleArray.length > 0) radius = scaleArray[0];
			radius = that.getDistanceTranslation(radius);
			$.getJSON('/services/dealerajaxservice.ashx', { culture: that.culture, submissiontype: submissiontype, latlon: center, distance: radius }, function(json) {
				that.updateMap(json);
			});

			cookie.set('mapSearchData', that.culture + '|' + center.Latitude + '|' + center.Longitude + '|' + that.map.GetZoomLevel() + '|' + radius);
		}
	},
	updateMap: function(newData) {
		var dataToBind = [],
			that = mazdaDealersMap;

		for (var index = 0; index < newData.length; index++) {
			var dealer = newData[index];
			if (!dealerInArray(that.locs, dealer)) dataToBind.push(dealer);
		}

		that.map.AddShapeLayer(that.addLocationsLayer(dataToBind, that.locs, true));
	},
	setView: function(zoom) {
		var s = this.locs;

		if (this.inputLatLon != null) {
			if (s.length == 1) {
				if (!s[0].Latitude == this.inputLatLon.Latitude && !s[0].Longitude == this.inputLatLon.Longitude) {
					s.push(this.inputLatLon);
				} else zoom = 10;
			} else s.push(this.inputLatLon);
		}

		if (this.locs.length > 1) {
			this.map.SetMapView(s);
		} else {
			var initView = new VEMapViewSpecification(s[0], zoom);
			this.map.SetMapView(initView);
		}
	},
	unloadMap: function() {
		if (this.map != null) {
			this.map.Dispose();
		}
	},
	addLocationsLayer: function(data, locs, isAddedOnDrag) {
		var that = this,
			layer = new VEShapeLayer();

		for (var index = 0; index < data.length; index++) {
			var dealer = data[index],
				itemLatLon = new VELatLong(dealer.lat, dealer.lon);
			locs.push(itemLatLon);

			var desc = '<div class="dealerPinPopup">';

			// extract dealer services array from dealer data and display in pushPin popup
			if (dealer.services !== undefined) {
				if (dealer.services.length > 0) {
					var dslookup = {
						sales: 'sales',
						service: 'service',
						parts: 'parts',
						mpsspecialists: 'mpsspecialists',
						zzapprovedused: 'zzapproved',
						motability: 'motability',
						testdrive: 'testdrive',
						authorisedrepairers: 'authorisedrepairers',
						mazdastore: 'mazdastore'
					};

					desc += '<ul class="services">';
					for (var i in dealer.services) desc += '<li class="' + dslookup[dealer.services[i].toLowerCase()] + '"></li>';
					desc += '</ul>';
				}
			}

			desc += '<div class="contactInfo">';

			// extract dealer address from dealer data and display in pushPin popup
			if (dealer.location !== '') {
				var dealerAddr = dealer.location.split(',');

				desc += '<address>';

				if (that.culture == 'de-DE' || that.culture == 'de-AT') {
					that.emailText = 'E-Mail:';
					for (var i = 0; i < (dealerAddr.length - 1); i++) {
						if (dealerAddr[i] !== '') desc += dealerAddr[i].replace(/^\s*/, '').replace(/\s*$/, '') + '<br />';
					}
				} else {
					for (var i in dealerAddr) {
						if (dealerAddr[i] !== '') desc += dealerAddr[i].replace(/^\s*/, '').replace(/\s*$/, '') + '<br />';
					}
				}

				desc += '</address>';
			}

			// extract dealer contact info from dealer data and display in pushPin popup
			var contactInfo = false;
			if (dealer.tel !== '' || dealer.fax !== '' || dealer.email !== '' || dealer.website !== '') contactInfo = true;

			if (contactInfo) desc += '<ul>';
			if (dealer.tel !== '') desc += '<li>' + that.telText + ' ' + dealer.tel + '</li>';
			if (that.culture == 'es-ES')
			 if (dealer.servicenumber !== '') desc += '<li>' + that.servicenumberText + ' ' + dealer.servicenumber + '</li>';
			if (dealer.fax !== '') desc += '<li>' + that.faxText + ' ' + dealer.fax + '</li>';
			if (dealer.email !== '') desc += '<li>' + that.emailText + ' <a href="mailto:' + dealer.email + '">' + dealer.email + '</a></li>';
			if (that.culture == 'de-DE' || that.culture == 'de-AT') {
				if (dealer.website !== '') desc += '<li>' + that.websiteText + ' <a href="' + dealer.website + '" target="_blank">' + dealer.website + '</a></li>';
			} else {
				if (dealer.website !== '') desc += '<li>' + that.websiteText + ' <a href="' + dealer.website + '" target="_blank">' + dealer.name + '</a></li>';
			}
			if (contactInfo) desc += '</ul>';

			desc += '</div>';

			desc += '<ul class="dealerLinks">';
			var linkSubstitutes = { 'formurl': mazdaDealersMap.formurl, 'dealerId': dealer.id, 'from': that.itemLatLon, 'directionText': that.getDirectionsText, 'detailText': that.viewDetailsText, 'testdriveText': that.testDriveText, 'selectText': that.selectDealerText, 'testDriveUrl': dealer.testdriveurl };
			if (!that.singleDealerDetails) {
				if (that.isDealerLocator) {
					desc += that.viewDetailsLink.substitute(linkSubstitutes);
					desc += that.getDirectionsLink.substitute(linkSubstitutes);
					if (that.culture == 'fr-CH' || that.culture == 'de-CH' || that.culture == 'it-CH') {
					}
					else {
						if (dealer.testdriveurl != "") {
							desc += that.testDriveLink.substitute(linkSubstitutes);
						}
					}
				} else {
					desc += that.selectDealerLink.substitute(linkSubstitutes);
				}
			}
			desc += '</ul>';

			desc += '</div>';

			var pin = new VEShape(VEShapeType.Pushpin, itemLatLon),
				formattedImg = { "src": that.pushpinUrls[1].substitute({ "letter": that.getMarkerImg(index) }), "dealerId": dealer.id };
			if (isAddedOnDrag) formattedImg = { "src": that.pushpinUrls[4], "dealerId": dealer.id };
			if (that.singleDealerDetails) formattedImg = { "src": that.pushpinUrls[3], "dealerId": dealer.id };
			pin.SetCustomIcon(that.pushpinTemplate.substitute(formattedImg));
			pin.SetTitle(dealer.name);
			pin.SetDescription(desc);

			layer.AddShape(pin);

			// Enable pin clustering
			var clusterOptions = new VEClusteringOptions();
			clusterOptions.Icon = new VECustomIconSpecification();
			clusterOptions.Icon.Image = '/images/markers/cluster.gif';

			layer.SetClusteringConfiguration(VEClusteringType.Grid, clusterOptions);
		}
		return layer;
	},
	createRadiusLayer: function() {
		var earthRadius = 6371;
		var lat = (this.inputLatLon.Latitude * Math.PI) / 180;
		var lon = (this.inputLatLon.Longitude * Math.PI) / 180;

		// increase the radius diameter slightly to avoid overlapping results
		var radius = this.radius,
			radiusAdjust = (radius == 100) ? 1.1 : 1.2,
			newRadius = radius * radiusAdjust;

		var d = parseFloat(newRadius) / earthRadius;
		var points = new Array();
		for (i = 0; i < 360; i++) {
			var point = new VELatLong(0, 0);
			var bearing = i * Math.PI / 180; // rad
			point.Latitude = Math.asin(Math.sin(lat) * Math.cos(d) + Math.cos(lat) * Math.sin(d) * Math.cos(bearing));
			point.Longitude = ((lon + Math.atan2(Math.sin(bearing) * Math.sin(d) * Math.cos(lat), Math.cos(d) - Math.sin(lat) * Math.sin(point.Latitude))) * 180) / Math.PI;
			point.Latitude = (point.Latitude * 180) / Math.PI;
			points.push(point);
		}

		var circle = new VEShape(VEShapeType.Polygon, points);
		circle.HideIcon();
		circle.SetLineColor(new VEColor(0, 108, 184, 0.5));
		circle.SetFillColor(new VEColor(166, 218, 255, 0.3));
		window.setTimeout(function() {
			mazdaDealersMap.map.SetMapView(points);
		}, 500);
		return circle;
	},
	getMarkerImg: function(j) {
		var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		return letters.charAt(j);
	},
	getDirections: function(lat, lon) {
		// this condition stops the directions from populating automatically
		if (!$('#summaryArea .summaryDirections').length) {
			this.userLayer.DeleteAllShapes();
			return false;
		}

		var options = new VERouteOptions(),
			that = this;

		options.DistanceUnit = (that.culture == 'en-GB') ? VERouteDistanceUnit.Mile : VERouteDistanceUnit.Kilometer;
		options.RouteOptimize = (that.shortestRouteOption != 'time') ? VERouteOptimize.MinimizeDistance : VERouteOptimize.MinimizeTime;
		options.RouteCallback = that.onGotRoute;
		options.SetBestMapView = true;
		options.RouteZIndex = 9999;

		if (that.routeOption != null) {
			if (that.routeOption == 'roundTrip') {
				that.map.GetDirections([that.inputLatLon, new VELatLong(lat, lon), that.inputLatLon], options);
				options.SetBestMapView = false;
			} else if (that.routeOption == 'reverseTrip') {
				that.map.GetDirections([new VELatLong(lat, lon), that.inputLatLon], options);
			}
		} else {
			that.map.GetDirections([that.inputLatLon, new VELatLong(lat, lon)], options);
		}

		tc_page_alias = tc_page_alias.replace('Step4', 'Step5');
	},
	onGotRoute: function(route) {
		var that = mazdaDealersMap;
		that.hideEachShape(); // hide existing pins

		var legs = route.RouteLegs,
			turns = '',
			numTurns = 0,
			leg = null,
			validRoute = false;

		for (var i = 0; i < legs.length; i++) {
			leg = legs[i]; // leg is a VERouteLeg object
			if (i == 0) { // from A to B
				turns += '<ul class="startEnd">';
				if (that.routeOption == 'reverseTrip') {
					turns += '<li class="start"><span>' + that.fromText + '</span> <strong>' + that.data[0].name + '</strong></li>';
					turns += '<li class="end"><span>' + that.toText + '</span> <strong>' + that.inputAddressString + '</strong></li>';
				} else {
					turns += '<li class="start"><span>' + that.fromText + '</span> <strong>' + that.inputAddressString + '</strong></li>';
					turns += '<li class="end"><span>' + that.toText + '</span> <strong>' + that.data[0].name + '</strong></li>';
				}
				turns += '</ul>';
			}

			if (i == 1) { // from B to A
				turns += '<ul class="startEnd roundTrip">';
				turns += '<li class="start"><span>' + that.fromText + '</span> <strong>' + that.data[0].name + '</strong></li>';
				turns += '<li class="end"><span>' + that.toText + '</span> <strong>' + that.inputAddressString + '</strong></li>';
				turns += '</ul>';
			}

			turns += '<h4>' + that.totalDistanceText + ': ' + route.Distance.toFixed(1) + ' ' + that.getUnits() + ' <span class="journeyTime">' + that.timeHandler(leg.Time) + '</span></h4>';

			var turn = null,
				turnHint = null,
				itinItems = legs[0].Itinerary.Items;

			// set start icon
			itinItems[0].Shape.SetCustomIcon(that.pushpinUrls[2]);

			// set end icon
			itinItems[itinItems.length - 1].Shape.SetCustomIcon(that.pushpinUrls[3]);

			// remove default end icon from roundTrip leg
			if (i == 1) legs[1].Itinerary.Items[legs[1].Itinerary.Items.length - 1].Shape.Hide();

			for (var j = 0; j < leg.Itinerary.Items.length; j++) {
				turn = leg.Itinerary.Items[j];
				turnHint = turn.Hints;
				numTurns++;

				turns += '<div class="itinStep" rel="' + turn.Shape.Primitives[0].iid + '"><em class="stepNum">' + turn.Shape.Title + '</em><span>' + turn.Text + '</span><em class="stepDis">' + turn.Distance.toFixed(1) + ' ' + that.getUnits() + '</em>';

				if (turnHint != null) {
					turns += '<ul class="hints">';
					for (var h in turnHint) {
						turns += '<li><em>' + turnHint[h].Text + '</em></li>';
					}
					turns += '</ul>';
				}

				turns += '</div>';
			}

			validRoute = true;
		}

		if (validRoute) {
			$('.dealerDirections .itinerary').append(turns);
			$('.dealerDirections .itinerary .itinStep:odd').css('background-color', '#eff9ff');

			// Add mouseover relationship between direction steps and map icons
			// $('.itinStep').mouseover(function() {
			// 	var relId = $(this).attr('rel');
			// 	$('div', '#'+relId).mouseover();
			// });

			// Create and append close directions link
			var clearDirectionsLink = '<br /><a href="#clearDirections" onclick="mazdaDealersMap.clearRoute()">' + that.clearDirectionsText + '</a>';
			$('.dealerDirections .itinerary').append(clearDirectionsLink);

			// Display the directions
			$('.dealerDirections').slideDown(300, function() {

				// Set the stepNum column width (padding allowance) by checking the text lengths
				var stepNumWidth = 0;

				$('.stepNum').each(function() {
					stepNumWidth = ($(this).width() > stepNumWidth) ? $(this).width() : stepNumWidth;
				});

				$('.itinStep span, .itinerary .itinStep .hints').css('padding-left', (stepNumWidth + 14) + 'px');

				// IE7 display fix
				$(this).show(function() {
					$('.ie7 .dealerDirections .itinerary').hide().show();
				});
				that.resetRouteTrips();
			});
		}
	},
	clearRoute: function() {
		var that = mazdaDealersMap;
		try {
			that.map.DeleteRoute();
			that.map.SetCenter(that.inputLatLon);
			that.setView(that.locs);
			$('.dealerDirections .itinerary').empty();
			$('.dealerDirections').slideUp(300, function() {
				$(this).hide(function() {
					//$('.ie7 .dealerDirections .itinerary').css({ 'position':'static' });
				});
			});
			that.showEachShape();
			that.userLayer.DeleteAllShapes();
		} catch (err) {
			alert(err.message);
		}
	},
	resetRouteTrips: function() {
		$('#summaryArea .directionActions input').attr('checked', false);
		mazdaDealersMap.routeOption = null;
		colourOpeningTimeRows();
	},
	hideEachShape: function() {
		if (this.dataLayer != null) {
			for (var i = 0; i < this.dataLayer.GetShapeCount(); i++) {
				var shape = this.dataLayer.GetShapeByIndex(i);
				shape.Hide();
			}
		}
		if (this.userLayer != null) {
			for (var i = 0; i < this.userLayer.GetShapeCount(); i++) {
				var shape = this.userLayer.GetShapeByIndex(i);
				shape.Hide();
			}
		}
	},
	showEachShape: function() {
		for (var i = 0; i < this.dataLayer.GetShapeCount(); i++) {
			var shape = this.dataLayer.GetShapeByIndex(i);
			shape.Show();
		}
		for (var i = 0; i < this.userLayer.GetShapeCount(); i++) {
			var shape = this.userLayer.GetShapeByIndex(i);
			shape.Show();
		}
	},
	timeHandler: function(time) {
		var timeStr = '',
			secs = parseInt(time, 10);

		var hours = Math.floor(secs / 3600);
		if (hours > 0) timeStr += hours + ' ' + this.hourText + ' ';

		var minutes = Math.floor((secs % 3600) / 60);
		if (minutes > 0) timeStr += minutes + ' ' + this.minuteText;

		return timeStr;
	},
	getDistance: function(latlong1, latlong2, miles) {
		var lat1 = this.getDegtoRad(latlong1.Latitude);
		var lon1 = this.getDegtoRad(latlong1.Longitude);
		var lat2 = this.getDegtoRad(latlong2.Latitude);
		var lon2 = this.getDegtoRad(latlong2.Longitude);

		var dLat = lat2 - lat1;
		var dLon = lon2 - lon1;
		var cordLength = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dLon / 2), 2);
		var centralAngle = 2 * Math.atan2(Math.sqrt(cordLength), Math.sqrt(1 - cordLength));
		return this.getEarthRadius() * centralAngle;
	},
	getUnits: function() {
		return this.culture == 'en-GB' ? this.mileText : this.kmText;
	},
	getDistanceTranslation: function(distance) {
		if (this.culture == 'en-GB') return (parseFloat(distance) / 0.621371192).toFixed(0);
		return distance;
	},
	getEarthRadius: function(miles) {
		var earthRadius = 6367;
		if (miles) return earthRadius * 0.621371192;
		return earthRadius;
	},
	getDegtoRad: function(x) {
		return x * Math.PI / 180;
	}
};

String.prototype.substitute = function(object) {
	return this.replace(/{[^{}]+}/g, function(key) {
		return object[key.replace(/[{}]+/g, "")] || "";
	});
};

function dealerInArray(array, obj) {
	for (var i = 0; i < array.length; i++) {
		if (array[i].Latitude == obj.lat && array[i].Longitude == obj.lon) return true;
	}
	return false;
}
