/*
 * Copyright 2007 Rob Newman <rlnewman@ucsd.edu>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This script uses Mike Purvis' LabeledMarker Class (copyright intact)
 * and some code by Pamela Fox of the Google Maps API Team. All attributions
 * are in the code where required by the license.
 *
 * The purpose of this script to determine which markers have the same station
 * code name, and if there is more than one at a location, to create child nodes
 * around the marker. These child nodes can be toggled on or off based on a
 * GEvent handler.
 *
 * The idea was to try and replicate the Google Earth behavior when there is more
 * than one sample at a location (such as a Panoramio photo). The line animation is 
 * much better in that than in this code.
 *
 */

var map, manager, mystas = {}, exclusion = [ 'LVA2', 'SCI2' ], gminimap, multiple = 0, expanded ;
var centerLat = 33.3, centerLon = -116.8, startZoom = 9 ;
var markerGroups = {} ;
var display = false ;
var urlPath = 'http://eqinfo.ucsd.edu/~rnewman/howtos/maps/images/' ;

var icon = new GIcon() ;
icon.image = urlPath+'station_icon.gif' ;
icon.iconSize = new GSize(32,32) ;
icon.iconAnchor = new GPoint(16,16) ;
icon.infoWindowAnchor = new GPoint(25,7);

var subIcon = new GIcon() ;
subIcon.image = urlPath+'sub_station_icon.gif' ;
subIcon.iconSize = new GSize(22,22) ;
subIcon.iconAnchor = new GPoint(11,11) ;
subIcon.infoWindowAnchor = new GPoint(25,7);

/* 
 * Extend array object to include in_array function 
 */

Array.prototype.in_array = function(datum, strict) {
    if (strict) function equals(a,b) { return a === b }
    else function equals(a,b) { return a == b }
    for (var i in this) {
        if (equals(this[i], datum)) return true;
    }
    return false;
}

/*
 * v2.77: GMarker show, hide, and isHidden = Quick & Easy Marker Toggling!
 * http://googlemapsapi.blogspot.com/2007/04/v277-gmarker-show-hide-and-ishidden.html
 */

function toggleGroup(type) {
    for( var i in markerGroups[type] ) {
        var thisMarker = markerGroups[type][i]["nodePoint"] ;
        var thisPolyline = markerGroups[type][i]["nodeLine"] ;
        if( thisMarker.isHidden() ) {
            thisMarker.show() ;
            thisPolyline.show() ;
        } else {
            thisMarker.hide();
            thisPolyline.hide() ;
        }
    } 
}

/*
 * createMarker function
 */

function createMarker( point, title, children, nodes ) {
    var point = point || new GPoint( 0,0 );
    var title = title || false ;
    var children = children || false ;
    var nodes = nodes || false ;

    var markerOpts = {} ;

    if( children == true ) {
        markerOpts = {
            "icon": subIcon,
            "clickable": true,
            "labelText": title,
            "labelOffset": new GSize(-16, -8)
        };
        var imageMouseOver = urlPath+'sub_station_icon_mouseover.gif' ;
        var imageMouseOut = urlPath+'sub_station_icon.gif' ;
        var marker = new GMarker( point, markerOpts ) ;
    } else {
        markerOpts = {
            "icon": icon,
            "clickable": true,
            "labelText": title,
            "labelOffset": new GSize(-16, -8)
        };
        var imageMouseOver = urlPath+'station_icon_mouseover.gif' ;
        var imageMouseOut = urlPath+'station_icon.gif' ;
        var marker = new LabeledMarker( point, markerOpts ) ;
    }


    GEvent.addListener( marker, "mouseover", function() {
        marker.setImage( imageMouseOver ) ;
    }) ;

    GEvent.addListener( marker, "mouseout", function() {
        marker.setImage( imageMouseOut ) ;
    }) ;

    GEvent.addListener( marker, "infowindowclose", function() {
        marker.setImage( imageMouseOut ) ;
    }) ;


    if( nodes != false ) {

        GEvent.addListener( marker, "click", function() {
            if( display == false ) {

                var pt = map.fromLatLngToDivPixel( point ) ;
                var angle = 360/nodes['stas'].length ;
                var radius = 50 ; // radius in px

                markerGroups[title] = [] ;

                for( var x=0; x<nodes['stas'].length; x++ ) {

                    var pointRatio = x/nodes['stas'].length ;
                    var xSteps = Math.cos( pointRatio*2*Math.PI ) ;
                    var ySteps = Math.sin( pointRatio*2*Math.PI ) ;
                    var newPt = new Object() ;

                    newPt.x = pt.x + xSteps * radius ;
                    newPt.y = pt.y + ySteps * radius ;

                    var poi = map.fromDivPixelToLatLng( newPt ) ;

                    var polyline = new GPolyline([point, poi], "#FFFFFF", 2, 1 ) ;

                    var subMarker = createMarker( poi, nodes['stas'][x], true ) ; // self-refer

                    map.addOverlay( subMarker ) ;
                    map.addOverlay( polyline ) ;

                    var mynode = {} ;

                    mynode = {
                        "staname": nodes['stas'][x],
                        "nodePoint": subMarker,
                        "nodeLine": polyline
                    }
                    markerGroups[title].push( mynode ) ; // add to visible group
                }

                display = true ;

            } else {
                toggleGroup( title ) ;
                display = false ;
            }
        }) ;
    } else {
        GEvent.addListener( marker, "click", function() {
            marker.openInfoWindowHtml( 'Station:'+markerOpts.labelText ) ;
        });
    }

    return marker ;
}

