var RoutenPlaner = {};

RoutenPlaner.lang = {
	'EN_en': {
		'GoogleMaps._onGDirectionsError.unknownAddress': 'Sorry, a match could not be found in our database. Please check your input.',
		'Interface._doSearch.streetError': 'Please fill in a street.',
		'Interface._doSearch.zipError': 'Please fill in a zip code.',
		'Interface._doSearch.cityError': 'Please fill in a city.',
		'Interface._onGDirectionsLoad.description': 'Description',
		'Interface._onGDirectionsLoad.distance': 'Distance',
		'Interface._onGDirectionsLoad.timeToTravel': 'Time of travel',
		'Interface._onGDirectionsLoad.searchResults': 'search results'
	},
	
	'DE_de': {
		'GoogleMaps._onGDirectionsError.unknownAddress': 'Die von Ihnen eingegebene Adresse konnte nicht gefunden werden. Bitte %FCberpr%FCfen Sie Ihre Eingabe.',
		'Interface._doSearch.streetError': 'Bitte geben Sie eine Stra%DFe an.',
		'Interface._doSearch.zipError': 'Bitte geben Sie eine PLZ an.',
		'Interface._doSearch.cityError': 'Bitte geben Sie eine Stadt an.',
		'Interface._doSearch.destinationError': 'Bitte w%E4hlen Sie ein Ziel-Restaurant aus.',
		'Interface._onGDirectionsLoad.description': 'Beschreibung',
		'Interface._onGDirectionsLoad.distance': 'Strecke',
		'Interface._onGDirectionsLoad.timeToTravel': 'Fahrzeit',
		'Interface._onGDirectionsLoad.searchResults': 'Gesamtangaben'
	}
}

RoutenPlaner.cGoogleMaps = Class.create({
	_element: null,
	_map: null,
	_gdir: null,
	_options: {},
	_marker: null,
	_marker_counter: 0,
	
	_lastUsedDirectionFrom: null,
	_lastUsedDirectionTo: null,
	
	initialize: function(element, options)
	{
		this._options = Object.extend({
			startCords: [0.0, 0.0, 10],
			locale: 'EN_en'
		}, options || {});
		
		if ($(element))
			this._element = $(element);
		else
			return false;
		
		RoutenPlaner.lang = RoutenPlaner.lang[this._options.locale];
		
		this._marker = new Hash();
		this._map = new GMap2(this._element);
		this._map.addControl(new GLargeMapControl());
		
		this._gdir = new GDirections(this._map);
		
		GEvent.addListener(this._gdir, 'load', this._onGDirectionsLoad.bind(this));
		GEvent.addListener(this._gdir, 'error', this._onGDirectionsError.bind(this));
		
		GEvent.addListener(this._map, 'infowindowbeforeclose', function() {
			$('maredo_standorte_chosenlocation').update('');    	}); 
    	
		this.centerByStartCoordinates();
		
		Event.observe(window, 'unload', GUnload);
		
		return true;
	}, // function
	
	setDirections: function(from, to)
	{
		this._lastUsedDirectionFrom = from = this._getAddress(from);
		this._lastUsedDirectionTo = to = this._getAddress(to);

		this._gdir.loadFromWaypoints([from, to], {
				'locale': this._options.locale,
				getPolyline: true,
				getSteps: true
			});
	}, // function
	
	_getAddress: function(value)
	{
		if (typeof value == 'object')
		{
			var a = Object.extend({
				street: null,
				zip: null,
				city: null
			}, value || {});
			
			value = '';
			
			if (Object.isString(a.street) && ! a.street.blank())
				value += a.street;
				
			if (Object.isString(a.zip) && ! a.zip.blank())
				value += (a.street.blank() ? a.zip : ', ' + a.zip);
				
			if (Object.isString(a.city) && ! a.city.blank())
				value += (value.blank() ? a.city : (a.zip.blank() ? ', ' + a.city : ' ' + a.city));
		} // if
		
		return value;
	}, // function
	
	_onGDirectionsLoad: function() { },
	
	_onGDirectionsError: function()
	{
		if (this._gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
		{
			if (Object.isString(this._lastUsedDirectionFrom) && !this._lastUsedDirectionFrom.blank())
			{
				this.getGeocoder().getLatLng(this._lastUsedDirectionFrom, function(point)
				{
					if (!Object.isString(this._lastUsedDirectionTo) || this._lastUsedDirectionTo.blank())
						return;
					else if (point)
						this.setDirections(point.toString(), this._lastUsedDirectionTo);
					else
						alert(unescape(RoutenPlaner.lang['GoogleMaps._onGDirectionsError.unknownAddress']));
				}.bind(this));
			}
			else
				alert(unescape(RoutenPlaner.lang['GoogleMaps._onGDirectionsError.unknownAddress']));
		} // if
		else if (this._gdir.getStatus().code == G_GEO_SERVER_ERROR)
			alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + this._gdir.getStatus().code);
		else if (this._gdir.getStatus().code == G_GEO_MISSING_QUERY)
			alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + this._gdir.getStatus().code);
		else if (this._gdir.getStatus().code == G_GEO_BAD_KEY)
			alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + this._gdir.getStatus().code);
		else if (this._gdir.getStatus().code == G_GEO_BAD_REQUEST)
			alert("A directions request could not be successfully parsed.\n Error code: " + this._gdir.getStatus().code);
		else
			alert("An unknown error occurred.");
	}, // function
	
	setCenterByCoordinates: function(longitude, latitude, zoom)
	{
		this.setCenter(
				new GLatLng(longitude, latitude), zoom
			);
	}, // function
	
	setCenter: function(point, zoom)
	{
		this._map.setCenter(point, zoom, G_NORMAL_MAP);
	}, // function
	
	centerByStartCoordinates: function()
	{
		this.setCenterByCoordinates(
				this._options.startCords[0], this._options.startCords[1],
				((this._options.startCords.length > 2) ? this._options.startCords[2] : 15)
			);
	}, // function
	
	moveToAddress: function(address, zoom)
	{
		address = this._getAddress(address);
		
		this.getGeocoder().getLatLng(address, function(point) {
			if (point)
			{
				this.setCenter(point, zoom);	
			}
		}.bind(this));
	}, // function

	getGeocoder: function()
	{
		if (this._geocoder == null)
		{
			this._geocoder = new GClientGeocoder();
		} // if
		
		return this._geocoder;
	}, // function

	getLastUsedDirectionFrom: function()
	{
		return this._lastUsedDirectionFrom;
	}, // function
	
	getLastUsedDirectionTo: function()
	{
		return this._lastUsedDirectionTo;
	}, // function
	
