/*
 * Ext JS Library 2.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 * 
 * http://extjs.com/license
 */

/**
 * @author Shea Frederick
 */

Ext.namespace('Ext.ux');
 
/**
 *
 * @class GMapPanel
 * @extends Ext.Panel
 */
Ext.ux.GMapPanel = Ext.extend(Ext.Panel, {
	markerRegistry : {
	    markers: [],
	    count: 0            
	},
	
    initComponent : function(){
        
        var defConfig = {
            plain: true,
            zoomLevel: 3,
            yaw: 180,
            pitch: 0,
            zoom: 0,
            gmapType: 'map',
            border: false,
            geoAccuracyWarning: false
        };
        
        Ext.applyIf(this,defConfig);
        
        Ext.ux.GMapPanel.superclass.initComponent.call(this);        
    },

    afterRender : function(){
        var wh = this.ownerCt.getSize();
        Ext.applyIf(this, wh);
        
        Ext.ux.GMapPanel.superclass.afterRender.call(this);    
        
        if (this.gmapType === 'map')
            this.gmap = new GMap2(this.body.dom);
        
        if (this.gmapType === 'panorama')
            this.gmap = new GStreetviewPanorama(this.body.dom);
        
        GEvent.bind(this.gmap, 'load', this, this.onMapReady);
        
        if (typeof this.addControl == 'object' && this.gmapType === 'map')
            this.gmap.addControl(this.addControl);
        
        if (typeof this.setCenter === 'object') {
            if (typeof this.setCenter.geoCodeAddr === 'string'){
                this.setMapCenter(this.setCenter.geoCodeAddr,this.setCenter.marker);
            } else {
                if (this.gmapType === 'map'){
                    var point = new GLatLng(this.setCenter.lat,this.setCenter.lng);
                    this.gmap.setCenter(point, this.zoomLevel);
                }
/*
                if (this.setCenter.marker && typeof this.setCenter.marker === 'object'
                    && typeof point === 'object') {
                    this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear);
                }
*/
            }
            if (this.gmapType === 'panorama') {
                this.gmap.setLocationAndPOV(new GLatLng(this.setCenter.lat,this.setCenter.lng),
                    {yaw: this.yaw, pitch: this.pitch, zoom: this.zoom});
            }
        }

    },

    onMapReady : function(){
        this.addMarkers(this.markers);
        this.addMapControls();
        this.addMapTypes();
        this.addOptions();  
        if ( !this.largeSizer )
            this.largeSizer = new GLargeMapControl();
        if ( !this.smallSizer )
            this.smallSizer = new GSmallMapControl();
        this.currentSizer = this.largeSizer;
    },

    onResize : function(w, h){
        if (typeof this.getMap() == 'object') {
            this.gmap.checkResize.defer(10,this.gmap);
            if ( h < 265 ) {
                if ( this.currentSizer === this.largeSizer ) {
                    this.removeMapControl(this.largeSizer);
                    this.addMapControl(this.currentSizer = this.smallSizer);
                }
            } else {
                if ( this.currentSizer === this.smallSizer ) {
                    this.removeMapControl(this.smallSizer);
                    this.addMapControl(this.currentSizer = this.largeSizer);
                }
            }
        }
        Ext.ux.GMapPanel.superclass.onResize.apply(this,arguments);
    },
    
    setSize : function(w, h, animate){
        if (typeof this.getMap() == 'object')
            this.gmap.checkResize();
        Ext.ux.GMapPanel.superclass.setSize.apply(this, arguments);
    },

    getMap : function(){
        return this.gmap;
    },

    getCenter : function(){
        return this.getMap().getCenter();
    },

    getCenterLatLng : function(){
        var ll = this.getCenter();
        return { lat: ll.lat(), lng: ll.lng() };
    },

    addMarkers : function(markers) {
        if (Ext.isArray(markers)) {
            for (var i = 0; i < markers.length; i++) {
                var mkr_point = new GLatLng(markers[i].lat,markers[i].lng);
                this.addMarker(mkr_point,markers[i].marker,false,markers[i].setCenter, markers[i].listeners, markers[i]);
            }
        }
    },

    addMarker : function(point, marker, clear, center, listeners, marker_data){
        Ext.applyIf(marker,G_DEFAULT_ICON);

        var identity = marker_data.id;
        var marker_icon = marker_data.icon_image;
        var marker_shadow_icon = marker_data.icon_shadow_image;
        
        if (clear === true)
            this.getMap().clearOverlays();
        if (center === true)
            this.getMap().setCenter(point, this.zoomLevel);

        var mark = new GMarker(point,marker);
        if (typeof listeners === 'object')
            for (evt in listeners)
                GEvent.bind(mark, evt, this, listeners[evt]);
        this.markerRegistry.markers[identity] = mark;
        this.markerRegistry.count++;
        //mark.setImage(marker_icon);
        this.getMap().addOverlay(mark);
    },

    addMapControls : function(){
        if (this.gmapType === 'map') {
            if (Ext.isArray(this.mapControls)) {
                for(i=0;i<this.mapControls.length;i++){
                    this.addMapControl(this.mapControls[i]);
                }
            } else if(typeof this.mapControls === 'string') {
                this.addMapControl(this.mapControls);
            } else if(typeof this.mapControls === 'object') {
                this.getMap().addControl(this.mapControls);
            }
        }
    },

    addMapControl : function(mc){
        if ( typeof mc == 'string' ) { 
            var mcf = window[mc];
            if (typeof mcf === 'function') {
                var obj = new mcf();
               if ( mc == 'GLargeMapControl' )
                   this.largeSizer = obj;
               if ( mc == 'GSmallMapControl' )
                   this.smallSizer = obj;
            }
        } else
            obj = mc;
        if ( obj )
           this.getMap().addControl(obj);
    },

    removeMapControl : function(mc){
        this.getMap().removeControl(mc);
    },

    addMapTypes : function() {
        if (Ext.isArray(this.mapTypes)) {
            for(i=0;i<this.mapTypes.length;i++){
                this.addMapType(this.mapTypes[i]);
            }
        } else
            this.addMapType(this.mapTypes);
    },
    
    addMapType : function(mt){
        this.getMap().addMapType(mt);
    },

    addOptions : function(){
        if (Ext.isArray(this.mapConfOpts)) {
            var mc;
            for( i=0; i < this.mapConfOpts.length; i++ )
                this.addOption(this.mapConfOpts[i]);
        } else if(typeof this.mapConfOpts === 'string')
            this.addOption(this.mapConfOpts);
    },

    addOption : function(mc){
        var mcf = this.getMap()[mc];
        if (typeof mcf === 'function')
            this.getMap()[mc]();
    },

    geoCodeLookup : function(addr) {
        this.geocoder = new GClientGeocoder();
        this.geocoder.getLocations(addr, this.addAddressToMap.createDelegate(this));
    },

    setMapCenter : function(res,marker) {
        if ( res && typeof res == 'string' ) {
            this.geocoder = new GClientGeocoder();
            this.geocoder.getLocations(res, this.setMapCenter.createDelegate(this,[marker],true));
        } else {
            if (!res || res.Status.code != 200) {
                if ( res )
                    Ext.MessageBox.alert('Error', 'Geocode: Code '+res.Status.code+' Error Returned');
                else
                    Ext.MessageBox.alert('Error', 'Geocode: Error Returned');
            } else {
                place = res.Placemark[0];
                addressinfo = place.AddressDetails;
                accuracy = addressinfo.Accuracy;
                if (accuracy === 0) {
                    Ext.MessageBox.alert('Geocode Error', 'Unable to Locate the Address you provided');
                } else {
                    if (this.geoAccuracyWarning && accuracy < 7) {
                        Ext.MessageBox.alert('Geocode Warning', 'The address provided has a low accuracy.<br><br>Level '+accuracy+' Accuracy (8 = Exact Match, 1 = Vague Match)');
                    } else {
                        var pt = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
                        if ( marker )
                            this.addMarker(pt,marker,false,true);
                        this.gmap.setCenter(pt, this.zoomLevel);
                    }
                }
            }
        }
    },

    addAddressToMap : function(response) {
        if (!response || response.Status.code != 200) {
            Ext.MessageBox.alert('Error', 'Code '+response.Status.code+' Error Returned');
        } else {
            place = response.Placemark[0];
            addressinfo = place.AddressDetails;
            accuracy = addressinfo.Accuracy;
            if (accuracy === 0) {
                Ext.MessageBox.alert('Geocode Error', 'Unable to Locate the Address you provided');
            } else {
                if (this.geoAccuracyWarning && accuracy < 7) {
                    Ext.MessageBox.alert('Geocode Warning', 'The address provided has a low accuracy.<br><br>Level '+accuracy+' Accuracy (8 = Exact Match, 1 = Vague Match)');
                } else {
                    point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
                    if (this.setCenter.marker && typeof this.setCenter.marker === 'object'
                        && typeof point === 'object') {
                        this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear,true, this.setCenter.listeners);
                    }
                }
            }
        }
    },
    
    clearMapOverlays: function() {
    	this.getMap().clearOverlays();
    	this.markerRegistry.count = 0;
    	this.markerRegistry.markers = []
    },
    
    centerMapMarkers: function() {
    	if(this.markerRegistry.count==0) {
    		return;
    	}
    	//Calculate average latlon pair.
    	var tlanlon;
    	var tlat = 0;
    	var tlon = 0;
    	var parity;
    	
    	if (Ext.isArray(this.markerRegistry.markers)) {
    		for(markerID in this.markerRegistry.markers){
    			if(typeof this.markerRegistry.markers[markerID].getLatLng == 'function') {
	    			window.tlatlon = this.markerRegistry.markers[markerID].getLatLng();
    				tlat += tlatlon.lat();
	        		tlon += tlatlon.lng();
    			}
    		}
    	}
    	
    	tlat = Math.round(tlat/this.markerRegistry.count);
    	tlon = Math.round(tlon/this.markerRegistry.count);
    	
    	var center = new GLatLng(tlat,tlon);
    	this.gmap.setCenter(center, this.zoomLevel);
    },
    
    setZoomLevel: function(zoomLevel) {
    	this.gmap.setCenter(this.gmap.getCenter(), zoomLevel);
    },
    
    getMarker: function(id){
    	if(typeof this.markerRegistry.markers[id] == 'undefined') {
    		return 'NA';
    	}
    	if(typeof this.markerRegistry.markers[id].getLatLng != 'function') {
    		return 'NA';
    	}
    	return this.markerRegistry.markers[id];
    },
    
    applyBestZoom: function(){
    	if(this.markerRegistry.count==0){
    		return;
    	}
    	
    	var temp;
    	var bounds = new GLatLngBounds;
    	
    	if (Ext.isArray(this.markerRegistry.markers)) {
    		for(markerID in this.markerRegistry.markers){
    			if(typeof this.markerRegistry.markers[markerID].getLatLng == 'function') {
	    			temp = this.markerRegistry.markers[markerID].getLatLng();
    				bounds.extend(temp);
    			}
    		}
    	}
    	
    	this.gmap.setZoom(this.gmap.getBoundsZoomLevel(bounds));
    	this.gmap.setCenter(bounds.getCenter());
    }
});

Ext.reg('gmappanel',Ext.ux.GMapPanel); 
