CM = window.CM || {};

CM.Geocoding = function(map){
	
	//Current WMS map.
	this.map = map;
	
	//Constant text for search input field.
	this.GEOCODING_EMPTY_FIELD_TEXT = 'Enter something in search field, please';
	this.SIDE_PANEL_WIDTH = '272';
	this.NO_RESPONSE_TEXT = 'We couldn\'t find what you were looking for, why not ';
	this.NO_RESPONSE_LINK_TEXT = 'add it to OpenStreetMap';
	this.NO_RESPONSE_LINK = 'http://mapzen.cloudmade.com';
	this.COUNTRY_INPUT_ERROR_MESSAGE = 'Should be longer than 1';
	this.STREET_INPUT_ERROR_MESSAGE = 'Should be longer than 2';
	this.ADD_POINT_INSTRUCTION = 'Right click to add one more destination point.';
	this.ADD_FIRST_POINT_INSTRUCTION = 'Right click on the map and select a start and end point to get started.';
	this.travel_mode = CM.DRIVING;
	this.clear_permalink_geocoding = false;
	this.clear_permalink_directions = false;

};

CM.Geocoding.prototype = {
	
	setControls : function(params){
		
		var _obj = this;
		
		if(!this.fieldsManager){
			this.fieldsManager = new CM.FieldsManager('directionsList');
		};
		
		if(!this.params){
			this.params = {};
		};
		
		for(var i in params){
			this.params[i] = params[i];
		};
		
		if($('preferenceSelect').selectedIndex == 1){
			this.travel_mode += '/shortest';
		};

		if(!MapState.permalinkControl){
			MapState.permalinkControl = new CM.PermalinkControl();
		};

		MapState.permalinkControl._update = function(){
			var opened_tab = 0;
			var directions = '';
			if(this._map.directions && _obj.filled_fields.length > 0){
				var tale = '&directions=';
				for(var i=0; i<this._map.directions.waypoints.length; i++){
					tale  += this._map.directions.waypoints[i]._lat+','+this._map.directions.waypoints[i]._lng;
					if(i!=this._map.directions.waypoints.length-1){
						tale += ',';
					};
				};
				tale += '&travel='+this._map.directions._options.travelMode;
				directions += tale;
			};
			
			var geocoding = '';
			if(this._map.geocoder){
				var tale = '&geocoding=';
				tale += this._map.geocoder.query;
				tale += '&active_page=' + this._map.geocoder._options.activePage;
				tale += '&results_number=' + this._map.geocoder._options.resultsNumber;
				
				if (this._map.geocoder.search_bbox) {
					var search_sw = this._map.geocoder.search_bbox.getSouthWest(),
					search_ne = this._map.geocoder.search_bbox.getNorthEast();
					tale += '&search_bbox=' + search_sw.lat() + '+' + search_sw.lng() + ',' + search_ne.lat() + '+' + search_ne.lng();
				};

				if(this._map.geocoder._options.bounds){
					var sw = this._map.geocoder._options.bounds.getSouthWest(),
					ne = this._map.geocoder._options.bounds.getNorthEast();
					tale += '&bbox=' + sw.lat() + '+' + sw.lng() + ',' + ne.lat() + '+' + ne.lng();
				};
				geocoding += tale;
			};
			
			var permalink = this._getPermalink();

			permalink = this._removeUrlParams(permalink, ['directions', 'travel', 'geocoding', 'bbox', 'layer', 'styleId', 'active_page', 'results_number', 'search_bbox', 'opened_tab']);
			
			if(_obj.clear_permalink_directions == false){
				 permalink += directions;
				 var iframeField = $("course-code");
				 if (iframeField) {
					 var iframeFieldValue = this._removeUrlParams(iframeField.value, ['directions', 'travel']);
					 iframeField.value = iframeFieldValue.replace("/iframe?", "/iframe?" + directions.replace('&', '') + '&');
				 }
			};
			
			permalink += '&styleId=' + MapState.id();
			
			if(_obj.clear_permalink_geocoding == false){
				permalink += geocoding;
			};
			
			if($('sidePanel').hasClassName('hidden')) {
				opened_tab = 0;
			} else {
				if($('geocodingOutput').hasClassName('hidden')){
					opened_tab = 1;
				} else if ($('routingControls').hasClassName('hidden')) {
					opened_tab = 2;
				}
			}
			
			permalink += '&opened_tab='+opened_tab;
			
			$('permalink_input').value = permalink;
			
			this._link.href = permalink;
			
			_obj.clear_permalink_geocoding = false;
			_obj.clear_permalink_directions = false;
			
		};
		
		var bottomLeft = new CM.ControlPosition(CM.BOTTOM_LEFT, new CM.Size(0, 0));
		this.map.addControl(MapState.permalinkControl, bottomLeft);
		this.setListeners();
		this.clearInputs();
		this.parseUrl();

	},
	
	setListeners : function(){
		
		var _obj = this;

		CM.DomEvent.addListener($('hidePanel'), 'click', this.hidePanel, this);
		CM.DomEvent.addListener($('getRoutes'), 'click', function(){
			if($('getRoutes').hasClassName('pressed')){
				$('getRoutes').removeClassName('pressed');
				this.hidePanel();
			} else {
				this.toggleDirections(true);
			}
		}, this);
		
		if($('searchButton')){
			CM.DomEvent.addListener($('searchButton'), 'click', function(){
					if($('searchButton').hasClassName('pressed')){
						$('searchButton').removeClassName('pressed');
						this.hidePanel();
					} else {
						this.toggleDirections(false);
					}
			}, this);
		};

		CM.DomEvent.addListener($('countryName'), 'focus', function(){
			if($('countryName').value == _obj.COUNTRY_INPUT_ERROR_MESSAGE){
				$('countryName').removeClassName('error');
				$('countryName').value = '';
			};
		});
		
		CM.DomEvent.addListener($('countryName'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			};
		}, this);
		
		CM.DomEvent.addListener($('cityTownName'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			};
		}, this);
		
		CM.DomEvent.addListener($('streetName'), 'focus', function(){
			if($('streetName').value == _obj.STREET_INPUT_ERROR_MESSAGE){
				$('streetName').removeClassName('error');
				$('streetName').value = '';
			};
		});
		
		CM.DomEvent.addListener($('streetName'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			}
		}, this);
		
		CM.DomEvent.addListener($('poiType'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			}
		}, this);
		
		CM.DomEvent.addListener($('houseNumber'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			}
		}, this);
		
		CM.DomEvent.addListener($('stateName'), 'keypress', function(event){
			var event = event || window.event;
			if (event.keyCode == 13) {
				this.getAdvancedSearch();
			}
		}, this);

		CM.DomEvent.addListener($('advancedSearchButton'), 'click', function(){
			this.getAdvancedSearch();
		}, this);
		
		CM.DomEvent.addListener($('shareLink'), 'click', function(){
			MapState.permalinkControl._update();
		});

		CM.DomEvent.addListener($('searchResult'), 'click', function(){
			if ($('geocodingOutput').hasClassName('hidden')){
				_obj.toggleDirections(false);
			};
		});
		
		CM.DomEvent.addListener(this.map.getPane(CM.Map.MAP_PANE), 'contextmenu', function(event){
			
			CM.DomEvent.preventDefault(event);
			if(!_obj.context_menu){
				_obj.context_menu = new CM.ContextMenu({
					'obj':_obj
				});
			}
			_obj.context_menu.show(event);
		});

		CM.DomEvent.addListener($('clearRoute'), 'click', function(){
			this.clear_permalink_directions = true;
			this.clearInputs(true);
			this.clearRoutesInfo();
			this.reloadFields();
			MapState.permalinkControl._update();
			this.directions = null;
			this.map.directions = null;
			this.routing_inprogress = false;
			this.fieldsManager.clearFields();
			$('loadingIndicatorRouting').addClassName('hidden');
			$('clearRoute').addClassName('hidden');
			$('routeExportLinks').addClassName('hidden');
			$('noRoutingMessage').removeClassName('hidden');
		}, this);

		$$('#transportSwitcher a').each(function(item) {
			var item = item;
			
			var switcherHandler = function(event){
				if($('drivingButton').hasClassName('pref')){
					_obj.saved_travel_preference = $('preferenceSelect').selectedIndex;
				};
				$$('#transportSwitcher a').each(function(link) {
					link.removeClassName('pref');
				});
				item.addClassName('pref');
				
				switch (item.id) {
				
					case 'drivingButton':
						$('preferenceSelect').disabled = '';
						if(_obj.saved_travel_preference){
							$('preferenceSelect').selectedIndex = _obj.saved_travel_preference;
						};
						_obj.travel_mode = CM.DRIVING;
					break;
					
					case 'walkingButton':
						$('preferenceSelect').selectedIndex = 0;
						$('preferenceSelect').disabled = 'disabled';
						_obj.travel_mode = CM.WALKING;
					break;
					
					case 'cyclingButton':
						$('preferenceSelect').selectedIndex = 0;
						$('preferenceSelect').disabled = 'disabled';
						_obj.travel_mode = CM.CYCLING;
					break;
				};
				_obj.refreshFields();
				_obj.reloadFields();
			};
			
		 	CM.DomEvent.addListener(item, 'click', function(event){
		  		switcherHandler(event);
			});
			
			CM.DomEvent.addListener(item, 'keypress', function(event){
				var event = event || window.event;
				if (event.keyCode == 13) {
					switcherHandler(event);
				};
			});
		});
		
		CM.DomEvent.addListener($('preferenceSelect'), 'change', function(){
			this.travel_mode = CM.DRIVING;
			if($('preferenceSelect').selectedIndex == 1){
				this.travel_mode = CM.DRIVING + '/shortest';
			};
			this.refreshFields();
			this.reloadFields();
		}, this);
		
		CM.DomEvent.addListener($('clearSearch'), 'click', function(){
			var list_elements = $('geocodingOutput').adjacent('li');
			this.search_results_number = 0;
			this.clear_permalink_geocoding = true;
			MapState.permalinkControl._update();
			this.geocoder = null;
			this.map.geocoder = null;
			this.changeTempMarkersState();
			this.clearVectorOverlays();
			$('clearSearch').addClassName('hidden');
			$('geocodingOutput').adjacent('li.no_response').each(function(item){
				item.remove();
			});
			$('geocodingOutput').adjacent('li.geocoding_location').each(function(item){
				item.remove();
			});
			if($('customPager')){
				$('customPager').remove();
			};
			if(this.map._infoWindow && !this.map._infoWindow.isClosed()){
				this.map.closeInfoWindow();
			};
			if($('geocodingErrorMessage')){
				$('geocodingErrorMessage').remove();
			};
			$('countryName').value = '';
			$('cityTownName').value = '';
			$('streetName').value = '';
			$('poiType').value = '';
			$('houseNumber').value = '';
			$('stateName').value = '';
			$('lookinProcess').addClassName('hidden');
			$('geocodingPager').addClassName('hidden');
			$('geocodingAdvancedSearchPanel').addClassName('hidden');
			$('geocodingExportLinks').addClassName('hidden');
			$('noGeocodingMessage').removeClassName('hidden');
			$('advancedSearchOptions').adjacent('input').each(function(item){
				item.removeClassName('error');
			});
		}, this);

	}, 
	
	clearInputs : function(state){
		this.fieldsManager.clearFields();
		if(!state){
			$('countryName').value = '';
			$('cityTownName').value = '';
			$('streetName').value = '';
			$('poiType').value = '';
			$('houseNumber').value = '';
			$('stateName').value = '';
		};
	},
	
	showPanel : function(){
		this.setLinks();
		var side_panel = $('sidePanel');
		if(side_panel.hasClassName('hidden')){
				side_panel.removeClassName('hidden');
			var map_control = $('map').adjacent('.wml-map-control')[0];
			var permalink = $('map').adjacent('.wml-permalink')[0];
			var scale_control = $('map').adjacent('.wml-scale-control')[0];
			var copyright = $('map').adjacent('.wml-copyright')[0];
				map_control.addClassName('wml-map-control-opened');
				scale_control.addClassName('wml-scale-control-opened');
				permalink.addClassName('wml-permalink-opened');
				copyright.addClassName('wml-copyright-opened');
		};
		MapState.permalinkControl._update();
	},
	
	hidePanel : function(){
		if($('searchButton')){
			$('searchButton').removeClassName('pressed');
		};
		$('sidePanel').addClassName('hidden');
		$('getRoutes').removeClassName('pressed');
		
		var map_control = $('map').adjacent('.wml-map-control')[0];
		var permalink = $('map').adjacent('.wml-permalink')[0];
		var scale_control = $('map').adjacent('.wml-scale-control')[0];
		var copyright = $('map').adjacent('.wml-copyright')[0];

		map_control.removeClassName('wml-map-control-opened');
		scale_control.removeClassName('wml-scale-control-opened');
		permalink.removeClassName('wml-permalink-opened');
		copyright.removeClassName('wml-copyright-opened');
		MapState.permalinkControl._update();
	},
	
	toggleDirections : function(state){
		var _obj = this;
		
		$('directionsSwitcher').innerHTML = '';
		
		if(this.search_results_number){
			var results = this.search_results_number;
		} else {
			var results = 0;
		};
		
		if(state == true){
			if($('searchButton')){
				$('searchButton').removeClassName('pressed');
			}
			$('directionsOptions').addClassName('hidden');
			$('geocodingOutput').addClassName('hidden');
			$('routingControls').removeClassName('hidden');
			$('directionsOptions').removeClassName('hidden');			
			$('getRoutes').addClassName('pressed');
			$('loadingIndicatorGeocoding').addClassName('hidden');
			if(this.routing_inprogress == true){
				$('loadingIndicatorRouting').removeClassName('hidden');
			};
		} else {
			if($('searchButton')){
				$('searchButton').addClassName('pressed');
			};
			
			$('advancedSearchOptions').removeClassName('hidden');
			$('advancedGeocodingPanel').addClassName('geocoding_title_opened');
			$('directionsOptions').removeClassName('hidden');
			$('geocodingOutput').removeClassName('hidden');
			$('routingControls').addClassName('hidden');
			$('directionsOptions').addClassName('hidden');
			$('getRoutes').removeClassName('pressed');
			$('loadingIndicatorRouting').addClassName('hidden');
			if(this.geocoding_inprogress == true){
				$('loadingIndicatorGeocoding').removeClassName('hidden');
			};
		};
		this.showPanel();
		$('mapHolder').addClassName('opened');
		MapState.permalinkControl._update();
	},
	
	addRouteStep : function(){
		
		var inputs_length = this.fieldsManager.getCoordFieldsNum();
		var li_el = this.fieldsManager.addNewLocation(this.fieldsManager.getCoordFieldsNum() + 1).parentNode;
		
		this.refreshIcons();
		this.setLinks();
		return li_el;
		
	},
	
	addWaypoint : function(latlng, _obj){
		if (!_obj.directions || _obj.directions.getNumRoutes() < 24) {
			var step = _obj.addRouteStep();
			_obj.fieldsManager.setCoords(latlng._lat+' '+latlng._lng, _obj.fieldsManager.getCoordFieldsNum() - 1);
			_obj.reloadFields();
		};
	},
	
	addStartPoint : function(latlng, _obj){
		if (_obj.fieldsManager.getCoordFieldsNum() == 0) {
			var step = _obj.addRouteStep();
		};
		_obj.fieldsManager.setCoords(latlng._lat+' '+latlng._lng, 0);
		_obj.reloadFields();
	},
	
	addEndPoint : function(latlng, _obj){
		if(_obj.fieldsManager.getCoordFieldsNum() == 1){
			_obj.addWaypoint(latlng, _obj);
		} else {
			var step = _obj.addRouteStep();
			_obj.addWaypoint(latlng, _obj);
		}
	},
	
	startSearch : function(event){
		if($('geocodingErrorMessage')){
			$('geocodingErrorMessage').remove();
		};
		if(this.pager){
			this.pager.active_page = 1;
			this.pager.bounds_flag = false;
		};
		this.getGeocoding(event);
	},
	
	displayEmptyFieldsError : function(){
		
		if(!$('geocodingErrorMessage')){
			var error_message
			error_message = document.createElement('div');
			error_message.className = 'wml-error-message';
			error_message.id = 'geocodingErrorMessage';
			$('geocodingOutput').insertBefore(error_message, $('advancedGeocodingPanel').next());
			error_message.innerHTML = this.GEOCODING_EMPTY_FIELD_TEXT;
		} else {
			$('geocodingErrorMessage').innerHTML = this.GEOCODING_EMPTY_FIELD_TEXT;
		};
		$('loadingIndicatorGeocoding').addClassName('hidden')
		
		
	},
	
	getPoints : function(){
		
		var points = [];
		
		for(var i=0; i<this.directions.getNumRoutes(); i++){
			var route = this.directions.getRoute(i);
			if(route.getStep(0)){
				if(i==0){
					points.push(route.getStep(0).latlngs[0]);
				};
				points.push(route.getStep(route.getNumSteps()-1).latlngs[route.getStep(route.getNumSteps()-1).latlngs.length - 1]);
			};
		};
		
	},
	
	getRoutes : function(){

		this.clearRoutesInfo();
		
		if(!this.directions){
			this.directions = new CM.Directions(this.map, $('directionsOptions'), this.params.routing_api_key);
			this.map.directions = this.directions;
		};

		if(this.directions.getPolyline == true){
			this.directions.hideRoutes();
		};

		var latlngs = [];
		
		for(var i=0; i<this.fieldsManager.getCoordFieldsNum(); i++){
			if(this.fieldsManager.getCoords(i)){
				var field = this.fieldsManager.getCoordField(i);
				var coords = this.fieldsManager.getCoords(i);
				if(coords && coords.match(/\d+(\.\d+)?/g) && coords.match(/\d+(\.\d+)?/g).length == 2 && field.value != ''){
					var lat = parseFloat(/^.+ /.exec(coords).toString().replace(/\s/, ''));
					var lng = parseFloat(/ .+$/.exec(coords).toString().replace(/\s/, ''));
				};
				var latlng = new CM.LatLng(lat, lng);
				latlngs.push(latlng);
			};
		};
		
		if(latlngs.length > 0){
			$('clearRoute').removeClassName('hidden');
			$('routingText').innerHTML = this.ADD_POINT_INSTRUCTION;
		};
		
		if(latlngs.length > 1){
			this.routing_inprogress = true;
			$('loadingIndicatorRouting').removeClassName('hidden');
		} else {
			this.routing_inprogress = false;
			$('loadingIndicatorRouting').addClassName('hidden');	
		};
		
		if(latlngs.length == 0){
			$('clearRoute').addClassName('hidden');
			$('routingText').innerHTML = this.ADD_FIRST_POINT_INSTRUCTION;
		};
		
		this.directions.loadFromWaypoints(latlngs, {'preserveViewport': true, 'travelMode': this.travel_mode, 'host':'http://routes.'+this.params.routing_server + ':' + this.params.routing_port, 'units':'km', 'draggableWaypoints': true});
		
		for (var i=0; i<this.directions._markers.length; i++) {
			CM.Event.removeListener(this.directions._markers[i], 'dragend',	this.dragendHandler, this);
			CM.Event.addListener(this.directions._markers[i], 'dragend', this.dragendHandler, this);
		};
		
		MapState.permalinkControl._update();
		this.exportDirections();
		
		CM.Event.removeListener(this.directions, 'load', this.routesLoadHandler, this);
		CM.Event.addListener(this.directions, 'load', this.routesLoadHandler, this);
		
	},
	
	routesLoadHandler : function(){
		$('loadingIndicatorRouting').addClassName('hidden');
		this.showWaypointsNames();
		this.getPoints();
		this.routing_inprogress = false;
	},
	
	dragendHandler : function(){
		for (var i=0; i<this.directions._markers.length; i++) {
			CM.Event.removeListener(this.directions._markers[i], 'dragend',	this.dragendHandler, this);
			CM.Event.addListener(this.directions._markers[i], 'dragend', this.dragendHandler, this);
		};
		if(this.fieldsManager.hasSearchSelect(i)){
			this.fieldsManager.destroySearchSelect(i);
		};
		MapState.permalinkControl._update();
		this.exportDirections();
		this.refreshFields();
		this.reloadFields();
		this.refreshIcons();
	},
	
	clearVectorOverlays : function(){
		if(this.overlays){
			for(var i=0; i<this.overlays.length; i++){
				if(this.overlays[i]){
					this.map.removeOverlay(this.overlays[i]);
				};
			};
			this.overlays  = [];
		};
	},
	
	clearRoutesInfo : function(){
		if(this.directions){
			this.directions.panel.innerHTML = '';
		};
	},
	
	getGeocoding : function(query){
		var _obj = this;
		var list_elements = $('geocodingOutput').adjacent('li');
		this.query = query;
		this.geocoding_inprogress = true;
		this.clearVectorOverlays();

		if(!this.geocoder){
			this.geocoder = new CM.Geocoder(this.params.geocoding_api_key);
			this.map.geocoder = this.geocoder;
		};
		
		$('loadingIndicatorGeocoding').removeClassName('hidden')
		$('searchResultText').addClassName('hidden');
		$('clearSearch').addClassName('hidden');
		
		if(!this.pager || this.pager.bounds_flag == false){
			this.bounds = this.map.getBounds();
			if(this.pager_params && this.pager_params.search_bbox){
				this.search_bounds = this.pager_params.search_bbox;
				var points = [];
				for(var i=0; i<this.pager_params.search_bbox.split(',').length; i++){
					points.push(this.pager_params.search_bbox.split(',')[i].split('+'));
				};
				this.bounds._ne = new CM.LatLng(points[0][0], points[0][1]);
				this.bounds._sw = new CM.LatLng(points[1][0], points[1][1]);
			};
		} else {
			this.bounds = this.pager.bounds;
		};
		
		var boundsOnly = false;
		var detailedDescription = true;

		if(this.permalink_params != null && this.permalink_params.geocoding){
			this.query = this.permalink_params.geocoding || '';
		};

		this.query = this.query.replace(/^\s|\s$/g, '').replace(/\s/g, '+').replace(/;\+$/, '');
		
		if(this.map.getZoom() < 10){
			boundsOnly = true;
			this.bounds = null;
		} else {
			boundsOnly = false;
		};
		
		if(this.bbox_flag == true){
			boundsOnly = false;
		};
		
		$('geocodingOutput').adjacent('li.no_response').each(function(item){
			item.remove();
		});
		$('geocodingOutput').adjacent('li.geocoding_location').each(function(item){
			item.remove();
		});
		
		var start_page = 0;
		
		if(_obj.pager_params && _obj.pager_params.active_page){
			start_page = _obj.pager_params.active_page;
		};

		this.active_page = (!_obj.pager ? start_page : _obj.pager.getActivePage() - 1);

		var params_array = this.query.split(';+').reverse();
		var query_string = '';
		
		for(var i=0; i<params_array.length; i++){
			query_string += params_array[i].split(':')[1].replace(/\+/g, ' ');
			if(i!=(params_array.length-1)){
				query_string += ', ';
			};
		};
		$('lookinProcess').removeClassName('hidden');
		$('geocodingLookingRequestText').innerHTML = decodeURI(query_string);
		$('geocodingPager').addClassName('hidden');
		if(this.map._infoWindow && !this.map._infoWindow.isClosed()){
			this.map.closeInfoWindow();
		}
		
		this.map.geocoder.search_bbox = this.bounds;
		this.map.geocoder.query = this.query;

		this.geocoder.getLocations(this.query, function(response) {
			$('clearSearch').removeClassName('hidden');
			if(_obj.temp_markers){
				_obj.changeTempMarkersState();
			};
			if(response.features){
				if(!_obj.pager){
					_obj.pager = new CM.CustomPager('geocodingPager', function(){
						_obj.getGeocoding(_obj.query);
					});
				};
				_obj.pager.addPager(response.found, _obj.bounds, _obj.active_page + 1);
				var response_bounds;
				if(response.found < 10){
					response_bounds = response.found + ' of ';
				} else if((response.found - ((_obj.pager.getActivePage()-1)*10 + 1)) < 10){
					response_bounds = ((_obj.pager.getActivePage()-1)*10 + 1) + ' - ' + response.found + ' of ';
				} else {
					response_bounds = ((_obj.pager.getActivePage()-1)*10 + 1) + ' - ' + ((_obj.pager.getActivePage()-1)+1)*10 + ' of ';
				};
				$('geocodingPager').removeClassName('hidden');
				$('lookinProcess').addClassName('hidden');
				$('geocodingPagesList').innerHTML = response_bounds;
				$('geocodingResultsNumber').innerHTML = response.found  = (response.found < 10 ? '' : response.found + ' for ');
				$('geocodingRequestText').innerHTML = decodeURI(query_string);
				$('geocodingAdvancedSearchPanel').removeClassName('hidden');
				var sw = new CM.LatLng(response.bounds[0][0], response.bounds[0][1]);
				var ne = new CM.LatLng(response.bounds[1][0], response.bounds[1][1]);
				_obj.map.zoomToBounds(new CM.LatLngBounds(sw, ne));
				for (var i = 0; i < response.features.length; i++) {
					var point = new CM.LatLng(response.features[i].centroid.coordinates[0], response.features[i].centroid.coordinates[1]);
					var title = response.features[i].properties.name;
					if (response.features[i].name) {
						title += ' (' + response.features[i].name + ')';
					};
					_obj.setTempMarker(point, i);
					_obj.displayGeocodeResult(response.features[i], i);
				};
				_obj.search_results_number = response.features.length;
				_obj.geocoding_inprogress = false;
				$('clearSearch').removeClassName('hidden');
			} else {
				$('lookinProcess').addClassName('hidden');
				_obj.search_results_number = 0;
				var no_response_li = document.createElement('li');
				no_response_li.className = 'no_response'
				var no_response_text_holder = document.createElement('p');
				var no_response_text = document.createTextNode(_obj.NO_RESPONSE_TEXT);
				var question_sign = document.createTextNode('?');
				var no_response_link = document.createElement('a');
				no_response_link.href = _obj.NO_RESPONSE_LINK;
				no_response_link.innerHTML = _obj.NO_RESPONSE_LINK_TEXT;
				no_response_text_holder.appendChild(no_response_text);
				no_response_text_holder.appendChild(no_response_link);
				no_response_text_holder.appendChild(question_sign);
				no_response_li.appendChild(no_response_text_holder);
				$('geocodingOutput').insertBefore(no_response_li, document.getElementById('geocodingPager'));
				_obj.geocoding_inprogress = false;
				$('loadingIndicatorGeocoding').addClassName('hidden');
			};
			
		}, {
			host: 'http://geocoding.' + _obj.params.geocoding_server + ':'+ _obj.params.geocoding_port, 
			bounds: _obj.bounds, 
			boundsOnly: boundsOnly, 
			detailedDescription: true, 
			type: 'find_structured', 
			activePage: this.active_page,
			geometry: true
		});
		this.exportGeocoding(this.query);
		this.permalink_params = null;
		MapState.permalinkControl._update();
	},
	
	getWaypointsNames : function(){
		
		for(var i=0; i<this.directions.getNumRoutes(); i++){
			if(i==0){
				var points_names = [];
				points_names.push(this.directions.getRoute(i).getStartPoint());
			};
			points_names.push(this.directions.getRoute(i).getEndPoint());
		};
		
		return points_names;
		
	},
	
	getAdvancedSearch : function(){
		
		var request = '';
		this.bbox_flag = false;
		$('geocodingOutput').adjacent('li.wml-error-message').each(function(item){
			item.remove();
		});
		var error = false;
		if($('poiType').value != ''){
			request += 'poi:' + $('poiType').value + ';+';
		};
		if($('houseNumber').value != ''){
			request += 'house:' + $('houseNumber').value + ';+';
		};
		if($('streetName').value != '' && $('streetName').value != this.STREET_INPUT_ERROR_MESSAGE){
			if($('streetName').value.length > 2){
				$('streetName').removeClassName('error');
				request += 'street:' + $('streetName').value + ';+';
			} else {
				error = true;
				$('streetName').addClassName('error');
				$('streetName').value = this.STREET_INPUT_ERROR_MESSAGE;
				$('streetName').blur();
			}
		};
		if($('cityTownName').value != ''){
			request += 'city:' + $('cityTownName').value + ';+';
		};
		if($('stateName').value != ''){
			request += 'county:' + $('stateName').value + ';+';
			this.bbox_flag = true;
		};
		if($('countryName').value != '' && $('countryName').value != this.COUNTRY_INPUT_ERROR_MESSAGE){
			if($('countryName').value.length > 1){
				$('countryName').removeClassName('error');
				request += 'country:' + $('countryName').value + ';+';
				this.bbox_flag = true;
			} else {
				error = true;
				$('countryName').addClassName('error');
				$('countryName').value = this.COUNTRY_INPUT_ERROR_MESSAGE;
				$('countryName').blur();
			}
		};
		if($('streetName').value == this.STREET_INPUT_ERROR_MESSAGE || $('countryName').value == this.COUNTRY_INPUT_ERROR_MESSAGE){
			error = true;
		}
		if(request != '' && error == false){
			if(this.pager){
				this.pager.active_page = 1;
				this.pager.bounds_flag = false;
			};
			if($('geocodingErrorMessage')){
				$('geocodingErrorMessage').remove();
			};
			this.getGeocoding(request);
		};
		if(request == ''){
			this.displayEmptyFieldsError();
		}
	},
	
	showWaypointsNames : function(){
		var waypoints = this.getWaypointsNames();
		if(typeof waypoints != 'undefined'){
			for(var i=0; i<waypoints.length; i++){
				if(waypoints[i] != ''){
					this.fieldsManager.setDescr(waypoints[i], i);
					this.fieldsManager.showDescr(i);
				};
			};
		};
		this.fieldsManager.resetCoordFields();
	},
	
	exportDirections : function(){
		var latlngs = '';
		var firstBraceOpened = false,
			lastBraceOpened = false;
		var coordsArr = [];
		for(var i=0, len = this.fieldsManager.getCoordsNum(); i<len; i++){
			var coords = this.fieldsManager.getCoords(i);
			if(coords){
				coordsArr.push(coords);
			};
		};
		for(i = 0, len = coordsArr.length; i<len; i++){
			if ((i == 1) && (i < coordsArr.length-1)) {
				latlngs += '[';
			}
			var lat = parseFloat(/^.+ /.exec(coordsArr[i]).toString().replace(/\s/, ''));
			var lng = parseFloat(/ .+$/.exec(coordsArr[i]).toString().replace(/\s/, ''));
			latlngs += lat+','+lng;
			if ((i == coordsArr.length - 2) && (i > 0)) {
				latlngs += ']';
			}
			if(i!=this.filled_fields.length-1){
				latlngs += ','
			}
		};
		if (latlngs != ''){
			var gpx_url = this.directions._options.host + '/' + this.directions.key + '/api/0.3/'+latlngs+ '/' +this.directions._options.travelMode+'.gpx'+'?units=' +this.directions._options.units+'&download=true';
			var json_url = this.directions._options.host + '/' + this.directions.key + '/api/0.3/'+latlngs+ '/' +this.directions._options.travelMode+'.js'+'?units=' +this.directions._options.units+'&download=true';
			$('exportRoutingGPX').href = gpx_url;
			$('exportRoutingJSON').href = json_url;
			
			$('routeExportLinks').removeClassName('hidden');
			$('noRoutingMessage').addClassName('hidden');
		} else {
			$('routeExportLinks').addClassName('hidden');
			$('noRoutingMessage').removeClassName('hidden');
		}
		
	},
	
	exportGeocoding : function(query){

		var tale = '';
		
		if (this.geocoder && this.geocoder._options) {
			if (this.geocoder._options.bounds) {
				tale = '&bbox_only=' + this.geocoder._options.boundsOnly;
			};
			
			tale += '&active_page=' + this.geocoder._options.activePage;
			tale += '&results_number=' + this.geocoder._options.resultsNumber;
			
			if (this.geocoder.search_bbox) {
				var search_sw = this.geocoder.search_bbox.getSouthWest(), search_ne = this.geocoder.search_bbox.getNorthEast();
				tale += '&bbox=' + search_sw.lat() + '+' + search_sw.lng() + ',' + search_ne.lat() + '+' + search_ne.lng();
			};
			
			var html_url = this.geocoder._options.host + '/' + this.geocoder.key + '/geocoding/find_structured/' + query + '.html' + '?return_location=' + this.geocoder._options.detailedDescription + tale;
			var json_url = this.geocoder._options.host + '/' + this.geocoder.key + '/geocoding/find_structured/' + query + '.js' + '?return_location=' + this.geocoder._options.detailedDescription + tale;
			$('exportGeocodingHTML').href = html_url;
			$('exportGeocodingJSON').href = json_url;
			
			$('geocodingExportLinks').removeClassName('hidden');
			$('noGeocodingMessage').addClassName('hidden');
		}
		
	},
	
	setTempMarker : function(latlng, i){
		
		if(!this.temp_markers){
			this.temp_markers = [];
		};
		
		var iconTemplate = new CM.Icon();
			iconTemplate.iconSize = new CM.Size(18, 18);
			iconTemplate.iconAnchor = new CM.Point(9, 9);
			
		var icon = new CM.Icon(iconTemplate, '/images/img/icons/temp_icons/temp_icon_' + (i + 1) +'.png');
		var marker = new CM.Marker(latlng, {'draggable': false, 'clickable':false, 'icon':icon});
		
		this.temp_markers.push({'marker':marker, 'selected':false});
		this.map.addOverlay(marker);
		
	},
	
	getTempMarker : function(i){
		
		return this.temp_markers[i];
		
	},
	
	changeTempMarkersState : function(hide){
		if(this.temp_markers){
			if(hide == true){
				for(var i=0; i<this.temp_markers.length; i++){
					this.temp_markers[i].marker.hide();
				}
			}else if(hide == false){
				for(var i=0; i<this.temp_markers.length; i++){
					if(this.temp_markers[i].selected == false){
						this.temp_markers[i].marker.show();
					}
				}
			} else {
				for(var i=0; i<this.temp_markers.length; i++){
					this.map.removeOverlay(this.temp_markers[i].marker);
				}
				this.temp_markers = [];
			}
		}
	},
	
	displayGeocodeResult : function(feature, index){
		var _obj = this;
		var index = index;
		var bounds_array = [];	
		var polyline_array = [];	
		var geocode_output_node = $('geocodingOutput');
		
		var latlng = new CM.LatLng(feature.centroid.coordinates[0], feature.centroid.coordinates[1]);

		var fields_number = this.fieldsManager.getCoordFieldsNum();
		
		$('loadingIndicatorGeocoding').addClassName('hidden');
		
		if(fields_number < 2){
			fields_number = 2;
		}
		
		var li_el = document.createElement('li');
			li_el.className = 'geocoding_location';
			
		$(feature.bounds).each(function(item){
			var x = parseFloat(/^.+,/.exec(item).toString().replace(/,/, ''));
			var y = parseFloat(/,.+$/.exec(item).toString().replace(/,/, ''));
			var bound_point = new CM.LatLng(x, y);
			bounds_array.push(bound_point);
		});
		
		var result_link = document.createElement('a');
			result_link.href='#';
			result_link.className = 'result_link';

		li_el.appendChild(result_link);

		var location_array = [];
		var location_description = '';
		
		if(feature && feature.location){
			
			if(feature.location.country){
				location_array.push(feature.location.country);
			}
			if(feature.location.county){
				location_array.push(feature.location.county);
			}
			if(feature.location.city){
				location_array.push(feature.location.city);
			}
			if(feature.location.postcode){
				location_array.push(feature.location.postcode);
			}
			if(feature.location.road){
				location_array.push(feature.location.road);
			}
			if(feature.location.house){
				location_array.push(feature.location.house);
			}
		}
		
		for(var i=0; i<location_array.length; i++){
			location_description += location_array[i];
			if(i != location_array.length-1){
				location_description += ', ';
			};
		};

		var prepareCoordsArray = function(coordinates) {
			var coordArray = new Array();
			for (var i=0; i<coordinates.length; i++) {
				coordArray.push(new CM.LatLng(coordinates[i][0], coordinates[i][1]));
			};
			return coordArray;
		};
		 
		var createPolyline = function(coordinates) {
			return new CM.Polyline(prepareCoordsArray(coordinates), '#5143eb', 3, .8);
		};
		
		var createMultiPolyline = function(coordinates) {
			var overlays = new Array();
			for (var i=0; i<coordinates.length; i++) {
				overlays.push(createPolyline(coordinates[i]));
			};
			return overlays;
		};
		
		var createPolygon = function(coordinates) {
			return new CM.Polygon(prepareCoordsArray(coordinates[0]), '#565a4d', 1, .8, '#5143eb');
		};
		
		var createMultiPolygon = function(coordinates) {
			var overlays = new Array();
			for (var i=0; i<coordinates.length; i++) {
				overlays.push(createPolygon(coordinates[i]));
			};
			return overlays;
		};
		
		var locationHandler = function(e){
			
			_obj.clearVectorOverlays();
			
			if(!_obj.overlays){
				_obj.overlays = [];
			};
			
			_obj.overlays = [];
			
			var coordinates = feature.geometry.coordinates;

			switch (feature.geometry.type) {
				
				case 'LINESTRING':
					
					_obj.overlays[0] = createPolyline(coordinates);
					
				break;
				
				case 'POLYGON':
				
					_obj.overlays[0] = createPolygon(coordinates);
					
				break;
				
				case 'MULTILINESTRING':
				
					_obj.overlays = createMultiPolyline(coordinates);
					
				break;
				
				case 'MULTIPOLYGON':
	
					_obj.overlays = createMultiPolygon(coordinates);
	
				break;
	
			};
			
			_obj.map.zoomToBounds(new CM.LatLngBounds(bounds_array));
			_obj.map.openInfoWindow(latlng, '<b>' + (feature.properties.name ? feature.properties.name : feature.location.road) + '</b>' + '<p>' + location_description + '</p>', {noCloseOnClick: true});

			if(_obj.overlays){
				for (var i = 0; i < _obj.overlays.length; i++) {
					_obj.map.addOverlay(_obj.overlays[i]);
				};
			};

			CM.DomEvent.addListener($(_obj.map._infoWindow._container).adjacent('a.wml-info-window-close')[0], 'click', _obj.clearVectorOverlays, _obj);
		};
		
		CM.DomEvent.addListener(result_link, 'click', locationHandler);
		CM.DomEvent.addListener(this.getTempMarker(index).marker._image, 'click', locationHandler);
		CM.Event.addListener(this.map, 'zoomend', function(){
			if(_obj.map._infoWindow){
				_obj.map._infoWindow._updatePosition();
			};
		});
		
		var icon = document.createElement('span');
			icon.className = 'number_icon';
			icon.innerHTML = index+1;
		var header = document.createElement('strong');
			header.innerHTML = feature.properties.name;
		var detailed_info = document.createElement('div');
			detailed_info.className = 'description';
		var description = location_description.toString();
			detailed_info.innerHTML = (description == '' || description == ' ') ? '&nbsp;' : description;
		var links_holder = document.createElement('div');
			links_holder.className = 'links';
		var from_icon = document.createElement('img');
			from_icon.src = CM.Util.getRootUrl() + 'images/routing/small/route_icon_1.png';
			from_icon.alt = 'Start';
			from_icon.width = '13';
			from_icon.height = '15';
		var to_icon = document.createElement('img');
			to_icon.src = CM.Util.getRootUrl() + 'images/routing/small/route_icon_'+ fields_number +'.png';
			to_icon.alt = 'End';
			to_icon.width = '13';
			to_icon.height = '15';
		var link_from = document.createElement('a');
			link_from.href = '#';
			link_from.innerHTML = 'From';
		var link_to = document.createElement('a');
			link_to.href = '#';
			link_to.innerHTML = 'Direction To';
			result_link.appendChild(icon);
			result_link.appendChild(header);
			result_link.appendChild(detailed_info);
			li_el.appendChild(links_holder);
			links_holder.appendChild(to_icon);
			links_holder.appendChild(link_to);
			links_holder.appendChild(from_icon);
			links_holder.appendChild(link_from);
		
		geocode_output_node.insertBefore(li_el, document.getElementById('geocodingPager'));
		
		CM.DomEvent.addListener(link_from, 'click', function(){
			this.geocode_point_added = true;
			this.addStartPoint(latlng, this);
			this.map.setCenter(latlng, this.map.getZoom());
		}, this);
		
		CM.DomEvent.addListener(link_to, 'click', function(){
			this.geocode_point_added = true;
			this.addEndPoint(latlng, this);
			this.map.setCenter(latlng, this.map.getZoom());
		}, this);
		
	},
	
	setLinks : function(){
		
		var _obj = this;
		var icons = $('directionsList').adjacent('img');
		var close_links = $('directionsList').adjacent('a.close_waypoint');
		var replace_links = $('directionsList').adjacent('a.replace_points');
		
		var refreshReplaceLinks = function(){
			var replace_links = $('directionsList').adjacent('a.replace_points');
			for(var i=0; i<replace_links.length; i++){
				if(i==0){
					replace_links[i].addClassName('hidden');
				} else {
					replace_links[i].removeClassName('hidden');
				};
			};
		};
		refreshReplaceLinks();

		for(var i=0; i<replace_links.length; i++){
			(function(){
				var index = i;
				replace_links[index].onclick = function(){
					for(var j=0; j<_obj.fieldsManager.getCoordFieldsNum(); j++){
						if(_obj.fieldsManager.hasSearchSelect(j)){
							_obj.fieldsManager.destroySearchSelect(j);
							if((_obj.fieldsManager.getCoords(j) && !(_obj.fieldsManager.getCoords(j).match(/\d+(\.\d+)?/g) && _obj.fieldsManager.getCoords(j).match(/\d+(\.\d+)?/g).length == 2) || !_obj.fieldsManager.getCoords(j))){
								_obj.fieldsManager.getCoordField(j).value = '';
							};
						};
					};
					replace_links.each(function(item){
						item.addClassName('hidden');
					});
					var current_node = _obj.fieldsManager.getCoordField(index);
					var current_value = _obj.fieldsManager.getCoords(index);
					var previous_node = _obj.fieldsManager.getCoordField(index-1);
					var previous_node_holder = previous_node.parentNode;
					var previous_value = _obj.fieldsManager.getCoords(index-1);
						current_node.parentNode.insertBefore(previous_node, current_node);
						previous_node_holder.insertBefore(current_node, previous_node_holder.getElementsByTagName('a')[0]);
						refreshReplaceLinks();
						_obj.fieldsManager.setCoords(current_value, index-1);
						_obj.fieldsManager.setCoords(previous_value, index);
						_obj.reloadFields();
						
				};
			})();
		};

		for(var i=0; i<icons.length; i++){
			(function(){
				var index = i;
				
				var centerPoint = function(){
					if(_obj.directions && _obj.directions._markers && _obj.directions._markers[index]){
						var current_position = _obj.map.fromLatLngToDivPixel(_obj.directions._markers[index].getLatLng());
						current_position.x += $('sidePanel').offsetWidth/2;
						_obj.map.setCenter(_obj.map.fromDivPixelToLatLng(current_position), _obj.map.getZoom());
					};
				};

				icons[index].onclick = null;
				icons[index].onclick = function(){
					centerPoint();
				};
				
			})();
		};

		for(var i=0; i<close_links.length; i++){
			(function(){
				var index = i;
				var destroyWaypoint = function(){
					_obj.destroyWaypoint(index, close_links[index].up());
					_obj.reloadFields();
				};
				
				close_links[index].onclick = null;
				close_links[index].onclick = function(){
					destroyWaypoint();
				};
			})();
		};
		
		if(!this.search_geocoder){
			this.search_geocoder = new CM.Geocoder(this.params.geocoding_api_key);
			this.map.search_geocoder = this.search_geocoder;
		};
		
		for(var i=0; i<this.fieldsManager.getCoordFieldsNum(); i++){
			(function(){
				var index = i;
				
				_obj.fieldsManager.getCoordField(index).onfocus = function(){
					if(_obj.fieldsManager.getCoordField(index).value == _obj.ADD_POINT_INSTRUCTION){
						_obj.fieldsManager.getCoordField(index).value =  '';
						_obj.fieldsManager.getCoordField(index).removeClassName('grey');
					};
				};
				
				_obj.fieldsManager.getCoordField(index).onblur = function(){
					if(_obj.fieldsManager.getCoordField(index).value == ''){
						_obj.fieldsManager.getCoordField(index).value =  _obj.ADD_POINT_INSTRUCTION;
						_obj.fieldsManager.getCoordField(index).addClassName('grey');
					};
				};
				
				_obj.fieldsManager.getCoordField(index).onkeydown = function(){
					_obj.temp_field_value = _obj.fieldsManager.getCoordField(index).value;
				};
				
				_obj.fieldsManager.getCoordField(index).onkeypress = function(event){
					var event = event || window.event;
					if((_obj.fieldsManager.getCoordField(index).value.match(/\d+(\.\d+)?/g) && _obj.fieldsManager.getCoordField(index).value.match(/\d+(\.\d+)?/g).length == 2) && _obj.fieldsManager.getCoordField(index).value != ''){
						if (event.keyCode == 13) {
							_obj.reloadFields();
						};
					} else {
						_obj.fieldsManager.getCoordField(index).value = _obj.temp_field_value;
						_obj.temp_field_value = null;
						return false;
					};
				};
				
			})();
		};
		
	},
	
	destroyWaypoint : function(index, element){
		
		this.fieldsManager.removePoint(index);
		element.parentNode.removeChild(element);

	},
	
	refreshIcons : function(){
		
		var control_icons = $('directionsList').adjacent('img');
		for(var i=0; i<control_icons.length; i++){
			var index = i+1;
			control_icons[i].src = CM.Util.getRootUrl() + 'images/routing/route_icon_'+index+'.png';
		};
		
		if(this.directions && this.directions._markers && this.directions._markers.length == 1){
			if(this.fieldsManager.getCoordField(0).innerHTML == '' || this.fieldsManager.getCoordField(0).innerHTML == this.ADD_POINT_INSTRUCTION){
				var index = 2;
			} else {
				var index = 1;
			};
			var url = '/images/routing/route_icon_' + index + '.png';
			if(this.directions._markers[0]._image.src){
				this.directions._markers[0]._image.src = url;
			} else {
				this.directions._markers[0]._image.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + 
					url + '", sizingMethod="scale")';
			};
		};
		
	},
	
	reloadFields : function(){
		this.filled_fields = [];
		this.fields_to_remove =[];
		this.fieldsManager.resetCoordFields();
		for(var i=0; i<this.fieldsManager.getCoordFieldsNum(); i++){
			var field = this.fieldsManager.getCoordField(i);
			if(this.fieldsManager.getCoords(i)){
				var coords = this.fieldsManager.getCoords(i);
			};
			if ((field.innerHTML.match(/\d+(\.\d+)?/g) && field.innerHTML.match(/\d+(\.\d+)?/g).length == 2) || (coords && coords.match(/\d+(\.\d+)?/g) && coords.match(/\d+(\.\d+)?/g).length == 2 && field.innerHTML != '' && field.innerHTML != this.ADD_POINT_INSTRUCTION)) {
				this.fieldsManager.getCoordField(i).up().removeClassName('hidden');
				this.filled_fields.push({'field':field, 'index':i});
				field.removeClassName('grey');
			} else {
				this.fields_to_remove.push({'field':field, 'index':i});
			};
		};

		if (this.filled_fields.length == 1 && this.fieldsManager.getCoordFieldsNum() == 2 && !this.fieldsManager.getCoords(1)){
			filled_index = 0;
		} else {
			filled_index = this.filled_fields.length;
		};
		for(var i=filled_index; i<this.fields_to_remove.length; i++){
			this.destroyWaypoint(this.fields_to_remove[i].index, this.fields_to_remove[i].field.parentNode);
		};
		
		this.field_from = this.fieldsManager.getCoordField(0);
		this.getRoutes();
		this.setLinks();
		this.map.closeInfoWindow();
		this.refreshIcons();
		
	},
	
	refreshFields : function(){
		if(this.directions && this.directions._markers){
			for(var i=0; i<this.directions._markers.length; i++){
				if((this.fieldsManager.getCoordField(0).innerHTML == '' || this.fieldsManager.getCoordField(0).innerHTML == this.ADD_POINT_INSTRUCTION) && this.fieldsManager.getCoordFieldsNum() == 2){
					var index = i+1;
				} else {
					var index = i;
				};
				this.fieldsManager.setCoords(this.directions._markers[i].getLatLng()._lat + ' ' + this.directions._markers[i].getLatLng()._lng, index);
			};
		};
	},
	
	parseUrl : function(){
		var opened_tab;
		var params = {};
		var url = window.location.href.replace(/^.+\?/, '').replace('#', '');
		var elements_array = url.split('&');
		var allow_geocoding_request = false;
		var allow_directions_request = false;
		
		for(var i=0; i<elements_array.length; i++){
			var couple = elements_array[i].split('=');
			params[couple[0]] = couple[1];
		};

		for(var i in params){
			if(i == 'geocoding' && $('searchButton')){
				allow_geocoding_request = true;
			};
			if(i == 'directions'){
				allow_directions_request = true;
			};
			if(i == 'opened_tab'){
				opened_tab = params[i];
			};
		};
		
		if(allow_geocoding_request == true && $('searchButton')){
			this.permalink_params = params;
			var params_array = this.permalink_params.geocoding.split(';+').reverse();
			var params_hash = {}
			for(var i=0; i<params_array.length; i++){
				params_hash[params_array[i].split(':')[0]] = params_array[i].split(':')[1];
			};
			if(params_hash.country){
				$('countryName').value = decodeURI(params_hash.country).replace(/\+/g, ' ');
			};
			if(params_hash.county){
				$('stateName').value = decodeURI(params_hash.county).replace(/\+/g, ' ');
			};
			if(params_hash.city){
				$('cityTownName').value = decodeURI(params_hash.city).replace(/\+/g, ' ');
			};
			if(params_hash.street){
				$('streetName').value = decodeURI(params_hash.street).replace(/\+/g, ' ');
			};
			if(params_hash.poi){
				$('poiType').value = decodeURI(params_hash.poi).replace(/\+/g, ' ');
			};
			if(params_hash.house){
				$('houseNumber').value = decodeURI(params_hash.house).replace(/\+/g, ' ');
			};
			if(!this.pager_params){
				this.pager_params = {};
			};
			this.pager_params.active_page = parseInt(params.active_page);
			this.pager_params.results_number = parseInt(params.results_number);
			this.pager_params.search_bbox = params.search_bbox;
			this.getGeocoding();
		};
		
		if(allow_directions_request == true){
			var points_array = [];
			this.permalink_params = params;
			var directions = this.permalink_params.directions.split(',');
			for(var i=0; i<directions.length; i++){
				if(i%2){
					points_array.push([directions[i-1], directions[i]]);
				}
			};
			
			$$('#transportSwitcher a').each(function(link) {
				link.removeClassName('pref');
			});
			
			switch (this.permalink_params.travel) {
				
				case 'car':
					$('drivingButton').addClassName('pref');
					$('preferenceSelect').selectedIndex = 0;
					$('preferenceSelect').disabled = '';
					this.travel_mode = CM.DRIVING;
				break;
				
				case 'car/shortest':
					$('drivingButton').addClassName('pref');
					$('preferenceSelect').selectedIndex = 1;
					$('preferenceSelect').disabled = '';
					this.travel_mode = CM.DRIVING + '/shortest';
				break;
				
				case 'foot':
					$('walkingButton').addClassName('pref');
					$('preferenceSelect').selectedIndex = 0;
					$('preferenceSelect').disabled = 'disabled';
					this.travel_mode = CM.WALKING;
				break;
				
				case 'bicycle':
					$('cyclingButton').addClassName('pref');
					$('preferenceSelect').selectedIndex = 0;
					$('preferenceSelect').disabled = 'disabled';
					this.travel_mode = CM.CYCLING;
				break;
			
			};

			this.permalink_center = this.map.getCenter();
			
			for(var i=0; i<points_array.length; i++){
				if(i==0){
					this.addStartPoint(new CM.LatLng(points_array[i][0], points_array[i][1]), this);
				} else if (i==1){
					this.addEndPoint(new CM.LatLng(points_array[i][0], points_array[i][1]), this);
				} else {
					this.addWaypoint(new CM.LatLng(points_array[i][0], points_array[i][1]), this);
				};
			};

		};
		if (opened_tab == 1){
			this.toggleDirections(true)
		} else if (opened_tab == 2) {
			this.toggleDirections(false)
		} else {
			this.hidePanel();
		}

	}

};

