/**
 * @author Johan
 */

/**
 * Google Maps API Interface
 * @param {Object} element
 */
var Map = Class.create({

        element: null,
        map: null,

        // polygons
        polygons: $A(),
        // drawn polygon
        drawn_polygons: $A(),
        
        // Default polygon style
        polygonStyle: $H({
                borderColor: '#000',
                borderWidth: 2,
                borderOpacity: 0.5,
                backgroundColor: '#60a6fd',
                backgroundOpacity: 0.2
        }),

        // markers
        markers: $A(),

        // center (GLatLng)
        center: null,
        // zoom level (int)
        zoom: 10,

        /**
         * Initialize the map
         * @param {Object} element
         */
        initialize: function(element) {
                
                this.element = element;
                
                // browser compatible?
                if(!GBrowserIsCompatible()) {
                        alert('Uw browser is niet compatible met Google Maps.');
                        return false;
                }
        
                // parse all data in the map element
                this.parseData();
        
                // load/apply the map
                this.map = new GMap2(this.element);
                this.map.addControl(new GSmallZoomControl());
                this.map.addControl(new GOverviewMapControl());
                this.map.addControl(new GMapTypeControl());
                this.setCenter(this.center, this.zoom);
        
                //this.element.select('svg').invoke('remove');
        
                // apply all data found in the element like poly's and markers.
                this.applyData();
                
                // save the position:
                // we can use this.returnToSavedPosition() to go back to the start.
                this.map.savePosition();
                // nasty:
                this.element.select('a, span').invoke('hide');
        },

        parseData: function() {
                // check for polygons
                this.element.select('ul.polygon').each(function(ul) {
                        this.addPolygon(ul);
                }.bind(this));

                // check for markers
                this.element.select('ul.markers li').each(function(li) {
                        this.addMarker(li);
                }.bind(this));

                // check for center parameter
                this.center = new GLatLng(51.704683,4.516754); //5
                if( (centerData = this.element.down('p.center') ) ) {
                        latlong = centerData.innerHTML.split(',');
                        this.center = new GLatLng(latlong[0], latlong[1]);
                        this.updatedCenter = true;
                }

                if ((zoomData = this.element.down('p.zoom'))) {
                        this.zoom = zoomData.innerHTML;
                }
        },

        applyData: function() {
        
                this.clearOverlays();
        
                // draw polygons:
                if(this.polygons.size() > 0) {
                        this.polygons.each(function(points) {
                                this.drawPolygon(points);
                        }.bind(this));
                }
                
                // draw markers:
                if(this.markers.size() > 0) {
                        this.markers.each(function(marker) {
                                this.map.addOverlay(marker);
                        }.bind(this));
                }
                
                // find center automagicly:
                if(!this.updatedCenter && this.drawn_polygons.size() > 0) {
                        var mapbounds = false;//this.map.getBounds();
                        this.drawn_polygons.each(function(polygon) {
                                var polybounds = polygon.getBounds();
                                // we start expanding the bounds of the first poly we find
                                // when all poly's fit in these bounds we center and zoom
                                // the map to these bounds.
                                if(!mapbounds) {
                                        mapbounds = polybounds;
                                }
                                if(!mapbounds.containsBounds(polybounds)) {
                                        mapbounds.extend(polybounds.getSouthWest());
                                        mapbounds.extend(polybounds.getNorthEast());
                                }
                        });
                        
                        this.map.setCenter(mapbounds.getCenter());
                        this.map.setZoom(this.map.getBoundsZoomLevel(mapbounds));

                } else {
                        // center is fixed by the <p class="center" /> element
                }
        },

        /**
         * Click event
         */
        click: function(overlay, latlng) {
                //var divXY = this.map.fromLatLngToDivPixel(latlng);
                this.map.addOverlay(new GMarker(latlng));
        },

        /**
         * Marker functions
         * ----------------
         * 
         * Add a marker
         */
        addMarker: function(li) {
                if((span = li.down('span'))) {
                        var text = span.innerHTML;
                        span.remove();
                }
                var latlong = li.innerHTML.split(',');
                var point = new GLatLng(latlong[0],latlong[1]);
                
                var icon = new GIcon(G_DEFAULT_ICON);

                switch(li.className) {
                        case 'ave':
                                icon.image = BaseURL+'/img/map-markers/map-logo-marker-ave.png';
                                icon.shadow = '';
                                icon.iconSize = new GSize(42, 40);
                                icon.iconAnchor = new GPoint(21, 40);
                        break;

                        case 'rehorst':
                                icon.image = BaseURL+'/img/map-markers/map-logo-marker-rehorst.png';
                                icon.shadow = '';
                                icon.iconSize = new GSize(42, 40);
                                icon.iconAnchor = new GPoint(21, 40);
                        break;
                }
                
                var marker = new GMarker(point, icon);
                if(text) {
                        GEvent.addListener(marker,"click", function() {
                                this.map.openInfoWindowHtml(point, text);
                        }.bind(this));  
                }
                
                this.markers.push(marker);
        },

        /**
         * Custom marker
         * @param {Object} ul
         */
        getIcon: function(color) {
                if(!color)
                        color = 'orange';

                var icon = new GIcon();
                icon.image = BaseURL+'/img/map-markers/mm_20_'+color+'.png';
                icon.shadow = BaseURL+'/img/map-markers/mm_20_shadow.png';
                icon.iconSize = new GSize(12, 20);
                icon.shadowSize = new GSize(22, 20);
                icon.iconAnchor = new GPoint(6, 20);
                icon.infoWindowAnchor = new GPoint(5, 1);
                return icon;
        },

        /**
         * Polygon functions
         * -----------------
         * 
         * Add a polygon
         */
        addPolygon: function(ul) {
                var points = $A();
                ul.select('li').each(function(li, index) {
                        points.push(li.innerHTML.split(','));
                }.bind(this));
                
                for(var i=0; i<points.size(); i++) {
                        points[i] = new GLatLng(points[i][0],points[i][1]);
                }

                // check if the polygon is closed. if not, close it.
                if(points.first().equals(points.last())) {
                        points.push(points.first());
                }

                var polygon = this.polygonStyle.merge($H({ 
                        points: points,
                        borderColor: '#F00'
                        // todo: get more style from style tag
                }));
                this.polygons.push(polygon);
        },

        /**
         * Draw a polygon
         * @param {Object} polygon
         */
        drawPolygon: function(polygon) {
                var polygon = new GPolygon(
                        polygon.get('points'),
                        polygon.get('borderColor'),
                        polygon.get('borderWidth'),
                        polygon.get('borderOpacity'),
                        polygon.get('backgroundColor'),
                        polygon.get('backgroundOpacity')
                );
                this.map.addOverlay(polygon);
                this.drawn_polygons.push(polygon);
        },

        /**
         * Center the map on the given polygon
         * @param {Object} polygon
         */
        centerPolygon: function(polygon) {
                
        },

        /**
         * Centers the map
         * @param {Long} lat
         * @param {Long} long
         * @param {Int} zoom
         */
        setCenter: function(centerPoint, zoom) {
                this.map.setCenter(centerPoint, parseFloat(zoom));
        },

        /**
         * Clears all overlays on the map 
         */
        clearOverlays: function() {
                this.map.clearOverlays();
        },

        /**
         * Returns to the saved position
         * This saved position is set when the map is fully loaded.
         */
        returnToSavedPosition: function() {
                this.map.returnToSavedPosition();
        }

});

