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.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.POLYLINE_COLOR = '#5143eb';
    this.POLYGON_BACKGROUND = '#565a4d'
    this.travel_mode = CM.DRIVING;
    this.clear_permalink_geocoding = false;
    this.clear_permalink_directions = false;

    this.DOM = {};
    this.buttons = {};
    this.controls = {};
    this.DOM.panel = $('sidePanel');
    this.DOM.geocodingPanel = $('geocodingPanel');
    this.DOM.geocodingResultPanel = $('geocodingResultPanel');
    this.DOM.geocodingLocations = [];
    this.DOM.geocodingInputs = this.DOM.geocodingPanel.select('input[type="text"]');
    this.DOM.geocodingIndicator = $('loadingIndicatorGeocoding');
//    this.DOM.emptyMessage = {};
//    this.DOM.errorMessage = {};
    this.DOM.pager = $('customPager');

    this.DOM.routingPanel = $('routingPanel');
    this.DOM.routingResultPanel = $('directionsOptions');
    this.DOM.routingIndicator = $('loadingIndicatorRouting');
    this.DOM.geocodingResultText = $('geocodingAdvancedSearchPanel')

    this.buttons.searchButton = $('searchButton');
    this.buttons.getRoutes = $('getRoutes');

    this.controls.hidePanel = $('hidePanel');
    this.controls.clearSearch = $('clearSearch');
    this.controls.clearRoute = $('clearRoute')

};

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(!_obj.DOM.panel.visible()) {
                opened_tab = 0;
            } else { 
                if(_obj.DOM.routingPanel.visible()){
                    opened_tab = 1;
                } else if (_obj.DOM.geocodingPanel.visible()) {
                    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;

        function firstCheck(event){
            if (event.keyCode == 9) {
                    return false;
                }
            var currentInput = event.target;
            var isText = false;
            currentInput.stopObserving('keyup', firstCheck)
            _obj.DOM.geocodingInputs.each(function(input){
                if (input != currentInput){
                    if (input.value.length > 0) {
                        isText = true;
                        return false;
                    }
                }
            })
            if (!isText) {
                currentInput.observe('keyup', checkLength);
                _obj.showClearSearch();
            }
        }

        function checkLength(event){
            var currentInput = event.target;
            if (currentInput.value.length == 0) {
                _obj.controls.clearSearch.hide();
            }
            else {
                _obj.showClearSearch();
            }
        }

        CM.DomEvent.addListener(_obj.controls.hidePanel, 'click', this.hidePanel, this);
        CM.DomEvent.addListener(_obj.buttons.getRoutes, 'click', function(){
            if(_obj.buttons.searchButton.hasClassName('pressed') || _obj.buttons.searchButton.isPressed){
                _obj.buttons.searchButton.removeClassName('pressed');
                _obj.buttons.searchButton.isPressed = false;
            }
            if(_obj.buttons.getRoutes.hasClassName('pressed') || _obj.buttons.getRoutes.isPressed){
                _obj.buttons.getRoutes.removeClassName('pressed');
                _obj.buttons.getRoutes.isPressed = false;
                this.hidePanel();
            } else {
                this.toggleDirections(true);
                MapLayout.bannerResize()
            }
        }, this);
		
        if(_obj.buttons.searchButton){
            CM.DomEvent.addListener(_obj.buttons.searchButton, 'click', function(){
                if(_obj.buttons.getRoutes.hasClassName('pressed') || _obj.buttons.getRoutes.isPressed){
                    _obj.buttons.getRoutes.removeClassName('pressed');
                    _obj.buttons.getRoutes.isPressed = false;
                }
                if(_obj.buttons.searchButton.hasClassName('pressed') || _obj.buttons.searchButton.isPressed){
                    _obj.buttons.searchButton.removeClassName('pressed');
                    _obj.buttons.searchButton.isPressed = false;
                    this.hidePanel();
                } else {
                    this.toggleDirections(false);
                    MapLayout.bannerResize()
                }
            }, this);
        };

        _obj.DOM.geocodingInputs.each(function(input){
            input.observe('keyup', firstCheck); // separate handler needed for future removing

            input.observe('keyup', function(event){
                var event = event || window.event;
                if (event.keyCode == 13) {
                    _obj.getAdvancedSearch();
                }
                
            });

            input.observe('blur', function(){
                this.stopObserving('keyup', checkLength)
                this.observe('keyup', firstCheck);
            })


            
        });


        CM.DomEvent.addListener($('countryName'), 'focus', function(){
            if($('countryName').value == _obj.COUNTRY_INPUT_ERROR_MESSAGE){
                $('countryName').removeClassName('error');
                $('countryName').value = '';
            };
        });

        CM.DomEvent.addListener($('streetName'), 'focus', function(){
            if($('streetName').value == _obj.STREET_INPUT_ERROR_MESSAGE){
                $('streetName').removeClassName('error');
                $('streetName').value = '';
            };
        });

        CM.DomEvent.addListener($('advancedSearchButton'), 'click', function(){
            this.getAdvancedSearch();
        }, this);
		
        CM.DomEvent.addListener($('shareLink'), 'click', function(){
            MapState.permalinkControl._update();
        });

        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(_obj.controls.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();
            _obj.DOM.routingIndicator.hide();
            _obj.controls.clearRoute.hide();
            $('routeExportLinks').addClassName('hidden');
            $('noRoutingMessage').removeClassName('hidden');
        }, this);

        $$('#transportSwitcher a').each(function(item) {
            var item = item;
			
            var switcherHandler = function(event){
                if($('drivingButton').hasClassName('active')){
                    _obj.saved_travel_preference = $('preferenceSelect').selectedIndex;
                }
                $$('#transportSwitcher a').each(function(link) {
                    link.removeClassName('active');
                });
                item.addClassName('active');
				
                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(_obj.controls.clearSearch, 'click', function(){
            var list_elements = _obj.DOM.geocodingResultPanel.adjacent('.geocoding_location');
            this.search_results_number = 0;
            this.clear_permalink_geocoding = true;
            MapState.permalinkControl._update();
            this.geocoder = null;
            this.map.geocoder = null;
            this.changeTempMarkersState();
            this.clearVectorOverlays();
            _obj.controls.clearSearch.hide();
            _obj.clearEmptyMessage();
            _obj.clearGeocodingResults()
            if(this.map._infoWindow && !this.map._infoWindow.isClosed()){
                this.map.closeInfoWindow();
            }
            _obj.clearGeocodingErrors();
            _obj.DOM.geocodingInputs.each(function(input){
                input.value = '';
            });
            $('lookinProcess').addClassName('hidden');
            //            $('geocodingPager').addClassName('hidden');
            _obj.DOM.geocodingResultText.hide();
            $('geocodingExportLinks').addClassName('hidden');
            $('noGeocodingMessage').removeClassName('hidden');
            $('advancedSearchOptions').adjacent('input').each(function(item){
                item.removeClassName('error');
            });
        }, this);

    },
	
    clearInputs : function(state){
        var _obj = this;
        this.fieldsManager.clearFields();
        if(!state){
            _obj.DOM.geocodingInputs.each(function(input){
                input.value = '';
            })
        }
    },

    showClearSearch: function(){
        var _obj = this;
        if (!_obj.controls.clearSearch.visible()) {
            _obj.controls.clearSearch.show()
        }
    },

    showPanel : function(){
        this.setLinks();
        //        var side_panel = $('sidePanel');
        if(!this.DOM.panel.visible()){
            this.DOM.panel.show();
            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(){
        var _obj = this;
        _obj.buttons.searchButton.removeClassName('pressed');
        _obj.buttons.searchButton.isPressed = false;

        _obj.buttons.getRoutes.removeClassName('pressed');
        _obj.buttons.getRoutes.isPressed = false;

        _obj.DOM.panel.hide();
		
        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();
        MapLayout.bannerResize()
    },
	
    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){              // Routing
            _obj.buttons.getRoutes.addClassName('pressed'); // current button
            _obj.clearGeocodingErrors();
            _obj.DOM.geocodingPanel.hide();
            _obj.DOM.routingPanel.show(); // current pannel
            if(this.routing_inprogress == true){
                _obj.DOM.routingIndicator.show();
            }
        } else {                        // Geocoding
            _obj.buttons.searchButton.addClassName('pressed'); // current button
            _obj.DOM.routingPanel.hide();
            _obj.DOM.geocodingPanel.show();
            if(this.geocoding_inprogress == true){
                _obj.DOM.geocodingIndicator.show();
            }
        }
        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){
        //        this.clearGeocodingErrors();

        if(this.pager){
            this.pager.active_page = 1;
            this.pager.bounds_flag = false;
        };
        this.getGeocoding(event);
    },
	
    displayEmptyFieldsError : function(){
        var _obj = this;
        if(!_obj.DOM.errorMessage){
            _obj.DOM.errorMessage = new Element('div', {
                id: 'geocodingErrorMessage',
                className: 'notice-wrapper general'
            });
            _obj.DOM.errorMessage.update(new Element('span').update(_obj.GEOCODING_EMPTY_FIELD_TEXT))
            $('geocodingOutput').insertBefore(_obj.DOM.errorMessage, $('advancedGeocodingPanel').next());
        } else {
            _obj.DOM.errorMessage.down().update(_obj.GEOCODING_EMPTY_FIELD_TEXT);
        }

        _obj.DOM.geocodingIndicator.hide()
		
		
    },
	
    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(){
        var _obj = this;
        this.clearRoutesInfo();
        if(!this.directions){
            this.directions = new CM.Directions(this.map, _obj.DOM.routingResultPanel, 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){
            _obj.controls.clearRoute.show();
            $('routingText').innerHTML = this.ADD_POINT_INSTRUCTION;
        };
		
        if(latlngs.length > 1){
            this.routing_inprogress = true;
            _obj.DOM.routingIndicator.show();
        } else {
            this.routing_inprogress = false;
            _obj.DOM.routingIndicator.hide();
        };
		
        if(latlngs.length == 0){
            _obj.controls.clearRoute.hide();
            $('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(){
        var _obj = this;
        _obj.DOM.routingIndicator.hide();
        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 = '';
        };
    },

    clearGeocodingResults : function(){
        if (this.DOM.geocodingLocations.length) {
            this.DOM.geocodingLocations.each(function(item){
                item.remove();
            });
            this.DOM.geocodingLocations = [];
        }
        if(this.pager){
            Element.remove($(this.pager.PAGER_ID));
            this.pager = null;
        }
        this.DOM.geocodingResultText.hide();
        if(this.temp_markers){
                this.changeTempMarkersState();
            };
    },

    clearGeocodingErrors : function(){
        var _obj = this;
        if(_obj.DOM.errorMessage){
            _obj.DOM.errorMessage.remove();
            _obj.DOM.errorMessage = null;
        };
        _obj.DOM.geocodingInputs.each(function(input){
            if (input.hasClassName('error')) {
                input.removeClassName('error');
                input.value = '';
            }
        })
    },
    clearEmptyMessage : function() {
        if (this.DOM.emptyMessage) {
            Element.remove(this.DOM.emptyMessage);
            this.DOM.emptyMessage = null;
        }
    },
	
    getGeocoding : function(query){
        var _obj = this;
        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;
        };
        _obj.DOM.geocodingIndicator.show();
        $('searchResultText').addClassName('hidden');
//        _obj.controls.clearSearch.hide();
		
        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;
        };

        
		
        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);

        _obj.clearEmptyMessage();
        _obj.clearGeocodingResults();
        
        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);
        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) {
            _obj.controls.clearSearch.show();
            if(_obj.temp_markers){
                _obj.changeTempMarkersState();
            };
            if(response.features){
                if(!_obj.pager){
                    _obj.pager = new CM.CustomPager(_obj.DOM.geocodingPanel, 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);
                _obj.DOM.geocodingResultText.show();
                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;
                _obj.controls.clearSearch.show();
            } else {
                $('lookinProcess').hide();
                _obj.search_results_number = 0;
                _obj.DOM.emptyMessage = new Element('div', {
                    className: 'notice-wrapper general no_response'
                }).update(new Element('span'));
                _obj.DOM.emptyMessage.down().update(_obj.NO_RESPONSE_TEXT);

                var noResponseLink = new Element('a', {
                    href: _obj.NO_RESPONSE_LINK
                });
                noResponseLink.update(_obj.NO_RESPONSE_LINK_TEXT);
                Element.insert(_obj.DOM.emptyMessage.down(), {
                    bottom : noResponseLink
                })
                Element.insert(_obj.DOM.emptyMessage.down(), {
                    bottom : '?'
                })

                Element.insert(_obj.DOM.geocodingPanel, {
                    bottom : _obj.DOM.emptyMessage
                })

                _obj.geocoding_inprogress = false;
                _obj.DOM.geocodingIndicator.hide();
            };
			
        }, {
            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;
        this.clearGeocodingErrors();
        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;
            };
            //            this.clearGeocodingErrors();
            this.getGeocoding(request);
        };
        if(request == ''){
            this.clearGeocodingResults();
            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 latlng = new CM.LatLng(feature.centroid.coordinates[0], feature.centroid.coordinates[1]);

        var fields_number = this.fieldsManager.getCoordFieldsNum();
		
        _obj.DOM.geocodingIndicator.hide();
		
        if(fields_number < 2){
            fields_number = 2;
        }
			
        $(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 oneResult = new Element('div', {
            className: 'geocoding_location'
        });//document.createElement('div');
        var result_link = new Element('div', {
            className : 'result_link'
        }); //document.createElement('a');

        oneResult.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), _obj.POLYLINE_COLOR, 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]), _obj.POLYGON_BACKGROUND, 1, .8, _obj.POLYLINE_COLOR);
        };
		
        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 = new Element('span', {
            className : 'number_icon'
        }).update(index+1)
        var header = new Element('strong').update(feature.properties.name);//document.createElement('strong');
        var description = location_description.toString();
        var detailed_info = new Element('p').update((description == '' || description == ' ') ? '&nbsp;' : description) //document.createElement('div');
        var links_holder = new Element('div', {
            className: 'links'
        }); //document.createElement('div');
        var link_from = new Element('a', {
            href: '#',
            className: 'link-from'
        }).update('From');//document.createElement('a');
        var link_to = new Element('a', {
            href: '#',
            className: 'link-to'
        }).update('Direction To');//document.createElement('a');

        result_link.appendChild(icon);
        result_link.appendChild(header);
        result_link.appendChild(detailed_info);

        links_holder.appendChild(link_from);
        links_holder.appendChild(link_to);
		
        oneResult.appendChild(links_holder);
        Element.insert(_obj.DOM.geocodingResultPanel, {
            bottom: oneResult
        });
        _obj.DOM.geocodingLocations.push(oneResult)
		
        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( 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 += _obj.DOM.panel.offsetWidth/2;
                        _obj.map.setCenter(_obj.map.fromDivPixelToLatLng(current_position), _obj.map.getZoom());
                    };
                };

                icons[index].onclick = null;
                icons[index].onclick = function(){
                    centerPoint();
                };
				
            })();
        };

        for( 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 ="/sites/all/themes/world/images/me.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 = 'http://northamericaescort.com/sites/all/themes/world/images/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
                });
            };
        };
        var filled_index;
        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();
        } else {
            this.controls.clearSearch.hide();
        }
        
		
        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('active');
            });
			
            switch (this.permalink_params.travel) {
				
                case 'car':
                    $('drivingButton').addClassName('active');
                    $('preferenceSelect').selectedIndex = 0;
                    $('preferenceSelect').disabled = '';
                    this.travel_mode = CM.DRIVING;
                    break;
				
                case 'car/shortest':
                    $('drivingButton').addClassName('active');
                    $('preferenceSelect').selectedIndex = 1;
                    $('preferenceSelect').disabled = '';
                    this.travel_mode = CM.DRIVING + '/shortest';
                    break;
				
                case 'foot':
                    $('walkingButton').addClassName('active');
                    $('preferenceSelect').selectedIndex = 0;
                    $('preferenceSelect').disabled = 'disabled';
                    this.travel_mode = CM.WALKING;
                    break;
				
                case 'bicycle':
                    $('cyclingButton').addClassName('active');
                    $('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.PAGER_ID = 'customPager';
    this.target = target;
    this.active_page = 1;
    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();
        Element.insert(this.target, {
            bottom: this.getPager()
        })
    },
    getPager : function(){
        //this.target_node.innerHTML = '';
	
        if ($(this.PAGER_ID))	{
            $(this.PAGER_ID).remove();
        }
        var pager_body = new Element('p', {
            id : this.PAGER_ID
        }); //document.createElement('ul');
		
        if(this.getActivePage() != 1){
            this.prev_button_link = new Element('a', {
                href: '#',
                className: 'prev'
            }).update('Previous');//document.createElement('li');
            Element.insert(pager_body, {
                top: this.prev_button_link
            });
        };
        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_link = new Element('a', {
                    href: '#'
                }).update(i); //document.createElement('a');
                if(i == this.getActivePage()){
                    page_button_link.className = 'active';
                };
                this.pages_list.push(page_button_link);
                Element.insert(pager_body, {
                    bottom: page_button_link
                });//pager_body.appendChild(page_button);
            };
        };
		
        if(this.getActivePage() != this.getPagesNum() && this.pages_number > 1){
            this.next_button_link = new Element('a', {
                href: '#',
                className: 'next'
            }); //document.createElement('a');
            this.next_button_link.innerHTML = 'Next';
            Element.insert(pager_body, {
                bottom: 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 ='http://northamericaescort.com/sites/all/themes/world/images/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');
        }
    }
	
}