CM.ContextMenu = function(params){
	
	this.params = params;
	this.menu_structure = {
		'links':[
			{'link':'#', 'params':{'id':'directionsFrom', 'className':''}, 'text':'Directions from here', 'action':this.params.obj.addStartPoint},
			{'link':'#', 'params':{'id':'directionsTo', 'className':''}, 'text':'Directions to here', 'action':this.params.obj.addEndPoint},
			{'link':'#', 'params':{'id':'addDestinationPoint', 'className':'hidden'}, 'text':'Add Destination', 'action':this.params.obj.addWaypoint}
		]
	};
	this.createMarkup();
};

CM.ContextMenu.prototype = {
	
	createMarkup : function(){
		
		var _obj = this;
		
		this.context_menu_bg = document.createElement('div');
		this.context_menu_bg.id = 'contextMenu';
		this.context_menu = document.createElement('ul');
		this.context_menu_bg.appendChild(this.context_menu);
		
		for (var i=0; i<this.menu_structure.links.length; i++){
			(function(){
				
				var index = i;
				var li_el = document.createElement('li');
				var link = document.createElement('a');
				
				link.href = _obj.menu_structure.links[index].link;
				link.innerHTML = _obj.menu_structure.links[index].text;
				
				CM.DomEvent.addListener(link, 'mousemove', function(){
					$(link).addClassName('hover');
				});
				CM.DomEvent.addListener(link, 'mouseout', function(){
					$(link).removeClassName('hover');
				});
				CM.DomEvent.addListener(link, 'click', function(){
					_obj.menu_structure.links[index].action(_obj.latlng, _obj.params.obj);
					_obj.hide();
					_obj.params.obj.toggleDirections(true);
				}, _obj);
				
				li_el.appendChild(link);
				
				for(var j in _obj.menu_structure.links[index].params){
					link.parentNode[j] = _obj.menu_structure.links[index].params[j];
				};
				
				_obj.context_menu.appendChild(li_el);
			})();
		}

		this.params.obj.map.getContainer().appendChild(this.context_menu_bg);
		
	},
	
	show : function(e){

		this.latlng = this.params.obj.map.fromContainerPixelToLatLng(
	    	new CM.Point(this.params.obj.map._mousePos.x, this.params.obj.map._mousePos.y)
		);
		$(this.context_menu_bg).setStyle({'left':this.params.obj.map._mousePos.x+'px', 'top':this.params.obj.map._mousePos.y+'px'})
		$(this.context_menu_bg).removeClassName('hidden');
		
		CM.DomEvent.addListener(this.params.obj.map.getContainer(), 'click', this.hide, this);
		CM.DomEvent.addListener($('sidePanel'), 'mouseover', this.hide, this);
		CM.DomEvent.addListener($('searchPanel'), 'mouseover', this.hide, this);
		
		if(this.params.obj.fieldsManager.getCoordFieldsNum() == 0){
			$('directionsFrom').removeClassName('hidden');
			$('directionsTo').removeClassName('hidden');
			$('addDestinationPoint').addClassName('hidden');
		} else if(this.params.obj.fieldsManager.getCoordFieldsNum() == 1){
			$('directionsTo').removeClassName('hidden');
			$('directionsFrom').addClassName('hidden');
			$('addDestinationPoint').addClassName('hidden');
		} else if((this.params.obj.fieldsManager.getCoordFieldsNum() == 2) && !this.params.obj.fieldsManager.getCoords(0)){
			$('directionsTo').addClassName('hidden');
			$('directionsFrom').removeClassName('hidden');
			$('addDestinationPoint').addClassName('hidden');
		} else {
			$('directionsFrom').addClassName('hidden');
			$('directionsTo').addClassName('hidden');
			$('addDestinationPoint').removeClassName('hidden');
		};

	},
	
	hide : function(){
		
		CM.DomEvent.removeListener(this.params.obj.map.getContainer(), 'click', this.hide, this);
		this.latlng = null;
		$(this.context_menu_bg).addClassName('hidden');
		
	}
	
};