var AdminMap = Class.create(Map, {
        // precision of points on the map:
        latlng_precision: 7,

        polygonPoints: $A(),

        centerInput: null,

        initialize: function($super, element) {
                $super(element);
                
                // center input:
                this.centerInput = new Element('input', { 'type': 'hidden', name: 'center', value: this.map.getCenter().toUrlValue(this.latlng_precision) });
                $('polygonPoints').appendChild(this.centerInput);
                // zoom input:
                this.zoomInput = new Element('input', { 'type': 'hidden', name: 'zoom', value: this.map.getZoom() });
                $('polygonPoints').appendChild(this.zoomInput);
                
                GEvent.addListener(this.map, "moveend", function() {
                this.centerInput.value = this.map.getCenter().toUrlValue(this.latlng_precision);
                        this.zoomInput.value = this.map.getZoom();
        }.bind(this));
                
                if((button = $('save-polygon')))
                        button.observe('click', this.savePolygon.bind(this));
                if((button = $('clear-overlays')))
                        button.observe('click', this.clearOverlays.wrap(function(proceed, event) {
                                event.stop(); // stop the event
                                this.polygonPoints = $A();
                                $('polygonPoints').select('input.area').invoke('remove');
                                proceed(); // call this.clearOverlays()
                        }).bind(this));
        },

        // apply admin specific data:
        applyData: function($super) {
                // apply other data:
                $super();
                // add the click event:
                var clickEvent = GEvent.bind(this.map, 'click', this, this.click);
        },

        // admin click event:
        click: function($super, overlay, latlng) {
                //var divXY = this.map.fromLatLngToDivPixel(latlng);
                $('save-polygon').enable();
                this.polygonPoints.push(latlng);
                this.map.addOverlay(new GMarker(latlng, this.getIcon('orange')));
        },

        savePolygon: function(event) {
                event.stop();
                // clear current overlays:
                this.clearOverlays();
                
                // close it:
                if(!this.polygonPoints.first().equals(this.polygonPoints.last())) {
                        this.polygonPoints.push(this.polygonPoints.first());
                }

                // save it:
                $('polygonPoints').select('input.area').invoke('remove');
                this.polygonPoints.each(function(point) {
                        var input = new Element('input', { 'type': 'hidden', name: 'area[]', className: 'area', value: point.toUrlValue(this.latlng_precision) });
                        $('polygonPoints').appendChild(input);
                });
                
                // create it:
                var polygon = this.polygonStyle.merge($H({ 
                        points: this.polygonPoints,
                        borderColor: '#F00'
                        // todo: get more style from style tag
                }));
                
                // draw it:
                this.drawPolygon(polygon);
        }

});

// todo: create method to convert rgb(#,#,#) notation to hex
Math.rgbToHex = function(r,g,b){
        return(r<<16 | g<<8 | b);
}

/**
 * The DOM Loaded event.
 * Fires when the DOM is fully loaded
 */
document.observe('dom:loaded', function() {
        $$('.map').each(function(element) {
                if(element.hasClassName('admin')) {
                        new AdminMap(element);
                } else {
                        new Map(element);
                }
        });
});
Event.observe(window, 'unload', function(event){ GUnload() });