// Marker
	addMarker: function(longitude, latitude)
	{
		var options = (arguments.length >= 3) ? arguments[2] : {};
		var marker_options = (arguments.length >= 4) ? arguments[3] : {};
		
		var marker = null;
		var point = new GLatLng(latitude, longitude);
		
		if (point)
		{
			marker = new RoutenPlaner.cGoogleMapsMarker(this, point, options, marker_options);
			this._map.addOverlay(marker.getMarker());

			this._marker.set(
					((options.id) ? options.id : 'anonymous_marker_' + this._marker_counter),
					marker
				);
			
			marker._afterAddEvent();
			
			this._marker_counter++;
		} // if
		
		return marker;
	}, // function
	
	getMarker: function(id)
	{
		return this._marker.get(id);
	} // function
});

RoutenPlaner.cGoogleMapsMarker = Class.create({
	_map: null,
	_options: {},
	_marker_options: {},
	_marker: null,

	initialize: function(map, point)
	{
		this._options = Object.extend({
			infoWindow: null
		}, (arguments.length >= 3) ? arguments[2] : {} || {});

		this._map = map;
		this._marker_options = (arguments.length >= 4) ? arguments[3] : {};

		this._preInitOptions();
		this._marker = new GMarker(point, this._marker_options);
		this._postInitOptions();
	}, // function

	_preInitOptions: function()
	{
		if (this._options.icon)
		{
			this._initIcon(this._options.icon);
		} // if
	}, // function

	_postInitOptions: function()
	{
		if (this._options.autoCenter)
		{
			this._map.setCenter(this.getPoint(), 15);
		} // if
		
		if (this._options.infoWindow)
		{
			this._initInfoWindow(this._options.infoWindow);
		} // if
	}, // function

	_initIcon: function (options)
	{
		var icon = new GIcon(G_DEFAULT_ICON);
		icon = Object.extend(icon, options);

		this._marker_options.icon = icon;
	}, // function

	_initInfoWindow: function(options)
	{
		options = Object.extend({
			event: 'click'
		}, options);

		GEvent.addListener(this._marker, options.event, GEvent.callback(this, function() {
			this.openInfoWindow();
		}));
	}, // function
	
	getInfoWindowContent: function()
	{
		return this._options.infoWindow.html;
	},

	openInfoWindow: function()
	{
		if (!this._options.infoWindow && arguments.length == 0) return;
		
		var options = Object.extend({
			html: '',
			zoom:  false,
			zoomLevel: 12
		}, this._options.infoWindow);
		
		if (arguments.length > 0)
		{
			options.html = arguments[0];
			this._options.infoWindow.html = options.html;
		}

		this.getMarker().openInfoWindowHtml(options.html);
		$('maredo_standorte_chosenlocation').update(options.html);

		if (options.zoom) {
			this._map.setCenter(
					this.getPoint(),
					options.zoomLevel
				);
		}
	}, // function
	
	_afterAddEvent: function()
	{	
		if (this._options.infoWindow && this._options.infoWindow.autoOpen)
		{
			this.openInfoWindow();
		} // if
	}, // function
	
	getMarker: function() { return this._marker; },
	getPoint: function() { return this._marker.getPoint(); },
	setPoint: function(point) { this._marker.setPoint(point); }
});

