/* 
 * Copyright (C) 2008 Moritz Ringler
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
//Mospace namespace
if (Mospace == null || typeof(Mospace) != "object") { var Mospace = new Object();}
   
//Mospace.OpenLayersMap class
Mospace.OpenLayersMap = function(divid, options) {
    
    /* PRIVATE FIELDS */
    var map;
    /** a Boxes layer */
    var boxes;
    /** The map's projection */ 
    var epsg4326 = new OpenLayers.Projection("EPSG:4326");
    /** the number of zoomlevels of the map */
    var nz= 1;
    
    var defaulticon = new OpenLayers.Icon('http://gpstools.sf.net/js/markers/marker.png',
        new OpenLayers.Size(20, 34),
        null,
        function(size) {
            return new OpenLayers.Pixel(-10, -34);
        });
    
    /* PRIVATE METHODS */
    /** Creates the map's base layers */
    function createBaseLayers(baseLayer){
        var blayers = [];
        if(baseLayer.gmap){
            blayers.push(new OpenLayers.Layer.Google( 
                "Google Map" , {type: G_NORMAL_MAP,
                sphericalMercator: true }));
        }
        if(baseLayer.gsat){
            blayers.push(new OpenLayers.Layer.Google( 
                "Google Satellite" , {type: G_SATELLITE_MAP,
                sphericalMercator: true }));
        } 
        if(baseLayer.ghyb){
            blayers.push(new OpenLayers.Layer.Google( 
                "Google Hybrid" , {type: G_HYBRID_MAP,
                sphericalMercator: true }));
        }
        if(baseLayer.gterrain){
            blayers.push(new OpenLayers.Layer.Google( 
                "Google Terrain" , {type: G_PHYSICAL_MAP,
                sphericalMercator: true }));
        }
        if(baseLayer.msvemap){
            blayers.push(new OpenLayers.Layer.VirtualEarth( "MS Virtual Earth Map (buggy)", {
                    type: VEMapStyle.Road,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.msvesat){
            blayers.push(new OpenLayers.Layer.VirtualEarth( "MS Virtual Earth Satellite (buggy)", {
                    type: VEMapStyle.Aerial,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.msvehyb){
            blayers.push(new OpenLayers.Layer.VirtualEarth( "MS Virtual Earth Hybrid (buggy)", {
                    type: VEMapStyle.Hybrid,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.ymap){
            blayers.push(new OpenLayers.Layer.Yahoo( "Yahoo Map", {
                    type: YAHOO_MAP_REG,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.ysat){
            blayers.push(new OpenLayers.Layer.Yahoo( "Yahoo Satellite", {
                    type: YAHOO_MAP_SAT,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.yhyb){
            blayers.push(new OpenLayers.Layer.Yahoo( "Yahoo Hybrid", {
                    type: YAHOO_MAP_HYB,
                    sphericalMercator: true
            }));
        }
        if(baseLayer.osmmapnik){
            blayers.push(new OpenLayers.Layer.OSM.Mapnik("OpenStreetMap (Mapnik)", {
                    displayOutsideMaxExtent: true,
                    wrapDateLine: true
            }));
        }
        if(baseLayer.osmosmarender){
            blayers.push(new OpenLayers.Layer.OSM.Osmarender("OpenStreetMap (Osmarender)", {
                    displayOutsideMaxExtent: true,
                    wrapDateLine: true
            }));
        }
        if(baseLayer.osmcyclemap){
            blayers.push(new OpenLayers.Layer.OSM.CycleMap("OpenStreetMap (Cycle Map)", {
                    displayOutsideMaxExtent: true,
                    wrapDateLine: true
            }));
        }
        map.addLayers(blayers);
	for(var i = 0; i<blayers.length; i++){
            nz = Math.max(nz, blayers[i].numZoomLevels); 
	}
	
	var control = new OpenLayers.Control();
            OpenLayers.Util.extend(control, {
                draw: function () {
                    this.point = new Mospace.BoxHandler( control,
                        {"done": this.notice},
                        {keyMask: OpenLayers.Handler.MOD_SHIFT | OpenLayers.Handler.MOD_CTRL});
		    this.point.boxDivClassName = "myZoomBox";
                    this.point.activate();
                },

                notice: function (bounds) {
                    sides = bounds.toArray();
		    px1 = new OpenLayers.Pixel(sides[0], sides[1]);
		    px2 = new OpenLayers.Pixel(sides[2], sides[3]);
		    lonlat1 = fromMap(map.getLonLatFromPixel(px1));
		    lonlat2 = fromMap(map.getLonLatFromPixel(px2));
		    bb = {
			    west:lonlat1.lon,
			    south:lonlat1.lat,
			    east:lonlat2.lon,
			    north:lonlat2.lat
		    };
		    setCoordinateField(bb);
                }
            });

        
            map.addControl(control);
	    
	    var control = new OpenLayers.Control();
            OpenLayers.Util.extend(control, {
                draw: function () {
                    this.point = new Mospace.BoxHandler( control,
                        {"done": this.notice},
                        {keyMask: OpenLayers.Handler.MOD_SHIFT});
                    this.point.activate();
                },

                notice: function (bounds) {
                    sides = bounds.toArray();
		    px1 = new OpenLayers.Pixel(sides[0], sides[1]);
		    px2 = new OpenLayers.Pixel(sides[2], sides[3]);
		    lonlat1 = map.getLonLatFromPixel(px1);
		    lonlat2 = map.getLonLatFromPixel(px2);
		    bounds = new OpenLayers.Bounds();
		    bounds.extend(lonlat1);
		    bounds.extend(lonlat2);
                    map.zoomToExtent(bounds);
                }
            });

        
            map.addControl(control);

        return map;
    }
    
    /** Coordinate transformation: user to map */
    function toMap(position){
        return position.clone().transform(epsg4326, map.getProjectionObject());
    }
    
    /** Coordinate transformation: map to user */
    function fromMap(position){
        return position.clone().transform(map.getProjectionObject(), epsg4326);
    }
    
    /* PRIVILEGED METHODS */
    /** Adds a box to the map. */ 
    this.addBox = function(bb) {
        /* Lazily create and add marker layer. */
        if(boxes == null){
            boxes = new OpenLayers.Layer.Boxes( "Tile Borders", 
		    {
		    	    numZoomLevels: nz
		    } );
            map.addLayer(boxes);
        }
	var bounds = new OpenLayers.Bounds();
	bounds.extend(toMap(new OpenLayers.LonLat(bb.W, bb.S)));
	bounds.extend(toMap(new OpenLayers.LonLat(bb.E, bb.N)));
	box = new OpenLayers.Marker.Box(bounds);
	boxes.addMarker(box);
        return box;
    };
    
    /** Removes a marker from the map. */ 
    this.removeBoxFromMap = function(box){
        boxes.removeMarker(box);
    };
    
    /*
    Wrappers for map methods. 
    */ 
    this.getCenter = function(center, zoom) {
        return fromMap(map.getCenter());
    };
    
    this.setCenter = function(center, zoom) {
        map.setCenter(toMap(center.clone()));
    };
    
    this.setExtent = function(extent) {
        map.zoomToExtent(toMap(extent));
    };
    
    this.getExtent = function(extent) {
        return fromMap(map.getExtent());
    };
    
    this.getEventPosition = function(event) {
        return fromMap(map.getLonLatFromViewPortPx(event.xy));
    };
    
    this.getSize = function(){
        return map.getSize();
    };
    
    this.updateSize = function(){
        map.updateSize();
    };
    
    /* constructor proper */
    options = options || {};
    var args = {
        controls: options.controls || [
        new OpenLayers.Control.ArgParser(),
        new OpenLayers.Control.Attribution(),
        new OpenLayers.Control.LayerSwitcher(),
        new OpenLayers.Control.Navigation(),
        new OpenLayers.Control.PanZoomBar(),
        new OpenLayers.Control.ScaleLine()
        ],
        
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: epsg4326,
        units: "m",
        maxResolution: 156543.0339,
        maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
            20037508, 20037508.34)
    };
    map =  new OpenLayers.Map(divid, args);
    createBaseLayers(options.baselayers || { gmap: true } );
}

Mospace.OpenLayersMap.prototype.setBounds = function(bb) {
    var bounds = new OpenLayers.Bounds();
    bounds.extend(new OpenLayers.LonLat(bb.W, bb.S));
    bounds.extend(new OpenLayers.LonLat(bb.E, bb.N));
    this.setExtent(bounds);
    return bounds;
};


