(function() {

    var SEARCH_MODE  = 'search';
    var BROWSE_MODE  = 'browse';
    
    var UPDATE_STATE = 'update';
    var PASS_STATE   = 'pass';

    window.map        = null;
    var _templates = {};
    var _cmarkers  = {};
    var _vpolygons = [];
    var _cpolygons = {};
    var _mode      = SEARCH_MODE;
    var _state     = UPDATE_STATE;

    //var _mn_vertices = [{'lat':"46.7054",'lng':"-92.0147"},{'lat':"46.6671",'lng':"-92.294"},{'lat':"46.0756",'lng':"-92.294"},{'lat':"45.7196",'lng':"-92.8691"},{'lat':"45.5772",'lng':"-92.8855"},{'lat':"45.4402",'lng':"-92.6445"},{'lat':"44.7501",'lng':"-92.8089"},{'lat':"43.9943",'lng':"-91.4341"},{'lat':"43.7752",'lng':"-91.2424"},{'lat':"43.5014",'lng':"-91.2151"},{'lat':"43.5014",'lng':"-91.3684"},{'lat':"43.5014",'lng':"-96.451"},{'lat':"45.2978",'lng':"-96.451"},{'lat':"45.6045",'lng':"-96.8563"},{'lat':"45.9332",'lng':"-96.5606"},{'lat':"46.333",'lng':"-96.5989"},{'lat':"46.6561",'lng':"-96.8015"},{'lat':"47.6091",'lng':"-96.8563"},{'lat':"48.1458",'lng':"-97.1411"},{'lat':"48.6826",'lng':"-97.0973"},{'lat':"49.0002",'lng':"-97.2287"},{'lat':"49.0002",'lng':"-95.153"},{'lat':"49.3836",'lng':"-95.153"},{'lat':"49.3727",'lng':"-94.9558"},{'lat':"49.3234",'lng':"-94.8189"},{'lat':"48.7428",'lng':"-94.6436"},{'lat':"48.6278",'lng':"-93.8385"},{'lat':"48.5183",'lng':"-93.7947"},{'lat':"48.6333",'lng':"-92.9567"},{'lat':"48.5402",'lng':"-92.6336"},{'lat':"48.4635",'lng':"-92.7103"},{'lat':"48.4142",'lng':"-92.4583"},{'lat':"48.2225",'lng':"-92.3707"},{'lat':"48.3594",'lng':"-92.053"},{'lat':"48.0418",'lng':"-91.5656"},{'lat':"48.2444",'lng':"-90.8864"},{'lat':"48.0911",'lng':"-90.7495"},{'lat':"48.0144",'lng':"-89.4898"},{'lat':"47.5543",'lng':"-90.87"},{'lat':"46.7876",'lng':"-92.0914"}];
    var _mn_vertices = [{'lat':45.26135531683856, 'lng':-92.79190063476562},{'lat':44.67841867818858, 'lng':-92.79190063476562},{'lat':44.67841867818858, 'lng':-93.61587524414062},{'lat':45.26135531683856, 'lng':-93.61587524414062}];
    var _mn_polygon  = new GPolygon(make_points(_mn_vertices));
    var _mn_bound    = _mn_polygon.getBounds();

    $(function() {
        $('#search-submit').val('Go!').attr('disabled', false);
    
    
        /* Templates */
        var _parser = TrimPath.parseDOMTemplate;
        _templates['search_results_pager_box']  = _parser('search_results_pager_box_tpl');
        _templates['search_results_box']        = _parser('search_results_box_tpl');
        _templates['map_info_window']           = _parser('map_info_window_tpl');
        _templates['intro_box']                 = _parser('intro_box_tpl');
    
        /* Ajax indicator */
        $('#ajax-indicator').ajaxStart(function() {
            $(this).show();
        });
        $('#ajax-indicator').ajaxStop(function() {
            $(this).hide();
        });
    
    
        /* Google map */
        init_map();


        /* Show intro */
        showSearch();
    });
    
    /* Tabs */
    $('#tabs li').live('click', function() {
        $('#tabs li').removeClass('active');
        $(this).addClass('active');
    
        var tab = $(this).attr('rel');
        
        if (tab == BROWSE_MODE) {
            showBrowse();
        }
        else {
            showSearch();
        }
    
        return false;
    });
            
    /* Pagination */
    $('ul.pager li').live('click', function() {
        var page = $('a', this).attr('rel');
    
        $('#search-page').val(page);
        $('#search-form').submit();
    
        return false;
    });
            
    /* Search */
    $('#search-submit').livequery('click', function() {
        $('#search-page').val(1);
        $('#search-topic_id').val('');
        $('#search-library_id').val('');
        $('#search-form').submit();
    
        return false;
    });
    
    $('#search-form').livequery('submit', function() {
        search_maps(this);
    
        return false;
    });
    
    
    /* Search result list/map bindings */
    $('#search_results_list li').live('click', function() {
        var key = $(this).attr('rel');
        
        if (!key) {
            return false;
        }
        
        $('#search_results_list li').removeClass('selected').removeClass('hover');
        $(this).addClass('selected');
        
        var item = _cmarkers[key];
        item.m.openInfoWindowHtml(item.h);
        
        return false;
    });
    
    $('#search_results_list li').live('mouseover', function() {
        var key = $(this).attr('rel');
        
        if (!key) {
            return false;
        }
       
        $('#search_results_list li').removeClass('hover');
        $(this).addClass('hover');
        
        //show_polygon(key);
        
        return false;
    });
    
    $('#search_results_list li').live('mouseout', function() {
        var key = $(this).attr('rel');
        
        if (!key) {
            return false;
        }
       
        $('#search_results_list li').removeClass('hover');
        
        clear_polygons();
        
        return false;
    });
    
    $('#refinery-content').live('submit', function() {
        var $selects = $('#results-panel').find('select');
        var stopic   = $selects.filter('.topics').val();
        var slibrary = $selects.filter('.libraries').val();
    
        $('#search-topic_id').val(stopic);
        $('#search-library_id').val(slibrary);
    
        $('#search-page').val(1);
        $('#search-form').submit();
            
        return false;
    });
    
    /* Show/Hide refinery form */
    $('#refinery-toggle').live('click', function() {
        $('#refinery-content').toggle();
        
        return false;
    });

    function init_map() {
        if (!GBrowserIsCompatible()) {
            return false;
        }
            
        var types = [C_AERIAL_MAP, G_NORMAL_MAP, G_HYBRID_MAP, G_PHYSICAL_MAP];
        var opts  = {mapTypes: types};
        map       = new GMap2(document.getElementById('map-canvas'), opts);
        
        map.setCenter(new GLatLng(40, -95), 4);
        map.enableScrollWheelZoom();
    
        map.addControl(new GMapTypeControl());
        map.addControl(new GLargeMapControl());
        map.setMapType(G_PHYSICAL_MAP);
        
        /* Hack: */
        setTimeout(function() {
            var button = getButtonElement(map, 'Aerial');
            
            if (!button) {
                return;
            }
            
            var map_bound = map.getBounds();

            if (!map_bound.intersects(_mn_bound) || map.getZoom() < 8) {
                $(button).hide().css('margin-right', '10px');
            }
        }, 500);
        
        GEvent.addListener(map, 'maptypechanged', function() {
            var name = map.getCurrentMapType().getName();
    
            if (name == 'Aerial') {
                window.location = 'http://map.lib.umn.edu/mhapo/';
            }
        });
        
        GEvent.addListener(map, "infowindowbeforeclose", function() {
            var sys = $('#map_info_window').attr('rel');
            
            if (!sys) {
                return false;
            }
            
            $('#search_results_list li').filter('[rel=sys_' + sys + ']').removeClass('selected');
        });
        
        GEvent.addListener(map, "infowindowopen", function() {
           _state = PASS_STATE;
        });
        
        GEvent.addListener(map, "infowindowclose", function() {
           _state = UPDATE_STATE;
        });
        
        GEvent.addListener(map, "dragstart", function() {
            map.closeInfoWindow();
        });
        
        GEvent.addListener(map, "zoomend", function() {
            _state = UPDATE_STATE;
            map.closeInfoWindow();
        });
        
        GEvent.addListener(map, "moveend", function() {
            if (_mode == BROWSE_MODE && _state == UPDATE_STATE) {
                browse_maps();
            }
            
            var button = getButtonElement(map, 'Aerial');

            if (!button) {
                return;
            }

            var map_bound = map.getBounds();

            if (map_bound.intersects(_mn_bound) && map.getZoom() >= 8) {
                $(button).show();
            }
            else {
                $(button).hide();
            }
        });
    }
    
    function make_points(input) {
        var out = [];
        
        for (var i = 0; i < input.length; i++) {
            var lat = parseFloat(input[i]['lat']);
            var lng = parseFloat(input[i]['lng']);
            
            out.push(new GLatLng(lat, lng));
        }
    
        /* Close the polygon */
        var lat = parseFloat(input[0]['lat']);
        var lng = parseFloat(input[0]['lng']);
        out.push(new GLatLng(lat, lng));

        return out;
    }
    
    function getButtonElement(map, label) {
        var button = null;
    
        $('div', map.getContainer()).each(function() {
            if ($(this).text() == label && $(this).children().length > 0) {
                button = this;
            }
        });
    
        return button;
    }
    
    function showBrowse() {
        $('#results-panel').hide();
        $('#search-form-wrapper').hide();
        $('#messages').show();
        $('#map-canvas').css('width', '998px');
    
        map.closeInfoWindow();
        map.clearOverlays();
        map.checkResize();
        
        _mode = BROWSE_MODE;
        browse_maps();
    }
    
    function showSearch() {
        $('#results-panel').show();
        $('#search-form-wrapper').show();
        $('#messages').hide();
        $('#map-canvas').css('width', '760px');
        
        map.closeInfoWindow();
        map.clearOverlays();
        map.checkResize();
        
        _mode = SEARCH_MODE;
        
        var intro_html = _templates['intro_box'].process({});
        $('#results-panel').html(intro_html);
    }
    
    /* This searches the map */
    function search_maps(form) {
        if ($('input[name=keyterm]', form).val() == '') {
            return false;
        }
        
        /* Ajax indicator */
        $('#search-submit').val('Searching...').attr('disabled', true);
    
        var url = $(form).attr('action');
        var q   = $(form).serialize();
    
        url += '?' + q;
        $.get(url, function(res) {
            $('#results-panel').html();
            map.clearOverlays();
    
            var o  = null;
            try {
                o = eval( '(' + res + ')' );
        
                if (!o['success']) {
                    o['success'] = false;
                }
    
            } catch(e) {o = {sucess: false}}
    
            if (o['success'] === false) {
                alert('Server error');
                return false;
            }
    
            _cmarkers  = {};
            var bounds = new GLatLngBounds();
            for(idx in o['maps']) {
                var html  = _templates['map_info_window'].process({
                    item : o['maps'][idx]
                });
                        
                var lat     = o['maps'][idx]['lat'];
                var lng     = o['maps'][idx]['lng'];
                var key     = 'sys_' + o['maps'][idx].sys;
                var center  = new GLatLng(parseFloat(lat), parseFloat(lng));
                var marker  = new GMarker(center);
        
                bounds.extend(center);
    
                var nw      = new GLatLng(parseFloat(o['maps'][idx]['lat1']), parseFloat(o['maps'][idx]['lng1']));
                var ne      = new GLatLng(parseFloat(o['maps'][idx]['lat1']), parseFloat(o['maps'][idx]['lng2']));
                var se      = new GLatLng(parseFloat(o['maps'][idx]['lat2']), parseFloat(o['maps'][idx]['lng2']));
                var sw      = new GLatLng(parseFloat(o['maps'][idx]['lat2']), parseFloat(o['maps'][idx]['lng1']));
                var square  = [nw, sw, se, ne, nw];
                var polygon = new GPolygon(square, "#FF6E00", 2, 1, "#ff0000", 0.2);
    
                GEvent.addListener(marker, "mouseover", GEvent.callbackArgs(marker, function(key) {
                    $('#search_results_list li').removeClass('hover');
                    $('#search_results_list li').filter('[rel=' + key + ']').addClass('hover');
                    $('#results-panel').scrollTo($('li[rel=' + key + ']'), 100);
        
                    show_polygon(key);
    
                    return false;
                }, key));

                GEvent.addListener(marker, "mouseout", function() {
                    $('#search_results_list li').removeClass('hover');
                    
                    clear_polygons();
    
                    return false;
                });
    
                GEvent.addListener(marker, "click", GEvent.callbackArgs(marker, function(key) {
                    var item = _cmarkers[key];
                    item.m.openInfoWindowHtml(item.h);
    
                    $('#search_results_list li').removeClass('selected').removeClass('hover');
                    $('#search_results_list li').filter('[rel=' + key + ']').addClass('selected');
                    $('#results-panel').scrollTo($('li[rel=' + key + ']'), 100);
    
                    return false;
                }, key));
    
                _cmarkers[key]  = {m: marker, h: html};
                _cpolygons[key] = polygon;
                map.addOverlay(marker);
            }

            var t     = o['meta']['subtotal'];
            var p     = o['meta']['page'];
            var l     = o['meta']['length'];
            var pager = _make_pager(t, p, l);
    
            var pager_html = _templates['search_results_pager_box'].process({
                pager : pager,
                total : o['meta']['total'],
                query : o['meta']['query'],
                page  : p
            });
            
            var clusters = {
                topics:{
                    selected:o.clusters.topics.selected,
                    list:[{n:'--- Any Topic ---', v:''}]
                },
                libraries:{
                    selected:o.clusters.libraries.selected,
                    list:[{n:'--- Any Library ---', v:''}]
                }
            };
            
            for (var i in o.clusters.topics.list) {
                var topic = o.clusters.topics.list[i];
                clusters.topics.list.push({
                    n: topic.name + ' (' + topic.cnt + ')',
                    v: topic.id
                });
            }
            
            for (var i in o.clusters.libraries.list) {
                var library = o.clusters.libraries.list[i];
                clusters.libraries.list.push({
                    n: library.name + ' (' + library.cnt + ')',
                    v: library.id
                });
            }
        
            var panel_html = _templates['search_results_box'].process({
                maps    : o['maps'],
                pager   : pager_html,
                clusters: clusters,
                total   : o['meta']['total']
            });
        
            $('#results-panel').html(panel_html);

            var zoom   = map.getBoundsZoomLevel(bounds);
            var center = bounds.getCenter();
    
            if (zoom > 13) {
                zoom = 13;
            }
    
            if (o['maps'].length > 0) {
                map.setCenter(center, zoom);
            }
            $('#results-panel').scrollTo({top:'0'}, 100);

            /* Enable button */
            $('#search-submit').val('Go!').attr('disabled', false);
    
            return;
        });
    }
    
    /* Browse the map */
    function browse_maps() {
        var url = 'browse.json.php';
        
        var ne = map.getBounds().getNorthEast();
        var sw = map.getBounds().getSouthWest();
    
        url += '?wlng=' + sw.lng() + '&elng=' + ne.lng() + '&slat=' + sw.lat() + '&nlat=' + ne.lat();
        
        $.get(url, function(res) {
            $('#results-panel').html();
            map.clearOverlays();
    
            var o  = null;
            try {
                o = eval( '(' + res + ')' );
        
                if (!o['success']) {
                    o['success'] = false;
                }
    
            } catch(e) {o = {sucess: false}}
    
            $('#messages').html('');
            if (o['success'] === false) {
                if (o['msg'] == 'Too many results') {
                    $('#messages').html('Too many results. Please zoom in.');
                }
                else {
                    alert('Server error');
                }
            
                return false;
            }
    
            _cmarkers  = {};
            for(idx in o['maps']) {
                var html  = _templates['map_info_window'].process({
                    item : o['maps'][idx]
                });
                        
                var lat     = parseFloat(o['maps'][idx]['lat']);
                var lng     = parseFloat(o['maps'][idx]['lng']);
                var key     = 'sys_' + o['maps'][idx].sys;
                var center  = new GLatLng(lat, lng);
                var marker  = new GMarker(center);
    
                var nw      = new GLatLng(parseFloat(o['maps'][idx]['lat1']), parseFloat(o['maps'][idx]['lng1']));
                var ne      = new GLatLng(parseFloat(o['maps'][idx]['lat1']), parseFloat(o['maps'][idx]['lng2']));
                var se      = new GLatLng(parseFloat(o['maps'][idx]['lat2']), parseFloat(o['maps'][idx]['lng2']));
                var sw      = new GLatLng(parseFloat(o['maps'][idx]['lat2']), parseFloat(o['maps'][idx]['lng1']));
                var square  = [nw, sw, se, ne, nw];
                var polygon = new GPolygon(square, "#FF6E00", 2, 1, "#ff0000", 0.2);
    
                GEvent.addListener(marker, "mouseover", GEvent.callbackArgs(marker, function(key) {
                    show_polygon(key);
                    return false;
                }, key));
    
                GEvent.addListener(marker, "mouseout", function() {
                    clear_polygons();
                    return false;
                });
    
                GEvent.addListener(marker, "click", GEvent.callbackArgs(marker, function(key) {
                    var item = _cmarkers[key];
                    item.m.openInfoWindowHtml(item.h);
    
                    return false;
                }, key));
    
                _cmarkers[key]  = {m: marker, h: html};
                _cpolygons[key] = polygon;
                map.addOverlay(marker);
            }
            
            return;
        });
    }
    
    function clear_polygons() {
        for (idx in _vpolygons) {
            map.removeOverlay(_vpolygons[idx]);
        }
        
        _vpolygons = [];
    }
    
    function show_polygon(key) {
        var polygon = _cpolygons[key];
    
        map.addOverlay(polygon);
        _vpolygons.push(polygon);
    }
            
    function _make_pager(t, p, l) {
        t = parseInt(t);
        p = parseInt(p);
        l = parseInt(l);
            
        var pager_middle = Math.ceil(5 / 2);
        var pager_first  = p - pager_middle + 1;
        var pager_last   = p + 6 - pager_middle;
        var pager_max    = Math.ceil(t / l);
        var i            = pager_first;
    
        if (pager_max < 2) {
            return [];
        }
    
        if (pager_last > pager_max) {
            i = i + (pager_max - pager_last);
            pager_last = pager_max;
        }
        if (i <= 0) {
            pager_last = pager_last + (1 - i);
            i = 1;
        }
        
        var pager = [];
    
        if (p > 1) {
            pager.push({page: (p - 1), label: '&laquo; Prev', prev: true});
        }
        for (; i <= pager_last && i <= pager_max; i++) {
            var active = (i == p) ? true : false;
            pager.push({page: i, label: i});
        }
        if (p < pager_max) {
            pager.push({page: (p + 1), label: 'Next &raquo;', next: true});
        }
            
        return pager;
    }
})();
 

