﻿/**
    @class manages the "Active Layers" inset window of a map.  Handles reordering through dragging, and drawing visibility controls for all layers on the map.  Listens to the mapPanel for add and remove events.
    @augments Ext.Panel
    @param {configObject} config the configuration object
    @config {TNRIS.MapPanel} mapPanel the map panel to connect with this legend
*/
TNRIS.LayerLegend = function(config) {
    this.outOfZoomMsg = 'Out of Zoom Scale';
    
    this.tpl = new Ext.XTemplate(
        '<tpl for="layer">',
            '<div layerid="{[values.mapId()]}" class="legendItem" ext:qtitle="Description" ext:qtip="{[Ext.util.Format.htmlEncode(values.teaser())]}">',
            '	<div class="legendInfo">',
		   	'   <img src="{[values.micronail()]}" class="piconail" />',
		   	'   <div class="nameAndButtons">',
            '   <h2 class="legendLayerName">{[values.name()]}</h2>',
            '       <tpl if="values.queryable() == 1">',
            '         <span class="gridButtonLegend" title="Click to launch a grid with field values"></span>',
            '       </tpl>',
            '       <tpl if="values.smartable()">',
            '         <span class="smartLayerLegend"></span>',
            '       </tpl>',
            '       <tpl if="values.isRefreshable()">',
            '         <span class="lastRefreshTime" title="Last download time from Layer Feed"></span>',
            '         <span class="refreshLayerButton"  title="Click to refresh layer"></span>',			
            '       </tpl>',
            '	</div>',
            '   </div>',		
            '	<div class="visButtons">',
            '	<tpl if="values.isOpacityVariable()">',
            '       <div class="opacityPanel">',
            '   	    <div class="opacitySliderTrack" />',
            '       	    <div class="opacitySliderHandle" title="Move opacity handle to change layer transparency"></div>',
            '	    </div>',
			'   </tpl>',		
            '	</div>',
            '		<div class="layerRemove">',			
            '   		<div class="removeButton"></div>',
			'   		<span class="visibilityButton visibilityButtonOn"></span>',
            '		</div>',				
            '</div>',
        '</tpl>');
    
    Ext.apply(this, config);

    TNRIS.LayerLegend.superclass.constructor.call(this, {
        collapsible: true,
        animCollapse: false,
        collapsedCls: 'collapsedLegend',
        listeners: {
            'collapse': {scope: this, fn: this.onCollapseToggle},
            'expand': {scope: this, fn: this.onCollapseToggle},
            'beforecollapse': {scope: this, fn: this.changeSizeOnCollapse},
            'beforeexpand': {scope: this, fn: this.changeSizeOnCollapse},
            'render': {scope: this, fn: this.refresh}
        }
    });
    
    this.mapPanel.on({
        'map-change': { scope: this, fn: this.layerChange }
    });
    
    this.mapPanel.getMap().AttachEvent("onendzoom", function(e) {
        if (this.items != null) {
            this.items.each(function(item) {
                item.checkZoomLevel(e.zoomLevel);
            }, this);
        }
    }.bind(this));

};

Ext.extend(TNRIS.LayerLegend, Ext.Panel, 
    /** @scope TNRIS.LayerLegend */
    {
    changeSizeOnCollapse: function() {
        // this.collapsed has not been set yet - so the logic appears backwards
        if (this.collapsed) {
            this.setWidth(this.width);
        } else {
            this.setWidth(this.collapsedWidth);
        }
    },
    
    onCollapseToggle: function() {
        var size = this.mapPanel.getSize();
        this.mapPanel.onResize(size.width, size.height);
    },

    // called when a new layer is added to the map
    layerChange: function(args) {
        if (args.add) {
            this.addLayerItem(args.add);
            args.add.on('metadatachange', this.refresh, this);
        }
        if (args.remove) {
            var item = this.findById(args.remove);
            this.remove(item);
            item.layer.removeListener('metadatachange', this.refresh, this);
        }
    },
    
    clear: function() {
        this.items && this.items.each(function(item) {
            this.remove(item);
        }, this);
    },
    
    refresh: function() {
        this.clear();
        this.mapPanel.getLayers().each(function(layer) {
            this.addLayerItem(layer);
        },this);
    },
    
    addLayerItem: function(layer) {
        var legendItem = new TNRIS.LegendItem({
            layer: layer,
            mapPanel: this.mapPanel,
            id: layer.mapId(),
            tpl: this.tpl,
            outOfZoomMsg: this.outOfZoomMsg
            });
        this.insert(0,legendItem);
        this.doLayout();

        // HACK - convert to Ext drag-n-drop sorting
        if (typeof(this.sortable) !== 'undefined' && null !== this.sortable) {
            this.sortable.destroy();
        }
        if (this.rendered) {
            this.sortable = Sortable.create(this.body.dom, {
                tag: 'div',
                scroll: this.body.dom,
                onChange: function(element) {
                    var elementList = Element.select(element.parentNode, ".legendItem");
                    var layerOrder = elementList.collect(function(element) {
                        return element.readAttribute('layerid');
                    });
                    this.mapPanel.setLayerOrder(layerOrder.reverse());
                }.bind(this)
            });
        }
    }
});

TNRIS.LegendItem = function(config) {
    Ext.apply(this, config);
    TNRIS.LegendItem.superclass.constructor.call(this, {
        listeners: {
            "render": {
                scope: this,
                fn: this.activate
            }
        }
    });
};

