
ClimateWatch.Maps = { }

ClimateWatch.Maps.OpenLayers = Class.create();

ClimateWatch.Maps.OpenLayers.prototype = {
    /** Projections. */
    googleProjection: new OpenLayers.Projection("EPSG:900913"),
    wgs84Projection: new OpenLayers.Projection("EPSG:4326"),
    /** Default options. */
    defaultOptions: {typeControl: true, scaleControl: false, zoomControl: true},
    
    /** The OL map. */
    olMap: null,
    
    initialize: function(div, options) {
        Event.observe(window, 'unload', this.destroy.bind(this));

        var opts = Object.clone(this.defaultOptions);
        if (Object.isUndefined(options)) {
            options = {};
        }
        Object.extend(opts, options);
        
        var options = { projection: this.googleProjection,
                        displayProjection: this.wgs84Projection,
                        units: "m",
                        maxResolution: 156543.0339,
                        maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34,
                                                         20037508.34, 20037508.34) };
                                                         
        this.olMap = new OpenLayers.Map(div, options);
            
        var gphy = new OpenLayers.Layer.Google("Google Physical", {type: G_PHYSICAL_MAP, sphericalMercator: true});
        var gmap = new OpenLayers.Layer.Google("Google Streets", {sphericalMercator: true});
        var ghyb = new OpenLayers.Layer.Google("Google Hybrid", {type: G_HYBRID_MAP, sphericalMercator: true});
        var gsat = new OpenLayers.Layer.Google("Google Satellite", {type: G_SATELLITE_MAP, sphericalMercator: true});
        this.olMap.addLayers([gphy, gmap, ghyb, gsat]);
        
        this.olMap.zoomToExtent(new OpenLayers.Bounds(113,-40,127,-25).transform(this.olMap.displayProjection, this.olMap.projection));
        this.olMap.addControl(new OpenLayers.Control.LayerSwitcher());
    },
    
    clickHandler: function(map, callbackObject, overlay, latLng) {
        callbackObject.clickHandler({map: map, coordinate: latLng});
    },
    
    addKMLOverlay: function(url, options) {
        var opts = {zoomToExtent: false, showInfo: true, showInfoFn: null, title: "KML Layer",
                    format: OpenLayers.Format.KML, formatOptions: { extractStyles: true, extractAttributes: true},
                    projection: this.olMap.displayProjection};

        Object.extend(opts, Object.isUndefined(options) ? { } : options);
        
        var kmlLayer = new OpenLayers.Layer.GML(opts.title, url, opts);

        this.olMap.addLayer(kmlLayer);
        if (opts.zoomToExtent === true) {
            this.olMap.zoomToExtent(kmlLayer.getExtent());
        }
        
        if (opts.showInfo === true) {
            new ClimateWatch.Maps.OpenLayers.Selector(this.olMap, kmlLayer, opts.showInfoFn);
        }
    },
    
    addImageOverlay: function(url, bounds, size, options) {
        var opts = {zoomToExtent: true, title: "Image Layer", isBaseLayer: false, boundsInGoogle: false};
        if (Object.isUndefined(options)) {
            options = {};
        }
        Object.extend(opts, options);
        
        var googleBounds = bounds;
        if (!opts.boundsInGoogle) {
            googleBounds = bounds.transform(this.wgs84Projection, this.googleProjection);
        }
        opts.projection = this.googleProjection;
        var imgLayer = new OpenLayers.Layer.Image(opts.title, url, googleBounds, size, opts);
        this.olMap.addLayer(imgLayer);
        //if (opts.zoomToExtent === true) {
        //    map.zoomToExtent(imgLayer.getExtent());
        //}
        
        //map.events.register("zoomend", "")
    },
	
	recenter: function() {
		this.olMap.setCenter(new OpenLayers.LonLat(135.75, -25.34).transform(this.olMap.displayProjection, this.olMap.projection), 3);
	},
    
    destroy: function() {
        if (this.olMap != null) {
            this.olMap.destroy();
        }
        this.olMap = null;
    }
}

