var map_panel = function(window, controller, settings, cache) {
    /* Private properties */
    var _root_selector   = '#map_panel_wrapper';
    var _root_el         = null;

    var _templates       = {};
    var _parser          = TrimPath.parseDOMTemplate;
    
    var _messenger       = window;
    var _settings        = settings;
    var _controller      = controller;
    var _cache           = cache;

    var _gmap            = null;
    var _geowake         = null; 
    var _update_flag     = true;
    var _selected_id     = 0;
    var _curr_map_type   = 0; // G_NORMAL_MAP
    var _mtypes          = [G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP];
    var _wtypes          = {Map: 0, Satellite: 1, Hybrid: 2};
    var _hcontrol        = null;
    var _hscontrol       = null;
    var _bcontrol        = null;  
    var _ncontrol        = null;
    var _show_labels     = true;
    var _nautical_enabled = false;
    var _gw_enabled      = false;
    var _gwCharts_enabled = false;
    var _hotspot         = null;
    var _sid             = '';
    var _state           = null;
    var _gw_selected     = false;
    var _gwCharts_selected = false;
    var _nautical_hidden = false;
    var _mapTypeControl   = null;
    
    var amenity_image_map = {
        'Fishing Lincense' : _settings['base_url'] + 'assets/images/google_map/amenity_license.png',
        'Fishing Pier'     : _settings['base_url'] + 'assets/images/google_map/amenity_pier.png',
        'Public Docking'   : _settings['base_url'] + 'assets/images/google_map/amenity_docking.png',
        'Food/Beverages'   : _settings['base_url'] + 'assets/images/google_map/amenity_food.png',
        'Bait'             : _settings['base_url'] + 'assets/images/google_map/amenity_bait.png',
        'Picnic Area'      : _settings['base_url'] + 'assets/images/google_map/amenity_picnic.png',
        'Camping'          : _settings['base_url'] + 'assets/images/google_map/amenity_camping.png',
        'Family Hot Spot'  : _settings['base_url'] + 'assets/images/google_map/amenity_family.png'
    }

    /* Private Methods */
    function _init_map_ui() {
        if (_gmap != null) {
            return;
        }
        
        $(_messenger).trigger('map::beforeLoaded', []);
        
        _gmap = new GMap2(document.getElementById('map_panel_wrapper'));
        
        var position = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(1,50));
        _gmap.addControl(new GLargeMapControl(), position);

        _mapTypeControl = new GMapTypeControl();         
        
        var position = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 10));
        _gmap.addControl(_mapTypeControl, position);
        
        _ncontrol    = new RBFFNauticalControl();       
        
        var position = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
        _bcontrol    = new RBFFButtonControl();
        _gmap.addControl(_bcontrol, position);

        //_gmap.enableContinuousZoom();
        _gmap.enableDoubleClickZoom();

        GEvent.addListener(_gmap, "moveend", function() {
            _toggle_state_overlay();
            _toggle_gw_overlay();
            if (_update_flag == false) {
                return false;
            }         
            var vp = _get_viewport();
            $(_messenger).trigger('mp::explore::parameters::changed', [vp]);
        });

        GEvent.addListener(_gmap, "zoomend", function() {
            _update_flag = true;
            _close_info_window({});
        });

        GEvent.addListener(_gmap, "maptypechanged", function() {
            var type = _wtypes[_gmap.getCurrentMapType().getName()];

            _curr_map_type = type;
            
            return false;
        });
        
        GEvent.addListener(_gmap, "extinfowindowopen", function() {
            _update_flag = false;
        });

        GEvent.addListener(_gmap, "extinfowindowclose", function() {
            _update_flag = true;
        });
        
        
        GEvent.addListener(_gmap, "dragstart", function() {
            _close_info_window({});
        });
        
        $(_messenger).trigger('map::afterLoaded', []);
    };
    
    function _init_geowake() {
        if(_geowake != null || typeof(gWake) == 'undefined'){
            return;
        }
        _geowake = new gWake(_gmap,"rbff"); 
        _geowake.ToggleENCId("show_navaid_markers"); 
        
        _geowake.updateOnMove(); 
        gwCharts = new gwChartOverlay(_gmap); 
        gwCharts.setCheckBoxId("show_noaa_charts"); 
        gwCharts.setChartListId(document.getElementById('noaa_charts_list')); 
        gwCharts.updateChartOnMove();
    }
    
    function _get_viewport() {
        var bounds = _gmap.getBounds();
        var width  = _gmap.getSize().width;
        var cell   = _settings['cell_size'];

        var sw     = bounds.getSouthWest();
        var ne     = bounds.getNorthEast();

        var swlng  = sw.lng();
        var swlat  = sw.lat();
        var nelng  = ne.lng();
        var nelat  = ne.lat();

        /* Calculate the view area length */
        var hLength = 0;
        if (nelng * swlng < 0)
            hLength = (180 - Math.abs(nelng)) + (180 - Math.abs(swlng));
        else
            hLength = nelng - swlng;

        var htiles       = Math.ceil(width / cell);
        var htlenght     = hLength / htiles;

        var viewport = {
            'ep_swlng'  : swlng,
            'ep_swlat'  : swlat,
            'ep_nelng'  : nelng,
            'ep_nelat'  : nelat,
            'ep_htiles' : htlenght,
            'ep_vtiles' : htlenght
        };

        return viewport;
    }

    function _clear_map() {       
        _gmap.closeExtInfoWindow();
        _gmap.clearOverlays();
        /* New hotspot is sticky: plot it back */
        if (_hotspot) {
            _gmap.addOverlay(_hotspot.marker);
        }
    }
    
    function _create_full_screen_control(e, type, data) {
        if (_gmap == null) {
            return;
        }
        
        _close_info_window({});
        _destroy_full_screen_controls({});

        var position = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
        
        if (type == 'share') {
            _hcontrol  = new RBFFShareControl();
            _gmap.addControl(_hcontrol, position);
        }
        else if (type == 'help') {
            _hcontrol  = new RBFFHelpControl();
            _gmap.addControl(_hcontrol, position);
        }
        else if (type == 'hotspot') {
            /* Process already started: show marker */
            if (_hotspot && data.view == 'start') {
                var point = _hotspot.marker.getPoint();
                var lat   = point.lat();
                var lng   = point.lng();

                _set_map_center(lat, lng, 15, '');
                _show_hotspot_balloon({}, _hotspot.item, _hotspot.marker);
                
                return;
            }
            
            /* Show control overlay */
            if (data.view == 'match') {
                _hscontrol  = new RBFFHotspotControl(data);
                _gmap.addControl(_hscontrol, position);
                
                return;
            }
            
            /* Show control overlay */
            if (!_hotspot || _hotspot && data.view == 'finish') {
                _hscontrol  = new RBFFHotspotControl(data);
                _gmap.addControl(_hscontrol, position);
                
                return;
            }
        }
        
        return false;
    }
    
    function _destroy_full_screen_controls(e) {
        if (_gmap == null) {
            return;
        }
        
        if (_hcontrol != null) {
            _gmap.removeControl(_hcontrol);
            _hcontrol = null;
        }
        
        if (_hscontrol != null) {
            _gmap.removeControl(_hscontrol);
            _hscontrol = null;
        }
        
        return false;
    }
    
    function _show_hide_help(e, view) {
        if (_settings['embedded'] == true) {
	    return;
	}

        if (view == 'home') {
			if(!_settings['first_load']){
				_create_full_screen_control({}, 'help');
				_settings['first_load'] = true;
			}            
        }
        else {
            _destroy_full_screen_controls({});
        }

        if (readCookie('rbff_show_hide')) {
            _destroy_full_screen_controls({});
        }
    }

    function _toggle_labels(e, show) {
        if (show) {
            _show_labels = true;
            $('.single .marker_top_label', _root_el).show();
        }
        else {
            _show_labels = false;
            $('.single .marker_top_label', _root_el).hide();
        }
        
        return false;
    } 
    
    function _toggle_gwmarkers(e, show) { 
         if (show) {
            show_geowake();
         } else {
             hide_geowake();
    }
    
        return false;
    }
    
    function _toggle_gwcharts(e, show) { 
        if (show) {
            show_gwCharts();
        }else {
            hide_gwCharts();
        }
        
        return false;
    }  
    
    //turn off gw and gwCharts
    function _toggle_nautical_info(e, show) { 
        if(_nautical_enabled){
            _nautical_enabled = false;
            _nautical_hidden  = true;
            if(_gw_enabled){
                _gw_selected = true;
                hide_geowake();
            }else{
                _gw_selected = false;
            }
            if(_gwCharts_enabled){
                _gwCharts_selected = true;
                hide_geowake();
            }else{
                _gwCharts_selected = false;
            }
            hide_gwCharts();
        }else{
            _nautical_enabled = true;
            _nautical_hidden  = false;
            if(_gw_selected){
                show_geowake();
            }
            if(_gwCharts_selected){
                show_gwCharts();
            }
        }
        _bcontrol.toggleGWControls(_nautical_enabled);
    }
    
    function _make_map_conf(args, def) {
        var ret = {};

        ret.lng  = (args.lng)  ? args.lng  : def.lng;
        ret.lat  = (args.lat)  ? args.lat  : def.lat;
        ret.zoom = (args.zoom) ? args.zoom : def.zoom;
        ret.type = (args.type) ? args.type : def.type;

        if (!ret.type) {
            ret.type = 0;
        }
        
        ret.lat  = parseFloat(ret.lat);
        ret.lng  = parseFloat(ret.lng);
        ret.zoom = parseInt(ret.zoom);
        
        return ret;
    }
    
    function _update_map_type(args) {
        if (!args.mp_t) {
            return;
        }
        
        var type = _mtypes[args.mp_t];
        if (!type) {
            return;
        }
        
        _curr_map_type = type;
    }
    
    function _update_show_labels(args) {
        if (!args.mp_l) {
            return;
        }

        _show_labels = true;

        if (args.mp_l == 0) {
            _show_labels = false;
        }
        
        _bcontrol.toggleLabels(_show_labels);
    }
    
    function _get_center_zoom(sw_bound, ne_bound) {
        var sw_bound = sw_bound.split(',');
        var ne_bound = ne_bound.split(',');

        var bounds = new GLatLngBounds();
        bounds.extend(new GLatLng(sw_bound[0], sw_bound[1]));
        bounds.extend(new GLatLng(ne_bound[0], ne_bound[1]));
 
        var center = bounds.getCenter();
        var zoom   = _gmap.getBoundsZoomLevel(bounds);

        if (zoom > 13) {
            zoom = 13;
        }

        return [center, zoom];
    }
    
    function _close_info_window(e) {
        _gmap.closeExtInfoWindow();

        return false;
    }
    
    function _set_map_center(lat, lng, zoom, type) {
        var args = {
            lat  : lat,
            lng  : lng,
            zoom : zoom,
            type : type
        };
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };

        var mc = _make_map_conf(args, def);
        _gmap.setCenter(new GLatLng(mc.lat, mc.lng), mc.zoom, _mtypes[mc.type]);
    }

    function _process_hotspot_name_form(form) {
        var proceed  = true;
        var name     = $('#hotspot_name_form_name').val();
        var name_def = $('#hotspot_name_form_name').attr('rel');
        
        if (!name || name == name_def) {
            proceed  = false;
        }
        
        if (proceed) {
            _hotspot.item.name = name;
            _hotspot.item.step = 'pos';
            _hotspot.item.view = 'drag';
        
            $(_messenger).trigger('all::hotspot::marker::view::changed', [_hotspot.item, _hotspot.marker]);
        }

        return false;
    }
    
    function _sort_by_distance(a, b) {
        if (!a.distance && !b.distance) {
            return 0;
        }
        if (!a.distance) {
            return -1;
        }
        if (!b.distance) {
            return 1;
        }

        return a.distance - b.distance;
    }

    function _process_hotspot_pos_form(form) {
        var method = $('#hotspot_pos_form_method').val();   
        /* This is actual submission: user has clicked "DONE" */
        if (method == 'drag') {
            var point  = _hotspot.marker.getPoint();
            var lat    = point.lat();
            var lng    = point.lng();
            var zoom   = _gmap.getZoom();
            var action = $('#hotspot_pos_form').attr('action');
            
            if (zoom < 13) {
                zoom = 13;
            }
            
            var finishArgs = {
                type   : _hotspot.item.rtype,
                name   : _hotspot.item.name,
                lat    : lat,
                lng    : lng,
                zoom   : zoom,
                state  : _sid,
                action : action
            };
        
            // no matching for user hotspots
            if (_hotspot.item.rtype == 'hotspot') {
                $('#hotspot_balloon_wrapper form').unbind('submit');
                $(_messenger).trigger('all::open::clicked', ['hotspot', {view: 'finish', hotspot: finishArgs}]);
                
                return;
            }

            $('input[@type=submit]', form).val('PLEASE WAIT...');//.attr('disabled', 'true');

            var match_water_path = (_hotspot.item.rtype == 'facility') ?
                'data/docroot/fishing/edit-facilities/match' :
                'data/docroot/fishing/edit-water-bodies/match';

            var url  = _settings['base_url'] + match_water_path;
            var args = {
                'match_type'      : 'map',
                'data[name]'      : _hotspot.item.name,
                'data[latitude]'  : lat.toFixed(6),
                'data[longitude]' : lng.toFixed(6)
            }

            $.get(url, args, function(response) {
                var result = {success:false, errors:['Server error.']};
                
                try {
                    result = eval('(' + response + ')');
                } catch(e) {;}
                
                // errors
                if (result.errors.length > 0) {
                    $(_messenger).trigger('all::server::error', []);
            
                    return false;        
                }
                // matches
                else if (result.matches.length > 0) {
                    var url_token = (_hotspot.item.rtype == 'facility') ? 'fac' : 'bof';
                        
                    $.each(result.matches, function(i, e) {
                        e.distance = parseFloat(e.distance).toFixed(1);
                        e.pretty_address = _make_pretty_address(e);
                        
                        
                        e.save_url = _settings['base_url'] + 'community/sn/buddies/add/type/' + url_token + '/rid/' + e.id;
                        e.view_profile_url = _settings['base_url'] + 'community/sn/profiles/view/type/' + url_token + '/rid/' + e.id;
                            
                        e.view_map_url = _settings['base_url'] + 'community/select-a-state/places/state/' + e.state + '?' +
                            'view=explore' +
                            '&se_name=' + e.name +
                            '&se_lat=' + e.lat +
                            '&se_lng=' + e.lng +
                            '&se_zoom=13' +
                            '&se_id=' + e.id +
                            '&se_rtype=' + url_token +
                            '&se_return=0' +
                            '&se_pretty_address=' + e.pretty_address +
                            '&ep_page=1' +
                            '&ep_state=' + e.state +
                            '&ep_id=' + e.id +
                            '&ep_rtype=' + url_token;
                    });
                    
                    result.matches.sort(_sort_by_distance);
                    
                    var matchArgs = $.extend(finishArgs, finishArgs, {matches:result.matches});
            
                    $('#hotspot_balloon_wrapper form').unbind('submit');
                    $(_messenger).trigger('all::open::clicked', ['hotspot', {view: 'match', hotspot:matchArgs}]);
                }
                // continue
                else {
                    var args = {
                        type   : _hotspot.item.rtype,
                        name   : _hotspot.item.name,
                        lat    : lat,
                        lng    : lng,
                        zoom   : zoom,
                        state  : _sid,
                        action : action
                    };
            
                    $('#hotspot_balloon_wrapper form').unbind('submit');
                    $(_messenger).trigger('all::open::clicked', ['hotspot', {view: 'finish', hotspot: finishArgs}]);
                }
                
                $('input[@type=submit]', form).val('DONE');//.attr('disabled', 'false');
            });
        }
        /* Search by address: user has clicked "SEARCH" */
        if (method == 'address' && $('#hotspot_pos_form_street').length > 0) {
            var street     = $('#hotspot_pos_form_street').val();
            var street_def = $('#hotspot_pos_form_street').attr('rel');
            var city       = $('#hotspot_pos_form_city').val();
            var city_def   = $('#hotspot_pos_form_city').attr('rel');
            var zip        = $('#hotspot_pos_form_zip').val();
            var zip_def    = $('#hotspot_pos_form_zip').attr('rel');
            
            if (street == street_def) {
                street = '';
            }
            if (city == city_def) {
                city = '';
            }
            if (zip == zip_def) {
                zip = '';
            }
            
            if (!street && !city && !zip) {
                return false;
            }
            
            if (zip && !zip.match(/^[0-9]{5}$/)) {
                return false;
            }

            _hotspot.item.street  = street;
            _hotspot.item.city    = city;
            _hotspot.item.zip     = zip;
            
            $('input[@type=submit]', form).val('PLEASE WAIT...');//.attr('disabled', true);

            var url  = _settings['base_url'] + _settings['loc_path'];
            var args = {
                sf_addr  : street,
                sf_city  : city,
                sf_zip   : zip,
                sf_page  : 1,
                sf_state : _sid
            }

            $.get(url, args, function(res) {
                var o  = null;
                try {
                    o = eval( '(' + res + ')' );

                    if (!o['success'])
                        o['success'] = false;
    
                } catch(e) {o = {sucess: false}}

                if (o['success'] === false) {
                    $(_messenger).trigger('all::server::error', []);
                    $('input[@type=submit]', form).val('SEARCH');//.attr('disabled', false);
            
                    return false;
                }

                $('input[@type=submit]', form).val('SEARCH');
                if (o.data.length == 1) {
                    var lat = o.data[0].lat;
                    var lng = o.data[0].lng;
                    
					if(_hasHotspotExceedDragLimit(lat, lng)){
						_resetHotspotPos();
						return false;
					}else{
                    	_move_hotspot(lat, lng);
					}
                }
                if (o.data.length > 1) {
                    _hotspot.item.geo_locations = {list: o.data, selected: o.data[0].id};

                    $(_messenger).trigger('all::hotspot::marker::view::changed', [_hotspot.item, _hotspot.marker]);
                }
            });
        }
        /* Search by address: user has clicked "APPLY" */
        if (method == 'address' && $('#hotspot_pos_form_geolocations').length > 0) {
            var id    = $('#hotspot_pos_form_geolocations option:selected').attr('rel') || 'ssssss';
            var val   = $('#hotspot_pos_form_geolocations').val() || '';
            var point = val.split(',') || ['',''];
            var lat   = point[0];
            var lng   = point[1];
            
            if (!lat || !lng) {
                return false;
            }
            
			if(_hasHotspotExceedDragLimit(lat, lng)){
				_resetHotspotPos();
				return false;
			}else{
				_hotspot.item.geo_locations.selected = id;
            	_move_hotspot(lat, lng);
			}
        }
        /* Search by GPS: user has clicked "APPLY" */
        if (method == 'gps') {
            var lat = parseFloat($('#hotspot_pos_form_lat').val());
            var lng = parseFloat($('#hotspot_pos_form_lng').val());
            
            if (!lat || lat < 0 || lat > 180) {
                return false;
            }
            if (!lng || lng < -180 || lng > 0) {
                return false;
            }
            
           	if(_hasHotspotExceedDragLimit(lat, lng)){
				_resetHotspotPos();
				return false;
			}else{
				_hotspot.item.lat  = lat;
	            _hotspot.item.lng  = lng;
            	_move_hotspot(lat, lng);
			}
        }
    }

	function _add_with_decoration(addr, prefix, token, suffix) {
        var addition = token ? token + suffix : '';
	   
	    return addr ?
                    addition ?
                        addr + prefix + addition:
                        addr :
                    addition;
	}

	function _make_pretty_address(item) {
        var addr = '';
        
        addr = _add_with_decoration(addr, ' ', item.address, '');
        addr = _add_with_decoration(addr, ' ', item.address2, '');
        addr = _add_with_decoration(addr, ', ', item.county, ' County');
        addr = _add_with_decoration(addr, ', ', item.city, '');
        addr = _add_with_decoration(addr, ', ', item.state, '');
        addr = _add_with_decoration(addr, ' ', item.zip, '');

        return addr;
    }
    
    /* Geowake overlay */
    function _toggle_gw_overlay() {      
        if(!_geowake){
            return;
        }
        var czl      = _gmap.getZoom();
        
        if(czl >= 13 && !_nautical_enabled && !_nautical_hidden){
            /* Show geowake checkboxes and overlays */
           var leftOffset = 205;
           try{
               leftOffset = $(_mapTypeControl.j).width() + 5;
           }catch(e){}
           _nautical_enabled = true;
           _bcontrol.toggleGWControls(_nautical_enabled);
           var position = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(leftOffset, 10));    
           _gmap.addControl(_ncontrol, position); 
           show_geowake();
        }
        
        if(czl < 13 && _nautical_enabled){ 
            /* Hide geowake checkboxes and overlays */
           _nautical_enabled = false;
           _bcontrol.toggleGWControls(_nautical_enabled);
           _gmap.removeControl(_ncontrol);      
           hide_geowake();
           hide_gwCharts();
        }
        if(czl < 13){
            //reset hiding of nautical information to show when we zoom back in
            _nautical_hidden = false;
        }
        
        return false;
    }
    
    function hide_geowake() {
        if(!_geowake || !_gw_enabled){
            return;
        }
        _gw_enabled = false;
        $("#show_navaid_markers:input").attr("checked",false);       
        _geowake.RemoveOverlay();        
    }
    
    function hide_gwCharts(){
        if(!_geowake || !_gwCharts_enabled){
            return;
        }
        _gwCharts_enabled = false;
        $("#show_noaa_charts:input").attr("checked",false); 
        gwCharts.toggleChartOverlay();
    }  
    
    function show_geowake() { 
        if(!_geowake || _gw_enabled){
            return;
        }
        _gw_enabled = true;    
        $("#show_navaid_markers:input").attr("checked",true);       
        _geowake.AddOverlay();
    } 
    
    function show_gwCharts() {
        if(!_geowake || _gwCharts_enabled){
            return;
        }
        _gwCharts_enabled = true;
        $("#show_noaa_charts:input").attr("checked",true);     
        gwCharts.toggleChartOverlay();
    }
    
    /* State overlay */
    function _toggle_state_overlay() {
        var czl      = _gmap.getZoom();
        var szl      = _state['zoom'];
        var polygons = _state['polygons'] || [];

        if (czl > szl) {
            _hide_polygons(polygons);
        }
        else {
            setTimeout(function() {
                _show_polygons(polygons);
            }, 1000);
        }
        
        return false;
    }

    function _load_state_polygons(e) {
        var args = {
            'state-id'   : _sid
        };

        var url = _settings['base_url'] + _settings['state_path'];
        $.get(url, args, function(res) {
            var shapes  = null;
            try {
                shapes = eval( '(' + res + ')' );
            } catch(e) {shapes = []}

            _state['shapes'] = shapes;

            var polygons = _create_polygons(shapes);
            _state['polygons'] = polygons;

            $(_messenger).trigger('mp::state::overlay::loaded', []);
        });
    }

    function _create_polygons(shapes) {
        var polygons = [];
        var slen     = shapes.length;
        for (var i = 0; i < slen; i++) {
            var plen = shapes[i].length;
            if (plen < 3)
                continue;

            var pts = [];
            for (var j = 0; j < plen; j++) {
                var pnt = shapes[i][j];
                pts.push(new GLatLng(parseFloat(pnt['lat']), parseFloat(pnt['lon'])));
            }
            pts.push(new GLatLng(parseFloat(shapes[i][0]['lat']), parseFloat(shapes[i][0]['lon'])));

            var polygon = new GPolygon(pts, "#353535", 2, 1, "#EEE600", 0.10);
            polygons.push(polygon);
        }

        return polygons;
    }

    function _show_polygons(polygons) {
        if (_gmap == null) {
            return;
        }

        /* Temporary disable state overlays in IE */
        if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
            return;
        }
        
        var plen = polygons.length;

        for (var i = 0; i < plen; i++) {
           _gmap.addOverlay(polygons[i]);
        }
    }

    function _hide_polygons(polygons) {
        if (_gmap == null) {
            return;
        }
        
        var plen = polygons.length;

        for (var i = 0; i < plen; i++) {
            _gmap.removeOverlay(polygons[i]);
        }
    }
    
    
    /* Marker and Info Window plotting */
    function _get_first_id(markers) {
        var id = 0;
        for (i in markers) {
            id = i;
            break;
        }
        
        return id;
    }
    
    function _make_markers(items) {
        var markers = {};

        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            var type = item.rtype;

            if (item['mtype'] == 'cluster') {
                var marker = _make_cluster_marker(item, type);
                markers[item.id] = {item: item, marker: marker};
            }
            if (item['mtype'] == 'item') {
                var marker       = _make_single_marker(item, type);
                markers[item.id] = {item: item, marker: marker};
            }
            if (item['mtype'] == 'result') {
                var marker       = _make_result_marker(item, type);
                markers[item.id] = {item: item, marker: marker};
            }
            if (item['mtype'] == 'selected') {
                var marker       = _make_selected_marker(item, type);
                markers[item.id] = {item: item, marker: marker};
            }
        }
        
        return markers;
    }
    
    function _init_hotspot_add(e, type) {
        var center = _gmap.getCenter();
        var zoom   = _gmap.getZoom();
        var item   = {
            id            : 0,
            rtype         : type,
            step          : 'name',
            view          : 'home',
            geo_locations : {},
            name          : '',
            street        : '',
            city          : '',
            zip           : '',
            lat           : '',
            lng           : '',
			o_lat		  : '',
			o_lng		  : ''	  
        };

        var marker = _make_hotspot_marker(item, center);
        _gmap.addOverlay(marker);

        item.o_lat = marker.getPoint().lat();
		item.o_lng = marker.getPoint().lng();
		
        _show_hotspot_balloon({}, item, marker);

        _hotspot = {item: item, marker: marker};
    }
    
    function _init_hotspot_handlers() {
        $('#hotspot_balloon_wrapper input').
        focus(function() {
            var original_text = $(this).attr('rel');
        
            if (!original_text) {
                return false;
            }
        
            if ($(this).val() == original_text) {
                $(this).val('');
            }
        }).
        blur(function() {
            var original_text = $(this).attr('rel');
        
            if (!original_text) {
                return false;
            }
        
            if ($(this).val() == '') {
                $(this).val(original_text);
            }
        });

        $('#hotspot_balloon_wrapper form').submit(function() {
            $(window).trigger('all::hotspot::form::submitted', [this]);
            
            return false;
        });

        $('#hotspot_pos_form_method').change(function() {
            var val = $(this).val();
        
            $(window).trigger('all::hotspot::pos::method::changed', [val]);

            return false;
        });

        $('#cancel_add_hotspot').click(function() {
            $(window).trigger('all::hotspot::cancel::clicked', []);

            return false;
        });

        $('#hotspot_pos_form input[@type=reset]').click(function() {
            $(window).trigger('all::hotspot::pos::method::address::reset', []);
            
            return false;
        });
    }

    function _move_hotspot(lat, lng) {
        _hotspot.item.view = 'drag';
        _gmap.closeExtInfoWindow();

        /*
        _gmap.removeOverlay(_hotspot.marker);
        var item        = _hotspot.item;            
        var marker      = _make_hotspot_marker(item, new GLatLng(lat, lng));
        _hotspot.marker = marker;
        _gmap.addOverlay(marker);
        */
            
        _hotspot.marker.setPoint(new GLatLng(lat, lng));
        _set_map_center(lat, lng, 15, '');
        _show_hotspot_balloon({}, _hotspot.item, _hotspot.marker);
    }

	function _hasHotspotExceedDragLimit(lat, lng) {
		if(!_hotspot){
			return;
		}

		var newPos;
		if(lat == null || lng == null){
			newPos = _hotspot.marker.getPoint();
		}else{
			newPos = new GLatLng(lat, lng);  
		}

		var origPos = new GLatLng(_hotspot.item.o_lat, _hotspot.item.o_lng); 
		var meter = newPos.distanceFrom(origPos);
		var metersPerMile = 1609.344;
		var milesDragged = meter/metersPerMile;
		var maxDraggedDistance = 10;

		if(milesDragged > maxDraggedDistance){
			alert("You've move the hotspot beyond the allowed distance.")
			return true;
		}
		return false;
	}
	
	function _resetHotspotPos() {
		_hotspot.item.street  = '';
        _hotspot.item.city    = '';
        _hotspot.item.zip     = '';
		_move_hotspot(_hotspot.item.o_lat, _hotspot.item.o_lng);
	}
    
    function _cancel_hotspot_add(e) {
        _gmap.closeExtInfoWindow();
        _gmap.removeOverlay(_hotspot.marker);
        _hotspot = null;
    }
    
    function _make_single_marker(item, type) {
        var classes = 'single ' + type + '_single';

        if (controller.hasCampingFilter() && item.raurl && item.raurl != '') {
            classes += ' rasite_single';
        }

        var html = _templates['item_marker'].process({
            item      : item,
            type      : type,
            classes   : classes
        });

        var marker = new LabeledMarker(new GLatLng(item.lat, item.lng), {
            icon: _make_small_icon(),
            labelText: html,
            labelOffset: new GSize(-6, -10)}
        );

        GEvent.addListener(marker, 'click', function() {
            $(_messenger).trigger('app::result::clicked', [item.rtype, item.id]);

            return false;
        });

        return marker;
    }
    
    function _make_result_marker(item, type) {
        var class_name = (controller.hasCampingSearch() == true && item.rtype == 'fac' && item.raurl && item.raurl != '') ?
            'result_single_rasite' :
			'result_single';
			
        var html = _templates['result_marker'].process({
            item       : item,
            class_name : class_name 
        });

        var marker = new LabeledMarker(new GLatLng(item.lat, item.lng), {
            icon: _make_small_icon(),
            labelText: html,
            labelOffset: new GSize(-6, -10)}
        );

        GEvent.addListener(marker, 'click', function() {
            $(_messenger).trigger('app::result::clicked', [item.rtype, item.id]);

            return false;
        });

        return marker;
    }
    
    function _make_selected_marker(item, type) {
        var html = _templates['selected_marker'].process({
            item      : item
        });

        var marker = new LabeledMarker(new GLatLng(item.lat, item.lng), {
            icon: _make_large_icon(),
            labelText: html,
            labelOffset: new GSize(-26, -30)}
        );

        GEvent.addListener(marker, 'click', function() {
            $(_messenger).trigger('app::result::clicked', [item.rtype, item.id]);

            return false;
        });

        return marker;
    }
    
    function _make_hotspot_marker(item, latlng) {
        var html = _templates['hotspot_marker'].process({
            item      : item
        });
        
        var image = '/assets/images/google_map/icon_hotspot.png';
        if (item.rtype == 'water') {
            image = '/assets/images/google_map/icon_water.png';
        }
        else if (item.rtype == 'facility') {
            image = '/assets/images/google_map/icon_facility.png';
        }

        var icon        = new GIcon(); 
        icon.image      = image;
        icon.shadow     = '/assets/images/google_map/tmf_gmap_shadow.png';
        icon.iconSize   = new GSize(27, 30);
        icon.shadowSize = new GSize(45, 30);
        icon.iconAnchor = new GPoint(12, 30);
        icon.infoWindowAnchor = new GPoint(-37, 9);
        
        var marker = new GMarker(latlng, {
            icon: icon,
            draggable: true
        });
        
        GEvent.addListener(marker, 'click', function() {
            $(_messenger).trigger('all::hotspot::marker::clicked', [item, marker]);

            return false;
        });

        GEvent.addListener(marker, 'dragstart', function() {
            item.view = 'drag';
            _gmap.closeExtInfoWindow();

            return false;
        });

        GEvent.addListener(marker, 'dragend', function() {
            _show_hotspot_balloon({}, item, marker);

            return false;
        });

        return marker;
    }

    function _make_cluster_marker(item, type) {
        var classes = 'cluster ' + type + '_cluster';

        var html = _templates['cluster_marker'].process({
            item      : item,
            type      : type,
            classes   : classes
        });

        var marker = new LabeledMarker(new GLatLng(item.lat, item.lng), {
            icon: _make_small_icon(),
            labelText: html,
            labelOffset: new GSize(-6, -10)}
        );

        GEvent.addListener(marker, 'click', function() {
            //var zoom = _gmap.getZoom();
            //var lat  = item.lat;
            //var lng  = item.lng;
            
            //_set_map_center(lat, lng, zoom, _curr_map_type);
        });

        return marker;
    }

    function _show_details_balloon(e, rtype, id) {
        var url  = _settings['base_url'] + _settings['balloon_path'];
        var args = {
            rtype: rtype,
            id   : id
        };
        $.get(url, args, function(res) {
            var o  = null;
            try {
                o = eval( '(' + res + ')' );
    
                if (!o['success'])
                    o['success'] = false;

            } catch(e) {o = {sucess: false}}

            if (o['success'] === false) {
                $(_messenger).trigger('sp::search::canceled', ['Server error']);
                return false;
            }
            
            var species = [];
            for (var j = 0; j < o.data.inhabitants.length; j++) {
                var fish_id   = o.data.inhabitants[j];
                var name = _settings['fish_names']['id' + fish_id];

                species.push(name);
            }
            species.sort();
            o.data.inhabitants = species;
            
            var amenities = [];
            for (var j = 0; j < o.data.amenities.length; j++) {
                var amenity_id   = o.data.amenities[j];
                var name = _settings['amenity_names']['id' + amenity_id];

                amenities.push(name);
            }
            amenities.sort();
            o.data.amenities = amenities;

            var data   = _cache.get(id);
            if (data) {
                o.data.mtype = data.item.mtype;
                o.data.label = data.item.label;
            }

            var markers  = _make_markers([o.data]);
            var marker   = markers[id].marker;
            var item     = markers[id].item;

            var template_name = '';
            if (rtype == 'loc') {
                template_name = 'loc_item_balloon';
            }
            else if (rtype == 'fac' && item.raurl && item.raurl != '' && (controller.hasCampingFilter()||controller.hasCampingSearch())) {
                template_name = 'rasite_item_balloon';
            }
            else if (rtype == 'fac') {
                template_name = 'fac_item_balloon';
            }
            else if (rtype == 'bof') {
                template_name = 'bof_item_balloon';
            }
            else if (rtype == 'hot') {
                template_name = 'hot_item_balloon';
            }
                
            var amenities = [];
            $.each(item.amenities, function(i,e) {
                if (!amenity_image_map[e]) { return true; }
                
                amenities.push({
                    name  : e,
                    image : amenity_image_map[e]
                });
            });
            item.amenities = amenities;

            item.pretty_address = _make_pretty_address(item);
            var html = _templates[template_name].process({
                item     : item,
                base_url : _settings['base_url']
            });

            setTimeout(function() {
                if (data) {
                    _gmap.removeOverlay(data.marker);
                }
                
                _cache.set(id, markers[id]);
                _show_markers(markers);

                marker.openExtInfoWindow(
                    _gmap,
                    "custom_window",
                    html,
                    {beakOffset: 0}
                );
            }, 100);
        });
        
        return false;
    }
    
    function _show_hotspot_balloon(e, item, marker) {
	    /*
         * Check if user has dragged 
		 * beyond distance allowed
		 */
		if(_hasHotspotExceedDragLimit()){
			_resetHotspotPos();
			return false;
		}
		
        /* 
         * Unbind event handlers: can't use livequery because GMap
         * cancels events before they bubble-up to the top object
         */
        $('#hotspot_balloon_wrapper input').unbind('focus').unbind('blur');
        $('#hotspot_balloon_wrapper form').unbind('submit');
        $('#hotspot_pos_form_method').unbind('change');
        $('#cancel_add_hotspot').unbind('click');
        $('#hotspot_pos_form input[@type=reset]').unbind('click');
        _gmap.closeExtInfoWindow();
        
        var content_html = '';
        
        if (item.step == 'name') {
            content_html = _templates['hotspot_name_home'].process({
                item       : item,
                labels     : {name: 'Name'}
            });
        }
        else if (item.step == 'pos') {
            var fields_html = _templates['hotspot_pos_' + item.view].process({
                item        : item,
                labels      : {name: 'Name', street: 'Street Address:', city: 'City:', zip: 'ZIP:', lat: 'Latitude:', lng: 'Longitude:'}
            });

            content_html    = _templates['hotspot_pos_wrapper'].process({
                item        : item,
                labels      : {name: 'Name', street: 'Street Address:', city: 'City:', zip: 'ZIP:', lat: 'Latitude:', lng: 'Longitude:'},
                fields_html : fields_html,
                base_url    : _settings['base_url']
            });
        }
        
        if (content_html == '') {
            return false;
        }
            
        var html = _templates['hotspot_balloon'].process({
            item    : item,
            content : content_html
        });
            
        marker.openExtInfoWindow(
            _gmap,
            "custom_window",
            html,
            {beakOffset: 0}
        );
        
        /* 
         * Bind event handlers: can't use livequery because GMap
         * cancels events before they bubble-up to the top object
         */
        _init_hotspot_handlers();
        return false;
    }

    function _show_markers(markers) {
        for (i in markers) { 
            if(typeof markers[i] != 'object'){
                continue;
            }
            _gmap.addOverlay(markers[i].marker);
        }

        if (_show_labels == false) {
            $('.single .marker_top_label', _root_el).hide();
        }
    }

    function _hide_markers(markers) {
        for (i in markers) {
            if(typeof markers[i] != 'object'){
                continue;
            }
            _gmap.removeOverlay(markers[i].marker);
        }
    }

    function _make_small_icon() {
        var icon        = new GIcon(); 
        icon.image      = '/assets/images/blank.gif';
        icon.shadow     = '/assets/images/google_map/tmf_gmap_single_shadow.png';
        icon.iconSize   = new GSize(1, 1);
        icon.shadowSize = new GSize(30, 30);
        icon.iconAnchor = new GPoint(-7, 10);

        icon.infoWindowAnchor = new GPoint(-20, 13);
        
        return icon;
    }

    function _make_large_icon() {
        var icon        = new GIcon(); 
        icon.image      = '/assets/images/blank.gif';
        icon.shadow     = '/assets/images/google_map/tmf_gmap_cluster_shadow.png';
        icon.iconSize   = new GSize(1, 1);
        icon.shadowSize = new GSize(30, 30);
        icon.iconAnchor = new GPoint(10, 22);

        icon.infoWindowAnchor = new GPoint(-19, 7);

        return icon;
    }
    
    
    /* View methods */
    function _show_home(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;
        
        var data = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };
        _update_map_type(d);
        _update_show_labels(d);
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type)
        
        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }

    function _show_bof_search(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;

        var data = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };
        _update_map_type(d);
        _update_show_labels(d);
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type)

        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }

    function _show_loc_search(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;
        
        var data = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };
        _update_map_type(d);
        _update_show_labels(d);
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type)

        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }

    function _show_fac_search(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;
        
        var data = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };
        _update_map_type(d);
        _update_show_labels(d);
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type)

        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }

    function _show_fish_search(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;
        
        var data = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };
        _update_map_type(d);
        _update_show_labels(d);
        
        var def = {
            lat  : _state.centroid[1],
            lng  : _state.centroid[0],
            zoom : _state['zoom'],
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type)

        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }

    function _show_results(e, d, q) {
        _init_map_ui();
        _clear_map();
        if (d.total == 1) {
            return false;
        }

        _selected_id = 0;

        var markers = _make_markers(d['data']);
        setTimeout(function() {
            for (id in markers) {
                if(typeof id != 'string'){
                    continue;
                }
                _cache.set(id, markers[id]);
            }
            _show_markers(markers);
        }, 100);


        var args = _controller.explodeQueryString(q);
        var data = {
            lat  : args.mp_lat,
            lng  : args.mp_lng,
            zoom : args.mp_z,
            type : args.mp_t
        };
        _update_map_type(args);
        _update_show_labels(args);

        var sw_bound    = d['sw_bound'];
        var ne_bound    = d['ne_bound'];
        var center_zoom = _get_center_zoom(sw_bound, ne_bound); 
        var center      = center_zoom[0];
        var def = {
            lat  : center_zoom[0].lat(),
            lng  : center_zoom[0].lng(),
            zoom : center_zoom[1],
            type : _curr_map_type
        }
        /* In case of 0 results */
        if (def.lat == 0 || def.lng == 0) {
            def.lat  = _state.centroid[1];
            def.lng  = _state.centroid[0];
            def.zoom = _state['zoom'];
        }

        var mc = _make_map_conf(data, def);
        _set_map_center(mc.lat, mc.lng, mc.zoom, mc.type);

        if(_settings['geowake']){
            _init_geowake();    
        }
        return false;
    }
    
    function _show_explore(e, d) {
        _init_map_ui();
        _clear_map();
        _selected_id = 0;

        var args = {
            lat  : d.mp_lat,
            lng  : d.mp_lng,
            zoom : d.mp_z,
            type : d.mp_t
        };

        var def = {
            lat  : d.se_lat,
            lng  : d.se_lng,
            zoom : d.se_zoom,
            type : _curr_map_type
        };
        
        var mc = _make_map_conf(args, def);
		//alert(mc.lat+", "+mc.lng);
		var adjLat = mc.lat + 0.01;
		var adjLng = mc.lng - 0.015;
		
        _set_map_center(adjLat, adjLng, mc.zoom, mc.type);

        _update_map_type(d);
        _update_show_labels(d);

        if(_settings['geowake']){
            _init_geowake();    
        }
        if (!d['se_id']) {
            return false;
        }

        var rtype      = d['se_rtype'] || 'loc';
        _selected_id   = d['se_id'];

        var data = _cache.get(_selected_id);

        /* Load item details */
        if (!data) {
            var url  = _settings['base_url'] + _settings['balloon_path'];
            var args = {
                rtype: rtype,
                id: _selected_id
            };
            $.get(url, args, function(res) {
                var o  = null;
                try {
                    o = eval( '(' + res + ')' );
    
                    if (!o['success'])
                        o['success'] = false;

                } catch(e) {o = {sucess: false}}

                if (o['success'] === false) {
                    $(_messenger).trigger('sp::search::canceled', ['Server error']);
                    return false;
                }

                o.data.label = '';
                o.data.mtype = 'selected';
                var markers  = _make_markers([o.data]);

                setTimeout(function() {
                    _cache.set(_selected_id, markers[_selected_id]);
                    _show_markers(markers);
                    if (!_gmap.getBounds().contains(new GLatLng(o.data.lat, o.data.lng))) {
                        return;
                    }
                    _show_details_balloon({}, o.data.rtype, _selected_id);
                }, 100);
            });
        }
        else {
            data.item.label = '';
            data.item.mtype = 'selected';
            
            _gmap.removeOverlay(data.marker);
            var markers  = _make_markers([data.item]);

            setTimeout(function() {
                _cache.set(_selected_id, markers[_selected_id]);
                _show_markers(markers);
                if (!_gmap.getBounds().contains(new GLatLng(data.item.lat, data.item.lng))) {
                    return;
                }
                _show_details_balloon({}, data.item.rtype, data.item.id);
            }, 100);
        }

        return false;
    }

    /* Public Functions and Variables */
    return {
        /**
        * Init function
        *
        * @method init
        * @public
        */
        init: function() {
            _controller.setMapPanel(this);
            
            /* Parse _templates */
            _templates['item_marker']         = _parser('item_marker_tpl');
            _templates['result_marker']       = _parser('result_marker_tpl');
            _templates['selected_marker']     = _parser('selected_marker_tpl');
            _templates['hotspot_marker']      = _parser('hotspot_marker_tpl');
            _templates['cluster_marker']      = _parser('cluster_marker_tpl');
            
            _templates['loc_item_balloon']    = _parser('loc_item_balloon_tpl');
            _templates['bof_item_balloon']    = _parser('bof_item_balloon_tpl');
            _templates['fac_item_balloon']    = _parser('fac_item_balloon_tpl');
            _templates['rasite_item_balloon'] = _parser('rasite_item_balloon_tpl');
            _templates['hot_item_balloon']    = _parser('hot_item_balloon_tpl');
            _templates['hotspot_balloon']     = _parser('hotspot_balloon_tpl');
            
            _templates['hotspot_name_home']   = _parser('hotspot_name_home_tpl');
            _templates['hotspot_pos_wrapper'] = _parser('hotspot_pos_wrapper_tpl');
            _templates['hotspot_pos_drag']    = _parser('hotspot_pos_drag_tpl');
            _templates['hotspot_pos_address'] = _parser('hotspot_pos_address_tpl');
            _templates['hotspot_pos_gps']     = _parser('hotspot_pos_gps_tpl');
            
            
            /* Initialize local vars */
            _sid      = _settings.curr_state;
            _state    = _settings.states[_sid];
            _root_el  = $(_root_selector)[0];
            
            // This is a big map: zoom one step further
            ++_state['zoom'];

            _load_state_polygons();
            _init_map_ui();


            /* Register message responders */
            $(_messenger).bind('view::home',    _show_home);
            $(_messenger).bind('view::bof',     _show_bof_search);
            $(_messenger).bind('view::loc',     _show_loc_search);
            $(_messenger).bind('view::fac',     _show_fac_search);
            $(_messenger).bind('view::fish',    _show_fish_search);
            $(_messenger).bind('view::explore', _show_explore);

            $(_messenger).bind('mp::labels::toggle::changed', _toggle_labels);
            $(_messenger).bind('mp::gwmarkers::toggle::changed', _toggle_gwmarkers);
            $(_messenger).bind('mp::gwcharts::toggle::changed', _toggle_gwcharts);
            $(_messenger).bind('mp::infowindow::close::clicked', _close_info_window);
            $(_messenger).bind('mp::state::overlay::loaded', _toggle_state_overlay);
            $(_messenger).bind('mp::nautical::toggle::changed', _toggle_nautical_info);
            $(_messenger).bind('all::open::clicked', _create_full_screen_control);
            $(_messenger).bind('all::close::clicked', _destroy_full_screen_controls);
            $(_messenger).bind('all::view::dispatched', _show_hide_help);
            $(_messenger).bind('all::hotspot::add::clicked', _init_hotspot_add);
            $(_messenger).bind('all::hotspot::cancel::clicked', _cancel_hotspot_add);
            $(_messenger).bind('all::hotspot::marker::clicked', _show_hotspot_balloon);
            $(_messenger).bind('all::hotspot::marker::view::changed', _show_hotspot_balloon);
			$(_messenger).bind('all::hotspot::zoom::change', function(e, zoom) {       
			   _gmap.setZoom(zoom);
			   return false;
			});
            $(_messenger).bind('all::hotspot::pos::method::address::reset', function(e) {
                _hotspot.item.geo_locations = {};
                
                $(_messenger).trigger('all::hotspot::marker::view::changed', [_hotspot.item, _hotspot.marker]);
                
                return false;
            });
            $(_messenger).bind('all::hotspot::pos::method::changed', function(e, method) {
                _hotspot.item.view = method;
                
                $(_messenger).trigger('all::hotspot::marker::view::changed', [_hotspot.item, _hotspot.marker]);
                
                return false;
            });
            $(_messenger).bind('all::hotspot::form::submitted', function(e, form) {
                var name = $(form).attr('name');

                if (name == 'hotspot_name_form') {
                    _process_hotspot_name_form(form);
                }
                if (name == 'hotspot_pos_form') {
                    _process_hotspot_pos_form(form);
                }
                
                return false;
            });

            $(_messenger).bind('sp::search::received', _show_results);
            $(_messenger).bind('app::result::clicked', _show_details_balloon);
            $(_messenger).bind('all::result::clicked', function(e, lat, lng, zoom) {
                _gmap.closeExtInfoWindow();
                _set_map_center(lat, lng, zoom, '');
            });
            $(_messenger).bind('sp::explore::received', function(e, d) {
                _clear_map();
                var bmarkers = _make_markers(d.bof);
                var fmarkers = _make_markers(d.fac);
                var hmarkers = _make_markers(d.hot);
                setTimeout(function() {
                    /* Show selected marker */
                    if (_selected_id) {
                        var data   = _cache.get(_selected_id);
                        if (data) {
                            _show_markers([data]);
                        }
                    }

                    /* Show page marker */
                    for (id in bmarkers) { 
                        _cache.set(id, bmarkers[id]);
                    }
                    for (id in fmarkers) { 
                        _cache.set(id, fmarkers[id]);
                    }
                    for (id in hmarkers) {
                        _cache.set(id, hmarkers[id]);
                    }

                    _show_markers(bmarkers);
                    _show_markers(fmarkers);
                    _show_markers(hmarkers);
                }, 100);
            
                return false;
            });


            /* Local DOM responders */
            
        },
        /**
        * 
        *
        * @method getState
        * @public
        */
        getState: function() {
            var zoom   = _gmap.getZoom() || _state['zoom'] || 7;
            var center = _gmap.getCenter();
            var type   = _wtypes[_gmap.getCurrentMapType().getName()];
            var lat    = center ? center.lat() : _state['centroid'][1] || 0;
            var lng    = center ? center.lng() : _state['centroid'][0] || 0;
            var sil    = (_show_labels) ? 1:0;

            return  'mp_z='   + zoom + '&' +
                    'mp_t='   + type + '&' +
                    'mp_lat=' + lat  + '&' +
                    'mp_lng=' + lng  + '&' +
                    'mp_l='   + sil;
        }
    };
}(window, controller, settings, cache);

$(function() {
    // adjust size
    if (settings.embedded === true) {
        var wh = $(window).height();
        var hh = $('#header').height();
        var fh = $('#newsFeed').height();
        var ww = $(window).width();
        var vh = wh - hh - fh;
        var vw = ww-20;
        
        $('#viewport').width(vw).height(vh);
        $('#contentInner').width(vw-230-20);
    }
        
    map_panel.init();
});



