/*
 * Google Earth API for Ext JS
 * Copyright(c) 2008, Bjorn Sandvik
 * bjorn@thematicmapping.org
 * http://thematicmapping.org
 *
 * License: GNU General Public License v3
 *
 * Version: 1.1
 *
 */

Ext.namespace('Ext.ux');

/**
 *
 * @class GEarthPanel
 * @extends Ext.Panel
 */
Ext.ux.GEarthPanel = Ext.extend(Ext.Panel, {

    initComponent: function(){
        // Default values
        var defConfig = {
            border: true,
            earthLayers: {
                LAYER_BORDERS:   true,
                LAYER_ROADS:     false,
                LAYER_BUILDINGS: false,
                LAYER_TERRAIN:   true
            },
            earthOptions: {
                setStatusBarVisibility:    false,
                setGridVisibility:         false,
                setOverviewMapVisibility:  true,
                setScaleLegendVisibility:  false,
                setAtmosphereVisibility:   true,
                setMouseNavigationEnabled: true
            },
            kmlTreePanel: null
        };
        Ext.applyIf(this, defConfig);
        Ext.ux.GEarthPanel.superclass.initComponent.call(this);
        this.addEvents('earthLoaded');
    },

    // Create Google Earth instance when panel is rendered
    afterRender: function(){
        Ext.ux.GEarthPanel.superclass.afterRender.call(this);
        google.earth.createInstance(this.body.dom, this.onEarthReady.createDelegate(this), {});
    },

    // Called by above function
    onEarthReady: function(object){
        this.earth = object;
        this.earth.getWindow().setVisibility(true);
        this.earth.getNavigationControl().setVisibility(this.earth.VISIBILITY_SHOW);
        this.setLayers(this.earthLayers);
        this.setOptions(this.earthOptions);

        // Create TreePanel to show KML documents
        this.kmlTreePanel = new Ext.tree.TreePanel({
                xtype: 'treepanel',
            border: false,
            bodyStyle: 'padding-bottom: 15px',
                root: new Ext.tree.TreeNode({
                        text: 'Documenti geografici KMZ/KML',
                        iconCls: 'folder',
                        expanded: true
                }),
            rootVisible: false,
            listeners: {checkchange: {fn: function(node, checked){
                node.attributes.kml.setVisibility(checked);
                        node.bubble(function(n){  // If a child node is checked, check all the ancestors
                                if (node.getUI().isChecked()) {
                                if (!node.parentNode.getUI().isChecked()) {
                                    node.parentNode.getUI().toggleCheck();
                                }
                            }
                        })
            }}}
        });

        this.fireEvent('earthLoaded', this);
    },

    // Return Google Earth instance
    getEarth: function(){
        return this.earth;
    },

    // Set Google Earth layers
    setLayers: function(layers){
        for (layer in layers){
            this.earth.getLayerRoot().enableLayerById(this.earth[layer], layers[layer]);
        }
    },

    // Returns FormPanel containing Google Earth layers
    getLayersPanel: function(){

        // Define layer labels
        var layerNames = {
            LAYER_BORDERS: 'Nomi e Confini',
            LAYER_ROADS: 'Strade',
            LAYER_BUILDINGS: 'Edifici',
            LAYER_TERRAIN: 'Terreno'
        }

        // Create checkbox for each layer
        var items = [];
        for (layer in this.earthLayers){
                        items.push({
                boxLabel: layerNames[layer],
                    checked: this.earthLayers[layer],
                    name: layer,
                    earth: this.earth,
                handler: function(layer, visibility) {
                    this.earth.getLayerRoot().enableLayerById(this.earth[layer.name], visibility);
                }.createDelegate(this)
                });
        }

        // Create FormPanel with all layers
        var layersPanel = new Ext.FormPanel({
            title: 'Google Earth Strati',
            defaultType: 'checkbox',
            defaults: {
                hideLabel: true
            },
            items: items
        });

        return layersPanel;
    },

    // Set Google Earth options
    setOptions: function(options){
        for (option in options){
            this.earth.getOptions()[option](options[option]);
        }
    },

    // Returns FormPanel containing Google Earth options
    getOptionsPanel: function(){

        // Define option labels
        var optionLabels = {
            setStatusBarVisibility: 'Mostra status bar',
            setGridVisibility: 'Mostra grid',
            setOverviewMapVisibility: 'Mostra overview map',
            setScaleLegendVisibility: 'Mostra legenda',
            setAtmosphereVisibility: 'Mostra atmosfera',
            setMouseNavigationEnabled: 'Mostra navigazione mouse '
        }

        // Create checkbox for each option
        var items = [];
        for (option in this.earthOptions){
                        items.push({
                boxLabel: optionLabels[option],
                    checked: this.earthOptions[option],
                    name: option,
                handler: function(option, visibility) {
                    this.earth.getOptions()[option.name](visibility);
                }.createDelegate(this)
                });
        }

        // Create FormPanel with all options
        var optionsPanel = new Ext.FormPanel({
            title: 'Options',
            defaultType: 'checkbox',
            defaults: {
                hideLabel: true
            },
            items: items
        });

        return optionsPanel;
    },

    // Returns FormPanel for finding locations
    getLocationPanel: function(){
        var locationPanel = new Ext.FormPanel({
            title: 'Cerca Posto',
            labelAlign: 'top',
            items: new Ext.form.TriggerField({
                fieldLabel: 'Posto',
                triggerClass: 'x-form-search-trigger',
                anchor: '100%',
                name: 'location',
                scope: this,
                onTriggerClick: function(){
                    this.scope.findLocation(this.getValue());
                },
                listeners: {specialkey: {fn: function(f, e){
                    if (e.getKey() == e.ENTER) {
                        this.onTriggerClick();
                    }
                }}}
            })
        });
        return locationPanel;
    },

    // Fly to location (geocoding) - used by above function
    // Based on http://earth-api-samples.googlecode.com/svn/trunk/examples/geocoder.html
    findLocation: function(geocodeLocation){
        var geocoder = new google.maps.ClientGeocoder();
        geocoder.getLatLng(geocodeLocation, function(point) {
            if (point) {
                var lookAt = this.earth.createLookAt('');
                lookAt.set(point.y, point.x, 10, this.earth.ALTITUDE_RELATIVE_TO_GROUND, 0, 60, 20000);
                this.earth.getView().setAbstractView(lookAt);
            }
        }.createDelegate(this));
    },

    // Returns FormPanel for KML documents
    getKmlPanel: function(){

        var kmlUrlField = new Ext.form.TriggerField({
            fieldLabel: 'Aggiungi segnaposto KML/KMZ',
            triggerClass: 'x-form-search-trigger',
            anchor: '100%',
            name: 'url',
            value: '',
            selectOnFocus: true,
            scope: this,
            onTriggerClick: function(){
                google.earth.fetchKml(this.scope.earth, this.getValue(), this.scope.addKml.createDelegate(this.scope));
                this.reset();
            },
            listeners: {specialkey: {fn: function(f, e){
                if (e.getKey() == e.ENTER) {
                    this.onTriggerClick();
                }
            }}}
        });

        var kmlPanel = new Ext.FormPanel({
            title: 'Documenti geografici KMZ/KML',
            labelAlign: 'top',
            items: [this.kmlTreePanel, kmlUrlField]
        });

        return kmlPanel;
    },

    // Load and display KML file
    fetchKml: function(kmlUrl){
                google.earth.fetchKml(this.earth, kmlUrl, this.addKml.createDelegate(this));
    },

    // Add KML object (called by above function)
    addKml: function(kmlObject){
        if (kmlObject) {
                this.earth.getFeatures().appendChild(kmlObject);
                this.kmlTreePanel.getRootNode().appendChild(this.treeNodeFromKml(kmlObject));
                } else {
                alert('Bad KML');
                }
    },

    // Create KML tree (called by above function)
    treeNodeFromKml: function(kmlObject){
        var result = this.createKmlTreeNode(kmlObject);

        if(kmlObject.getFeatures().hasChildNodes()) {
                var subNodes = kmlObject.getFeatures().getChildNodes();
                for(var i = 0; i < subNodes.getLength(); i++) {
                        var subNode = subNodes.item(i);
                        switch(subNode.getType()) {
                                case 'KmlFolder' :
                                var node = this.treeNodeFromKml(subNode); // Recursion
                                        break;
                                default:
                                        var node = this.createKmlTreeNode(subNode);
                                        break;
                        }
                        result.appendChild(node);
                }
        }
        return result;
    },

    // Create KML tree node (called by above function)
    createKmlTreeNode: function(kmlEl){
        var node = new Ext.tree.TreeNode({
                text: kmlEl.getName(),
                checked: (kmlEl.getType() != 'KmlPlacemark' ? (kmlEl.getVisibility() ? true : false) : null),
                expanded: (kmlEl.getOpen() ? true : false),
                iconCls: kmlEl.getType(),
                kml: kmlEl
        });
        return node;
    }

});

Ext.reg('gearthpanel', Ext.ux.GEarthPanel);