ClimateWatch.Maps.OpenLayers.SingleMarker = OpenLayers.Class(OpenLayers.Control, {
    defaultHandlerOptions: {
        single: true,
        //double: false,
        pixelTolerance: 0,
        stopSingle: true,
        stopDouble: false
    },
    cwMap: null,
    layer: null,
    icon: null,
    marker: null,
    postMark: new Array(),
    
    /*
     * Map is an instance of ClimateWatch.Map.OpenLayers
     */
    initialize: function(map, options) {
        this.cwMap = map;
        
        this.handlerOptions = OpenLayers.Util.extend({}, this.defaultHandlerOptions);
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.handler = new OpenLayers.Handler.Click(this, {'click': this.clickHandler.bind(this)}, this.handlerOptions);
        
        this.layer = new OpenLayers.Layer.Markers("SinglePoints", {showInLayerControl: false, projection: this.cwMap.olMap.displayProjection});
        this.cwMap.olMap.addLayer(this.layer);
        
        var size = new OpenLayers.Size(21, 25);
        var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
        this.icon = new OpenLayers.Icon("/" + ClimateWatch.servletName + "/js/ol/img/marker-gold.png", size, offset);
        
        this.cwMap.olMap.addControl(this);
        this.activate();
    },
    
    clickHandler: function(e) {
        var lonlat = this.cwMap.olMap.getLonLatFromViewPortPx(e.xy);
        this.addMarker(lonlat);
    },
    
    addMarker: function(lonlat) {
        this.clearMarker();
        this.marker = new OpenLayers.Marker(lonlat, this.icon.clone());
        this.layer.addMarker(this.marker);
        if (this.cwMap.olMap.projection.getCode() != this.cwMap.wgs84Projection.getCode()) {
            lonlat.transform(this.cwMap.olMap.projection, this.cwMap.wgs84Projection);
        }
       this.doPostMark(lonlat.lon, lonlat.lat);
    },
    
    clearMarker: function() {
        if (this.marker != null) {
            this.layer.removeMarker(this.marker);
        }
    },
    
    addPostMark: function(f) {
        this.postMark[this.postMark.length] = f;
    },
    
    doPostMark: function(lon, lat) {
        var param = {lat: lat, lon: lon};
        this.postMark.each(function(f) {
            f(param);
        });
    }
});

ClimateWatch.Maps.OpenLayers.PolygonMarker = Class.create();
ClimateWatch.Maps.OpenLayers.PolygonMarker.prototype = {
    layer: null,
    control: null,
    
    initialize: function(map, options) {
        this.options = {layerTitle: "Draw Polygon", showInLayerControl: false,
                        featureAddedCallback: Prototype.emptyFunction};
        Object.extend(this.options, options || {});
        
        this.layer = new OpenLayers.Layer.Vector(this.options.layerTitle);
        map.olMap.addLayer(this.layer);
        
        var drawOptions = {handlerOptions: {freehand: true}, featureAdded: this.featureAdded.bind(this)};
        this.control = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Polygon, drawOptions);
        map.olMap.addControl(this.control);
    },
    
    activate: function(active) {
        if (active) {
            this.control.activate();
        } else {
            this.control.deactivate();
        }
    },
    
    featureAdded: function(feature) {
        var layer = feature.layer;
        var polygon = feature.geometry;
        polygon.transform(layer.projection, this.wgs84Projection);
        this.options.featureAddedCallback({layer: layer, geometry: polygon});
    }
}

ClimateWatch.Maps.OpenLayers.Selector = Class.create();
ClimateWatch.Maps.OpenLayers.Selector.prototype = {
    map: null,
    layer: null,
    generateFn: null,
    selector: null,
    selectedFeature: null,
    
    initialize: function(map, layer, generate) {
        this.layer = layer;
        this.map = map;
        this.generateFn = generate;
        if (typeof (this.generateFn) != "function") {
            this.generateFn = this.showName.bind(this);
        }
        
        this.selector = new OpenLayers.Control.SelectFeature(this.layer, 
                                                             {onSelect: this.onFeatureSelect.bind(this), 
                                                              onUnselect: this.onFeatureUnselect.bind(this)});
        this.map.addControl(this.selector);
        this.selector.activate();
    },
    
    onFeatureSelect: function(feature) {
        selectedFeature = feature;
        var popup = new OpenLayers.Popup.FramedCloud("chicken", 
                                                 feature.geometry.getBounds().getCenterLonLat(),
                                                 new OpenLayers.Size(200, 200),
                                                 this.generateFn(feature),
                                                 null, true, this.onPopupClose.bind(this));
        feature.popup = popup;
        this.map.addPopup(popup);
        this.selectedFeature = feature;
    },
    
    showName: function(feature) {
        return "<div style='font-size:.8em'>" + feature.attributes.name + "</div>";
    },
    
    onFeatureUnselect: function(feature) {
        this.map.removePopup(feature.popup);
        feature.popup.destroy();
        feature.popup = null;
    },
    
    onPopupClose: function(evt) {
        this.selector.unselect(this.selectedFeature);
    }
}
