
(function() {
	var formElement = document.getElementById('calculator');  
	var mapElement = document.getElementById('map');
	var inputs = {
		from: document.getElementById('calculator-from'),
		to: document.getElementById('calculator-to')
	}
	var comparsionTable = document.getElementById('comparsion');
	
	var defaultMapCenter = new GLatLng(50.087811, 14.42046);
	var defaultMapZoom = 12;
	var defaultAddress = ', Prague, Czech Republic';
	
	var map = new GMap2(mapElement);	
	var directions = new GDirections();
	var geocoder = new GClientGeocoder();
	var markers = {from:null, to:null};
	var locations = {from:null, to:null};
	var polyline = null;
	var formSubmitted = false;
	var messages = [];
	var formSubmittedByUser = false;
	
	map.setCenter(defaultMapCenter, defaultMapZoom);
	map.setUIToDefault();
	map.disableScrollWheelZoom();
	
	var clearMessages = function() {
		for (var i=0; i<messages.length; i++) {
			messages[i].parentNode.removeChild(messages[i]);
		}
		messages = [];
	}
	var showMessage = function(text, type) {		
		if (text) { 
			message = document.createElement('p');
			message.className = type || "";
			message.appendChild(document.createTextNode(text));			
			formElement.insertBefore(message, formElement.firstChild);
			messages[messages.length] = message;
		}
	};
	// Show calculated prices in comparsion table
	var showPrices = function() {
		var distance = directions.getDistance().meters / 1000;
		var rows = comparsionTable.getElementsByTagName('tbody')[0].getElementsByTagName('tr');		
		for (var i = 0; i < rows.length; i++) {
		  var cells = rows[i].getElementsByTagName('td');
		  var calc = rows[i].getAttribute("data-calc");
		  if (calc) {
		    var func = window[calc];  
		    var result = func(distance, cells);  
      } else {
        var km = parseFloat(cells[2].innerHTML);
        var price = parseFloat(cells[1].innerHTML) + km * distance;
        var result = 10 * Math.ceil(price / 10);
      }
      cells[4].innerHTML = result;
		}
	}
	
	// Redraws polyline when directions are loaded
	GEvent.addListener(directions, 'load', function() {		
		polyline = directions.getPolyline()
		map.addOverlay(polyline);
		showPrices();
		if (formSubmitted) {
			formSubmitted = false;			
			var bounds = polyline.getBounds(); 
			map.setZoom(map.getBoundsZoomLevel(bounds));
			map.panTo(bounds.getCenter());
			clearMessages();
			if (formSubmittedByUser) {
				showMessage('Celkovou cenu za hledanou cestu m\u016f\u017eete porovnat v tabulce.', 'info')
				showMessage('Na map\u011b si m\u016f\u017eete prohl\u00e9dnou a p\u0159\u00edpadn\u011b upravit trasu.', 'info');
			}
		}
	});
	// Shows error message when directions can not loaded
	GEvent.addListener(directions, 'error', function() {
		showMessage('Hledan\u00e1 cesta nebyla nalezena.', 'error');
	});
	// Finds new directions according to markers position
	var findDirections = function() {		
		if (polyline) map.removeOverlay(polyline);
		if (locations.from && locations.to) {			
			polyline = null;
			directions.loadFromWaypoints([locations.from, locations.to], {getPolyline:true});
		}
	};
	// Marker was draged
	var markerDrag = function(which) {
		locations["from"] = markers["from"].getLatLng();
		locations["to"] = markers["to"].getLatLng();
		clearMessages();
		findDirections();
	}
	// Shows marker at specified latlng
	var showMarker = function(which, latlng) {
		if (markers[which]) {
			markers[which].setLatLng(latlng);
		} else { 
			markers[which] = new GMarker(latlng, {draggable: true});
			map.addOverlay(markers[which]);
			GEvent.addListener(markers[which], 'dragend', function() {
				markerDrag(which);
			});			
		}
	};
	// Geocoder callback
	var showLocation = function(which, response) {
		if (response.Status.code == 200 && response.Placemark[0].AddressDetails.Accuracy > 3) {
			var coordinates = response.Placemark[0].Point.coordinates;
			var latlng = new GLatLng(coordinates[1], coordinates[0]);
			locations[which] = latlng;
			showMarker(which, latlng);
			findDirections();
		} else {
			formSubmitted = false;
			if (which == "from") { 
				showMessage('M\u00edsto n\u00e1stupu nebylo nalezeno.', 'error');
			} else {
				showMessage('C\u00edl cesty nebyl nalezen.', 'error');
			}
		}
	};
	// Finds location 
	var findLocation = function(which, query) {
		if (query.match(/airport|leti[sš]t[eě]/i)) {
			// Google does not know where Prague airport is
			var latlng = new GLatLng(50.107557723024094, 14.268144965171814);
			showMarker(which, latlng);
			locations[which] = latlng;
		} else {
			locations[which] = null
			geocoder.getLocations(query + defaultAddress, function(response){
				showLocation(which, response);
			});
		}
	};	
	// Finds locations given locations 
	var findLocations = function(fromQuery, toQuery) {
		findLocation('from', fromQuery);
		findLocation('to', toQuery);
	};
	// Submit search form
	var submitForm = function(silent) {
		var fromQuery = inputs.from.value.replace(/^\s*/, '').replace(/\s*$/, '');
		var toQuery = inputs.to.value.replace(/^\s*/, '').replace(/\s*$/, '');
		clearMessages();
		if (fromQuery && toQuery) {
			formSubmitted = true;
			findLocations(fromQuery, toQuery);
		} else if (!silent) {
			if (toQuery) {
				showMessage('Zadejte pros\u00edm m\u00edsto n\u00e1stupu.', 'error');
			} else if (fromQuery) {
				showMessage('Zadejte pros\u00edm c\u00edl cesty.', 'error');
			} else {
				showMessage('Zadejte pros\u00edm m\u00edsto n\u00e1stupu a c\u00edl cesty.', 'error');
			}
		}
	}
	
	GEvent.addDomListener(formElement, 'submit', function(e) {
		if (e.preventDefault) {
			e.preventDefault();
		} else {
			e.returnValue = false;
		}
		formSubmittedByUser = true;
		submitForm();
	});
	// Load default directions
	showMarker("from", defaultMapCenter);
	showMarker("to", defaultMapCenter);
	submitForm(true);
	
	
	var inputClickListenerFrom = GEvent.addDomListener(inputs.from, 'click', function(e) {
		this.value = "";
		GEvent.removeListener(inputClickListenerFrom);
	});
	var inputClickListenerTo = GEvent.addDomListener(inputs.to, 'click', function(e) {
		this.value = "";
		GEvent.removeListener(inputClickListenerTo);
	});
})();