/*
 * loadStations function
 */

function loadStations () {
    GDownloadUrl( 'stations.xml', function( data, responseCode ) {
        if( responseCode == 200 ) {
            var stations = GXml.parse( data ) ;
            var markers = stations.documentElement.getElementsByTagName("station") ;
            for( var i=0; i<markers.length; i++ ) {
                var name = markers[i].getAttribute('name') ;
                var lat = GXml.value( markers[i].getElementsByTagName('lat')[0] ) ;
                var lng = GXml.value( markers[i].getElementsByTagName('lon')[0] ) ;
                var point = new GLatLng( lat, lng ) ; 

                stacode_match = /^[A-Za-z]+/ ; // Matches any non-digit character
                int_match = /[0-9]$/ ; // Matches any digit character
                var stacode = stacode_match.exec( name ) ;

                if( node = int_match.exec( name ) && !exclusion.in_array( name ) ) {
                    var lblText = stacode[0] ;
                } else {
                    var lblText = name ;
                }

                var dups = {} ; // New object for associative array

                dups = {
                    "staname": name,
                    "location": point
                } ;

                if( !mystas[lblText] ) {
                    mystas[lblText] = [] ;
                }
                mystas[lblText].push( dups ) ;

            }
            plotStations( mystas ) ;
       }
    }) ;
}

/*
 * plotStations function
 */

function plotStations( stationObj ) {

    for( var x in stationObj ) {
        if( stationObj[x].length > 1 ) {
            var duplicatedStas = [] ;
            for( var y=0; y<stationObj[x].length; y++ ) { // Make new array for stations with same locations
                duplicatedStas.push( stationObj[x][y]['staname'] ) ;
            }
            var marker = createMarker( stationObj[x][0]['location'], x, false, { 'stas': duplicatedStas } ) ;
        } else {
            var marker = createMarker( stationObj[x][0]['location'], x, false ) ;
        }

        map.addOverlay( marker ) ;
    }

}

function init() {

    map = new GMap(document.getElementById("googlemap")) ;

    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());

    gminimap = new GOverviewMapControl(new GSize(100,100));
    map.addControl(gminimap);

    map.setCenter(new GLatLng( centerLat, centerLon ), startZoom, G_HYBRID_MAP);
    map.enableDoubleClickZoom() ;
    map.enableScrollWheelZoom() ;

    manager = new GMarkerManager( map ) ;

    // Restrict range of zoom levels
    var mt = map.getMapTypes() ;
    for( var j=0; j<mt.length; j++ ) { 
        mt[j].getMaximumResolution = function() { return 10 ; }
    }

    loadStations() ;

}

window.onload = init;
window.onunload = GUnload;