Ext.extend(TNRIS.LegendItem, Ext.Container, {
    initComponent: function() {
    	// call superclass initComponent
        TNRIS.LegendItem.superclass.initComponent.call(this);

        this.el = this.tpl.insertFirst(Ext.getBody(),
            {
                layer: this.layer
            });
        this.layer.on('layer-refresh',this.refreshLayer,this);
    },
    
    activate: function() {
        var _layer = this.layer;
        var el = this.getEl();
                
        var slider = el.select('.opacitySliderHandle', true).first();
        if (null != slider) {
            this.opacity = new Control.Slider(slider.dom,el.select('.opacitySliderTrack', true).first().dom, {
                minimum: 0, 
                maximum: 1, 
                increment:0.01, 
                onChange: function(value) {_layer.opacity(1.0 - value);}, 
                onSlide: function(value) {_layer.opacity(1.0 - value);}, 
                sliderValue: 1.0 - _layer.opacity(),
                axis: 'vertical' // or 'horizontal'
                });
        }
        
        var vizButton = new ToggleButton(el.select('.visibilityButton',true).first().dom, {
            offClass: 'visibilityButtonOff',
            onClass: 'visibilityButtonOn',
            value: _layer.visible(),
            toggleState: function() {
                var visible = _layer.toggleVisible();
                if (visible) {
                    el.unmask();
                } else {
                    el.mask();
                }
                return visible;
            }.bind(this)
        });
        if (!_layer.visible()) {
            el.mask();
        }
        
        
        var removeButton = el.select('.removeButton', true).first();
        removeButton.on('click', function() {
            // TODO: dispose of javascript elements below
            this.mapPanel.removeLayer(_layer.mapId());
        }, this);
        
        // setup view_data button if it exists
        var gridbtn = el.select('.gridButtonLegend', true).first();
        if (null != gridbtn) {
            gridbtn.on('click', function(e, el) {
                Ext.getCmp('infoPanel').addLayerToGrid(_layer);
            }, this);
        }
        
        // setup smart button if it exists
        var smartbtn = el.select('.smartLayerLegend', true).first();
        if (null != smartbtn) {
            smartbtn.on('click', function(e, el) {
                var win = new TNRIS.SmartLayerWindow({layer: _layer, onSuccess: function(smartLayer) {
                    this.mapPanel.addLayer(smartLayer);
                }.bind(this)});
                win.show();
            }, this);
        }
        
        //setup refresh button if it exists
        var refreshbtn = el.select('.refreshLayerButton', true).first();
        if (null != refreshbtn) {
            refreshbtn.on('click', function(e, el) {
                this.layer.refreshLayer();
            }, this);
        }
        
        // per #160, mask the legend item if it's out of zoom
        var zoomLevel = this.mapPanel.getMap().GetZoomLevel();
        if (zoomLevel > _layer.maxZoomLevel() || zoomLevel < _layer.minZoomLevel()) {
            el.mask(this.outOfZoomMsg);
        }
        
        // TODO:  The style of this message is same as out of zoom level and can be changed
        this.layer.on('beforedataload', this.mask, this);

        this.layer.on('dataload', this.unmask ,this);

        this.getEl().on('contextmenu', this.onContextMenu, this);
    },
    
    mask: function(message) {
        this.getEl().mask(message);
    },
    
    unmask: function() {
        this.getEl().unmask();
    },
    
    destroy: function() {
        this.layer.removeListener('dataload', this.unmask, this);
        this.layer.removeListener('beforedataload', this.mask, this);
        this.layer.removeListener('layer-refresh', this.refreshLayer, this);
        TNRIS.LegendItem.superclass.destroy.call(this);
    },
    
    checkZoomLevel: function(zoomLevel) {
        if (zoomLevel > this.layer.maxZoomLevel() || zoomLevel < this.layer.minZoomLevel()) {
            this.getEl().mask(this.outOfZoomMsg);
        } else {
            this.getEl().unmask();
        }
    },
    
    refreshLayer: function(values) {
        var refTimeLabel =this.getEl().select('.lastRefreshTime', true).first();
        if (null != refTimeLabel) {
            gemss.app.msg("Layer Refresh", "The '{0}' layer is currently being updated with most recent information from source" ,this.layer.name());
            refTimeLabel.update(values.time);
        }
    },
    
    onContextMenu: function (e, node, scope) {
        if (!this.menu) {
            this.menu = new Ext.menu.Menu({
                id:"active-layers-menu", 
                cls: 'activeLayerMenu',
                items:[
                    {
                        id:"zoomToLayer", 
                        cls: 'zoomToLayerCtxMenuItem',
                        icon: '../images/buttons/zoom_to_layer.png',
                        text:"Zoom to Layer", 
                        scope: this, 
                        handler:function (btn, e) {
                            btn.parentMenu.hide();
                            this.mapPanel.zoomToLayer(this.layer);
                        }
                    }
                ]
            });
            if (this.layer.isEditable()&& (! this.layer.hasRestrictedEdit())) {
                this.menu.add({
                        id:"editLayer", 
                        icon: '../images/buttons/edit.png',
                        cls: 'editLayerCtxMenuItem',
                        text:"Edit Layer", 
                        scope: this, 
                        handler:function (btn, e) {
                            btn.parentMenu.hide();
                            var win = new TNRIS.UserLayerWindow({
                                layer: this.layer,
                                mapPanel: this.mapPanel
                            });
                            win.show();
                        }
                    });
            }
            this.menu.on('hide', this.onContextHide, this);
        }
        e.stopEvent();
        
        if (this.ctxNode) {
            Ext.fly(this.ctxNode).removeClass("x-node-ctx");
        }
        this.ctxNode = node;
        Ext.fly(this.ctxNode).addClass("x-node-ctx");
        this.menu.showAt(e.getXY());
    },
    
    onContextHide: function() {
        if (this.ctxNode) {
            Ext.fly(this.ctxNode).removeClass("x-node-ctx");
            this.ctxNode = null;
        }
    }

});

if (typeof(Sys) !== "undefined") { Sys.Application.notifyScriptLoaded(); }