CM.CustomPager = function(target, action){
	this.PAGES_PER_PAGE = 10;
	this.target = target;
	this.active_page = 1;
	this.target_node = document.getElementById(this.target);
	this.action = action;
	this.pages_list = [];
	this.bounds_flag = false;
};

CM.CustomPager.prototype = {
	addPager : function(number, bounds, active_page){
		if(this.bounds_flag == false){
			this.bounds = bounds;
			this.bounds_flag = true;
		};
		if(active_page){
			this.active_page = active_page;
		};
		this.items_number = number;
		this.pages_number = this.getPagesNum();
		this.target_node.appendChild(this.getPager());
	},
	getPager : function(){
		this.target_node.innerHTML = '';
		
		var pager_body = document.createElement('ul');
			pager_body.id = 'customPager';
		
		if(this.getActivePage() != 1){
			var prev_button = document.createElement('li');
				prev_button.className = 'prev';
			this.prev_button_link = document.createElement('a');
			this.prev_button_link.innerHTML = 'Previous';
			this.prev_button_link.href = '#';
				prev_button.appendChild(this.prev_button_link);
				pager_body.appendChild(prev_button);
		};
		if(this.pages_number > 1){
			var num = this.getPagesNum();
			var start_page = 1;
				if((this.getPagesNum() - this.getActivePage())<2 || this.getPagesNum()<5){
					num = this.getPagesNum();
				}else if(this.getActivePage()<3 && this.getPagesNum()>=5){
					num = this.getActivePage() + (5-this.getActivePage());
				}else{
					num = parseInt(this.getActivePage())+2;
				};
				start_page = parseInt((this.getActivePage() > 2) ? this.getActivePage()-2 : 1);
			for(var i=start_page; i<=num; i++){
				var page_button = document.createElement('li');
				var page_button_link = document.createElement('a');
					if(i == this.getActivePage()){
						page_button_link.className = 'active';
					};
					this.pages_list.push(page_button_link);
					page_button_link.href = '#';
					page_button_link.innerHTML = i;
					page_button.appendChild(page_button_link);
					pager_body.appendChild(page_button);
			};
		};
		
		if(this.getActivePage() != this.getPagesNum() && this.pages_number > 1){
			var next_button = document.createElement('li');
				next_button.className = 'next';
			this.next_button_link = document.createElement('a');
			this.next_button_link.innerHTML = 'Next';
			this.next_button_link.href = '#';
				next_button.appendChild(this.next_button_link);
				pager_body.appendChild(next_button);
		};
		this.addListeners();
		return pager_body;
	},
	getPagesNum : function(){
		var correction = (this.items_number%this.PAGES_PER_PAGE > 0) ? 1 : 0
		var pages_number = (this.items_number - this.items_number%this.PAGES_PER_PAGE)/this.PAGES_PER_PAGE;
			pages_number = (pages_number < 10 ? pages_number : 10) + correction;
		return pages_number;
	},
	getActivePage : function(){
		return parseInt(this.active_page);
	},
	setActivePage : function(value){
		this.active_page = value;
	},
	addListeners : function(){
		var _obj = this;
		if(this.prev_button_link){
			this.prev_button_link.onclick = function(){
				_obj.setActivePage(_obj.getActivePage()-1);
				_obj.getPage();
				_obj.action();
			};
		};
		if(this.next_button_link){
			this.next_button_link.onclick = function(){
				_obj.setActivePage(_obj.getActivePage()+1);
				_obj.getPage();
				_obj.action();
			}
		};
		for(var i=0; i<this.pages_list.length; i++){
			(function(){
				var index = i;
				_obj.pages_list[index].onclick = function(){
					_obj.setActivePage(_obj.pages_list[index].innerHTML);
					_obj.getPage();
					_obj.action();
				};
			})();
		};
	},
	getPage : function(){
		this.addPager();
	}
};