RoutenPlaner.cInterface = Class.create(RoutenPlaner.cGoogleMaps, {
	_searchForm: null,
	_destinationDropdown: null,
	_loader: null,
	_options: {},
	
	initialize: function($super, element, options)
	{
		this._options = Object.extend({
			searchForm: 'maredo_standorte_searchform',
			searchFormSteet: 'street',
			searchFormZip: 'zip',
			searchFormCity: 'city',
			loader: 'maredo_standorte_loader'
		}, options || {});
		
		if (!$super(element, this._options))
			throw('GoogleMaps error');
		
		if (!(this._searchForm = $(this._options.searchForm)))
			throw('Searchformular not found');
		
		this._searchForm.observe('submit', function(e) {
				e.stop();
				this.doSearch();
			}.bindAsEventListener(this));
		
		this._destinationDropdown = this._searchForm.select('select').first();
		this._destinationDropdown.observe('change', this._onChangeLocationEvent.bindAsEventListener(this));
		
		this._loader = $(this._options.loader);
	}, // function
	
	_onChangeLocationEvent: function(e)
	{
		var option = this._destinationDropdown.options[this._destinationDropdown.options.selectedIndex];
		
		if (Element.hasClassName(option, 'city_option'))
		{
			var max_lat = parseFloat(Element.readAttribute(option, 'max_lat'));
			var min_lat = parseFloat(Element.readAttribute(option, 'min_lat'));
			var max_lon = parseFloat(Element.readAttribute(option, 'max_lon'));
			var min_lon = parseFloat(Element.readAttribute(option, 'min_lon'));

			if (!isNaN(max_lat) && !isNaN(min_lat) && !isNaN(max_lon) && !isNaN(min_lon))
			{
				var len_lon = max_lon - min_lon;
				var len_lat = max_lat - min_lat;
	
				min_lon-= len_lon * 0.1;
				max_lon+= len_lon * 0.1;
				min_lat-= len_lat * 0.1;
				max_lat+= len_lat * 0.1;
	
				var latitude = ((min_lat + max_lat) / 2);
				var longitude = ((min_lon + max_lon) / 2);
				
				var bds = new GLatLngBounds(new GLatLng(min_lat, min_lon), new GLatLng(max_lat, max_lon));
				var zoom  = this._map.getBoundsZoomLevel(bds);
	
				this.setCenterByCoordinates(latitude, longitude, zoom);
			}
			else
			{
				this.moveToAddress(option.value);
			} // if
		}
		else
		{
			var coordinates = Element.readAttribute(option, 'coordinates');
			var id = Element.readAttribute(option, 'id');
			var marker = null;
			
			if (Object.isString(id) && !id.blank() && (marker = this.getMarker(id)) != null)
			{
				marker.openInfoWindow();
			} // if
			else if (coordinates == null || coordinates.blank() || coordinates.split(',').length < 2)
			{
				this.centerByStartCoordinates();
			}
			else
			{
				var coordinatesParts = coordinates.split(',');
				this.setCenterByCoordinates(
						coordinatesParts[1], coordinatesParts[0],
						(coordinates.lenght >= 3) ? coordinates[2] : 15
					);
			} // if
		}
	}, // function
	
	doSearch: function(e)
	{
		$('maredo_standorte_summary').hide();
		$('maredo_standorte_description').hide();
		
		var street = this._searchForm.elements[this._options.searchFormSteet];
		var zip = this._searchForm.elements[this._options.searchFormZip];
		var city = this._searchForm.elements[this._options.searchFormCity];
		
		if (street.value.length == 0)
		{
			alert(unescape(RoutenPlaner.lang['Interface._doSearch.streetError']));
			street.focus();
			return false;
		}
		else if (city.value.length == 0)
		{
			alert(unescape(RoutenPlaner.lang['Interface._doSearch.cityError']));
			city.focus();
			return false;
		}
		else if (zip.value.length > 0 && (zip.value.length < 5 || !/^\d+$/.test(zip.value)))
		{
			alert(unescape(RoutenPlaner.lang['Interface._doSearch.zipError']));
			zip.focus();
			return false;
		}
		else if (this._destinationDropdown.value == '')
		{
			alert(unescape(RoutenPlaner.lang['Interface._doSearch.destinationError']));
			this._destinationDropdown.focus();
			return false;
		}
		
		this.setDirections(
				{ 'street': street.value, 'zip': zip.value, 'city': city.value },
				this._destinationDropdown.value
			);
		
		return true;
	}, // function
	
	_onGDirectionsLoad: function($super)
	{
		$super();
		this._loader.hide();
		
		var description = '<table id="routen-tabelle" cellpadding="0" cellspacing="0" summary="Die folgende Tabelle gibt eine Wegschreibung zum gew&auml;hlten Ziel an.">'
			+ '<thead><tr><th id="platzierung"></th>'
			+ '<th id="beschreibung">' + unescape(RoutenPlaner.lang['Interface._onGDirectionsLoad.description']) + '</th>'
			+ '<th id="Strecke">' + unescape(RoutenPlaner.lang['Interface._onGDirectionsLoad.distance']) + '</th>'
			+ '<th id="Zeit">' + unescape(RoutenPlaner.lang['Interface._onGDirectionsLoad.timeToTravel']) + '</th></tr>'
			+ '</thead><tbody>';
		
		for (var i=0; i < this._gdir.getRoute(0).getNumSteps(0); i++)
		{
			description+= '<tr><td class="rank">' + (i + 1) + '</td>';
			description+= '<td class="desc">' + this._gdir.getRoute(0).getStep(i).getDescriptionHtml() + '</td>';
			description+= '<td class="km">' + this._gdir.getRoute(0).getStep(i).getDistance().html + '</td>';
			description+= '<td class="time"><small>' + this._gdir.getRoute(0).getStep(i).getDuration().html + '</small></td></tr>';
		}
		 
		description+= '</tbody></table>';
		
		$('maredo_standorte_chosenlocation').update('');
		$('maredo_standorte_start_address').update(this.getLastUsedDirectionFrom().replace(/,/, '<br />'));
		$('maredo_standorte_destination_address').update(this.getLastUsedDirectionTo());

		$('maredo_standorte_summary_text').update(unescape(RoutenPlaner.lang['Interface._onGDirectionsLoad.searchResults']) + ': ' + this._gdir.getSummaryHtml())
		$('maredo_standorte_summary').show();
		
		$('maredo_standorte_description')
			.update(description)
			.show();

		// content des infoWindow ermitteln
		
		var option = this._destinationDropdown.options[this._destinationDropdown.options.selectedIndex];
		var id = Element.readAttribute(option, 'id');
		var marker = null;
		if (Object.isString(id) && !id.blank() && (marker = this.getMarker(id)) != null)
		{
			$('maredo_standorte_destination_description').update(marker.getInfoWindowContent().replace(/<div[^>]*>/, '<div>'));
		}
		
		$$('#subcontent > div.scroll').first().scrollTop = 300;
	}, // function
	
	_onGDirectionsError: function($super)
	{
		$super();
		this._loader.hide();
	}
});