/*

This javascript file loads the necessary libraries from Google,
then fetches the data and template data, and creates the map.

Basic configuration should be done in the HTML file that points
to this file.  There, you can define:

* data and template files to use
* which data columns should be used for name, type, lat, and lng
* legend size, colors, and labels for the different types of sites
* which columns to display as filters (search)

Keith Jenkins
kgj2@cornel.edu
2009-03-19

*/

var maptable = new Object();
maptable.origtitle = document.title;

google.load("maps", "2");
google.load("jquery", "1.3.1");
google.setOnLoadCallback(function() {

    if (!GBrowserIsCompatible()) {
        $("#map").html("Sorry, you're browser isn't compatible with Google Maps.");
    }

    var map = new google.maps.Map2(document.getElementById("map"));
    map.setCenter(new google.maps.LatLng(42.6, -76.3), 6);
    map.setUIToDefault();
    map.setMapType(G_PHYSICAL_MAP);

    // ADD BOUNDARIES
    for (var i=0; i<maptable.boundaries.length; i++) {
        map.addOverlay(new GGeoXml(maptable.boundaries[i]));
    }

    // FETCH TEMPLATE AND DATA
    $.get(maptable.files.template, gotTemplate, 'text');

    function gotTemplate(html) {
        maptable.template = html;
        $.get(maptable.files.data, gotData, 'text');
    }

    // STORE THE ORIGINAL WEBPAGE CONTENT
    $('#info').data('orig', $('#info').html());


    function gotData(data) {
        // INGEST THE DATA
        // First line of table should contain column names

        var rows = data.split("\n");
        var columnNames = rows[0].replace(/[\x0d\x0a]/, '').split("\t");
        maptable.sites = Array();
        for (var i=1; i<rows.length; i++) {
            var site = { __id:i }; // always add an internal ID
            var cols = rows[i].replace(/[\x0d\x0a]/, '').split("\t");
            if (cols<columnNames.length) continue; // skip non-data rows
            for (var c=0; c<cols.length; c++) {
                var val = cols[c].replace(/^"(.*)"$/, "$1"); // remove quotes from text-formatted cells
                site[columnNames[c]] = val;
            }
            maptable.sites[i] = site;
        }
        createMap();
    }

    function createMap() {
        for (var id in maptable.sites) {
            var s = maptable.sites[id];
            if (s[maptable.meta.lat]!=0 && s[maptable.meta.lng]!=0) { // make sure coordinates are non-zero
                var latlng = new GLatLng(s[maptable.meta.lat], s[maptable.meta.lng]);
                var marker = createMarker(latlng, s);
                map.addOverlay(marker);
                maptable.sites[id]['__marker'] = marker;

                // Expand the bounds so that it contains all the points
                if (!bounds) {
                    var bounds = new GLatLngBounds(latlng, latlng);
                }
                else {
                    bounds.extend(latlng);
                }
            }
            else { // delete ungeoreferenced points
                delete maptable.sites[id];
            }
        }
        maptable.bounds = bounds;
        map.setCenter(bounds.getCenter(),map.getBoundsZoomLevel(bounds));
        showLegend();
        showList();
        interpretHash();
        showFilterForm();
    }

    function createMarker(latlng, s) {
        // Calculate the marker type
        var color = legendTypeAttr(s[maptable.meta.type], 'color');
        var size = legendTypeAttr(s[maptable.meta.type], 'size');
        var flatIcon = MapIconMaker.createFlatIcon({ width:size, height:size, primaryColor:color });
        var marker = new GMarker(latlng, {icon:flatIcon});
        marker['__data'] = s;
        GEvent.addListener(marker,'click', function() {
            selectPoint(this.__data.__id);
        });
        return marker;
    }

    function debug(str) {
        $('body').append("<br />"+str);
    }

    function interpretHash() {
        // Examine the hash of the URL (after the '#')
        // if numeric, show the point for that ID
        // if var=val, filter accordingly
        map.closeInfoWindow();
        var hash = location.hash.substr(1);
        if (hash.search(/^\d+$/) > -1) { // id must be numeric
            // Show info for the current point (as specified in the URL hash)
            var id = hash;
            var s = maptable.sites[id];
            document.title = maptable.origtitle + ": " + s[maptable.meta.name];
            maptable.filter = { column:null, value:null };

            // Create info pop-up on map
            s.__marker.openInfoWindowHtml("<div class='balloon'><b>"+s[maptable.meta.name]+"</b></div>", {maxWidth:320});

            // Generate HTML for info pane
            var html = maptable.template;

            for (var c in s) {
                // escape regexp special characters
                var csafe = c.replace(/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
                var re = new RegExp('\\['+csafe+'\\]', 'g');
                if (s[c].length>0) {
                    if (s[c].substring(0,4)=='http') {
                        html = html.replace(re, s[c]);
                    }
                    else {
                        html = html.replace(re, '<span class="data">'+s[c]+'</span>');
                    }
                }
                else {
                    html = html.replace(re, '<span class="nodata"></span>');
                }
            }

            // Remove "nodata" lines, but only if there are no other "data" on the line
            var lines = html.split(/[\n\r]+/);
            html2 = '';
            for (var i=0; i<lines.length; i++) {
                var line = lines[i];
                if (line.search(/<span class="nodata"/)==-1 || line.search(/<span class="data"/)>-1) {
                    html2 += line + "\n";
                }
            }
            $('#info').html(html2);

            // Remove whole sections lacking data
            $('#info div').each(function(){
                if ($(this).find('span.data').length==0) {
                    $(this).remove();
                }
            });

            window.scroll(0,0); // scroll to top of page
        }
        else if (hash.search(/=/) > -1) {
            var c = hash.split('=');
            var column = c[0];
            var value = c[1];
            if (column && value) {
                document.title = maptable.origtitle + ": " + column + "=" + value;
                maptable.filter = { column:column, value:value };
                $('#info').html('Click a site to view the site info.');
                for (var id in maptable.sites) {
                    var s = maptable.sites[id]
                    var m = s['__marker'];
                    if (s[column]==value || column=='') {
                        m.show(); // show map marker
                        $('#list-'+id).show(); // show name in list
                        var latlng = new GLatLng(s[maptable.meta.lat], s[maptable.meta.lng]);
                        if (!bounds) {
                            var bounds = new GLatLngBounds(latlng, latlng);
                        }
                        else {
                            bounds.extend(latlng);
                        }
                    }
                    else {
                        m.hide(); // hide map marker
                        $('#list-'+id).hide(); // hide name in list
                    }
                }
                map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
            }
        }
        else { // Show everything
            document.title = maptable.origtitle;
            maptable.filter = { column:'', value:'' };
            $('#info').html('Click a site to view the site info.');
            for (var id in maptable.sites) {
                var m = maptable.sites[id]['__marker'];
                m.show();
                $('#list-'+id).show();
            }
            var b = maptable.bounds;
            map.setCenter(b.getCenter(), map.getBoundsZoomLevel(b));
        }
    }
    function legendTypeAttr(t, attr) {
        var l = maptable.legend;
        // See if legend attribute is defined for type t
        if (l[t]) {
            var v = l[t][attr];
            if (v!=null) return v;
        }
        // if not, try the legend default
        if (l['']) {
            var v = l[''][attr];
            if (v!=null) return v;
        }
        // always return something for the color attribute
        if (attr=='color') return '000000';
        return null;
    }

    function selectFilter() {
        var column = $('#filterColumn').val();
        var value = $('#filterValue').val();
        $('#info').html("Click a site to view the site info...");
        if (column && value) {
            var hash = '#' + column + "=" + value;
        }
        else {
            var hash = '#';
        }
        location.replace(location.href.replace(/#.*$/, '') + hash);
        window.setTimeout(interpretHash, 100);
    }

    function selectPoint(id) {
        $('#info').html($('#info').data('orig')).show();
        location.replace(location.href.replace(/#.*$/, '') + '#' + id);
        window.setTimeout(interpretHash, 100);
    }

    function showFilterForm() {
        var selectColumn = $("<select id='filterColumn'></select>");
        selectColumn.append("<option value=''>ALL SITES</option>");
        for (var i in maptable.filters) {
            selectColumn.append("<option>"+maptable.filters[i]+"</option>");
        }
        selectColumn.change(function(){
            $('#filterValue').parent().remove();
            var c = $(this).val();
            if (c=='') {
                selectFilter();
                return;
            }

            // get list of all values in this column
            var seen = Array();
            for (var i in maptable.sites) {
                var val = maptable.sites[i][c];
                if (val!='') seen[val] = 1;
            }
            var vals = Array();
            for (var k in seen) {
                vals.push(k);
            }
            vals.sort();

            var selectVal = $("<select id='filterValue'></select>");
            selectVal.append("<option></option>");
            for (var i in vals) {
                selectVal.append("<option>"+vals[i]+"</option>");
            }
            selectVal.change(selectFilter);
            $('#filter').append(' ');
            $("<span>... show:</span>").append(selectVal).appendTo('#filter');
        });
        $("<span>Search by:</span>").append(selectColumn).appendTo('#filter');
        if (!maptable.filter.column) {
            maptable.filter.column = maptable.filters[0];
            maptable.filter.value = null;
        }
        $('#filterColumn').val(maptable.filter.column).change();
        $('#filterValue').val(maptable.filter.value);
    }

    function showLegend() {
        var html = '';
        for (var t in maptable.legend) {
            var size = legendTypeAttr(t, 'size');
            var color = legendTypeAttr(t, 'color');
            var label = legendTypeAttr(t, 'label');
            if (label==null) label = t;
            html += "<img src='http://chart.apis.google.com/chart?cht=it&chs="+size+"x"+size+"&chco="+color+",000000ff,ffffff01&chl=&chx=000000,0&chf=bg,s,00000000&ext=.png' /> = "+label+"<br />";
        }
        $('#legend').html(html);
    }

    function showList() {
        $('#list').html("<ul></ul>");
        var list = Array();
        for (var id in maptable.sites) {
            var s = maptable.sites[id];
            list.push({id:id, name:s[maptable.meta.name], type:s[maptable.meta.type]});
        }
        function byName(a,b) {
            if (a['name'] < b['name']) return -1;
            else if (a['name'] > b['name']) return 1;
            else return 0;
        }
        list.sort(byName);
        for (var i in list) {
            var s = list[i];
            if (s) {
                var color = legendTypeAttr(s.type, 'color');
                var size = legendTypeAttr(s.type, 'size');
                $('#list ul').append("<li id='list-"+s.id+"'><img src='http://chart.apis.google.com/chart?cht=it&chs="+size+"x"+size+"&chco="+color+",000000ff,ffffff01&chl=&chx=000000,0&chf=bg,s,00000000&ext=.png' /><a href='#"+s.id+"'>"+s.name+"</a></li>");
            }
        }
        $('#list a').click(function(){
            // force links to show info
            var id = $(this).attr("href").replace(/^.*#/, ''); // beware: the href value varies depending on the browser!
            selectPoint(id);
        });
    }



});