CM.FieldsManager = function(target){
	
	this.coordinates_array = [];
	this.locations_array = [];
	this.target = $(target);
	this.resetCoordFields();
	this.ADD_POINT_INSTRUCTION = 'Right click to add point.';
	
};

CM.FieldsManager.prototype = {
	
	resetCoordFields : function(){
		this.coord_fields = this.target.adjacent('div.waypoint_latlng');
	},
	
	setDescr : function(value, i){
		this.locations_array[i] = value;
	},
	
	getDescr : function(i){
		return this.locations_array[i];
	},
	
	setCoords : function(value, i){
		if ((value && value.match(/\d+(\.\d+)?/g) && value.match(/\d+(\.\d+)?/g).length == 2) || !value){
			this.coordinates_array[i] = value;
			if(value){
				this.getCoordField(i).innerHTML = /[-+]?[0-9]*\.?[0-9]{0,2}/.exec(value.match(/\d+(\.\d+)?/g)[0])+' '+/[-+]?[0-9]*\.?[0-9]{0,2}/.exec(value.match(/\d+(\.\d+)?/g)[1]);
			}
		}
	},
	
	getCoords : function(i){
		return this.coordinates_array[i];
	},
	
	removePoint : function(i){
		this.coordinates_array.splice(i,1);
		this.locations_array.splice(i,1);
	},
	
	showCoords : function(i){
		this.getCoordField(i).innerHTML = this.getCoords(i);
	},
	
	getCoordsNum : function(){
		return this.coordinates_array.length;
	},
	
	showDescr : function(i){
		this.getCoordField(i).innerHTML = (/Unknown road/.test(this.getDescr(i)) ? 'Unknown road...' : this.getDescr(i));
		this.getCoordField(i).title = this.getDescr(i);
	},
	
	getCoordField : function(i){
		return this.coord_fields[i];
	},

	getCoordFieldsNum : function(){
		return this.coord_fields.length;
	},
	
	clearFields : function(){
		for(var i=0; i<this.getCoordFieldsNum(); i++){
			this.getCoordField(i).up().remove();
			this.removePoint();
		};
	},
	
	addNewLocation : function(i){

		this.resetCoordFields();
		var li_el = document.createElement('li');
		var icon = document.createElement('img');
			icon.src = CM.Util.getRootUrl() + 'images/routing/route_icon_'+i+'.png';
			icon.alt = 'Point '+i;
			icon.width = '23';
			icon.height = '26';
			
		this.latlng_field = document.createElement('div');
		this.latlng_field.className = 'waypoint_latlng grey';
			
		var close_link = document.createElement('a');
			close_link.href = '#';
			close_link.className = 'close_waypoint';
			
		var replace_points_link = document.createElement('a');
			replace_points_link.href = '#';
			replace_points_link.className = 'replace_points';
			replace_points_link.id = 'replacePointsLink_' + i;
			
			li_el.appendChild(icon);
			li_el.appendChild(this.latlng_field);
			li_el.appendChild(close_link);
			li_el.appendChild(replace_points_link);
			
		this.target.insertBefore(li_el, $('clearRoute').parentNode);
		this.resetCoordFields();
		return li_el;
	},
	
	getSearchSelect : function(i){

		this.resetCoordFields();
		
		if(!this.search_results_selects){
			this.search_results_selects = [];
		};
		
		this.search_results_selects[i] = document.createElement('select');
		this.search_results_selects[i].className = 'waypoint_search_results hidden';
		
		this.getCoordField(i).parentNode.insertBefore(this.search_results_selects[i], this.getCoordField(i));
		return this.search_results_selects[i];
		
	},
	
	hasSearchSelect : function(i){
		if(this.search_results_selects && this.search_results_selects[i]){
			return true;
		};
	},
	
	destroySearchSelect : function(i){
		if(this.search_results_selects[i] && this.search_results_selects[i].parentNode){
			this.search_results_selects[i].parentNode.removeChild(this.search_results_selects[i]);
			if(this.getDescr(i)){
				this.showDescr(i);
			} else if(this.getCoords(i)) {
				this.showCoords(i);
			};
			this.getCoordField(i).removeClassName('hidden');
		};
	}
	
}
