/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/** 
 * @requires OpenLayers/Control.js
 */

/**
 * Class: OpenLayers.Control.LayerSwitcher
 * The LayerSwitcher control displays a table of contents for the map. This 
 * allows the user interface to switch between BaseLasyers and to show or hide
 * Overlays. By default the switcher is shown minimized on the right edge of 
 * the map, the user may expand it by clicking on the handle.
 *
 * To create the LayerSwitcher outside of the map, pass the Id of a html div 
 * as the first argument to the constructor.
 * 
 * Inherits from:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.LayerSwitcherTimed = 
  OpenLayers.Class(OpenLayers.Control.LayerSwitcher, {

    /**  
     * Property: activeColor
     * {String}
     */
    activeColor: "black",
    timeLbl: null,
    timeLayersDiv: null,
    timeLayers: null, //Dummy
    isFirstRun: true,
    helpPopup: null,
 
    /**
     * Constructor: OpenLayers.Control.LayerSwitcher
     * 
     * Parameters:
     * options - {Object}
     */
    initialize: function(options) {
        OpenLayers.Control.LayerSwitcher.prototype.initialize.apply(this, arguments);
        //this.layerStates = [];
    },

    /**
     * APIMethod: destroy 
     */    
    /** 
     * Method: setMap
     *
     * Properties:
     * map - {<OpenLayers.Map>} 
     */
    /**
     * Method: draw
     *
     * Returns:
     * {DOMElement} A reference to the DIV DOMElement containing the 
     *     switcher tabs.
     */  
    /** 
     * Method: clearLayersArray
     * User specifies either "base" or "data". we then clear all the
     *     corresponding listeners, the div, and reinitialize a new array.
     * 
     * Parameters:
     * layersType - {String}  
     */
    /**
     * Method: checkRedraw
     * Checks if the layer state has changed since the last redraw() call.
     * 
     * Returns:
     * {Boolean} The layer state changed since the last redraw() call. 
     */
     
     
    getDefaultTime: function() {
    	var today = new Date();
		var onejan = new Date(today.getFullYear(),0,1);
		var doy = Math.ceil((today - onejan) / 86400000);
		if (doy <= 150) {
			return 'spring_noon';
		} else {
			return 'summer_noon';
		}
    },
    /** 
     * Method: redraw
     * Goes through and takes the current state of the Map and rebuilds the
     *     control to display that state. Groups base layers into a 
     *     radio-button group and lists each data layer with a checkbox.
     *
     * Returns: 
     * {DOMElement} A reference to the DIV DOMElement containing the control
     */  
    redraw: function() {
        //if the state hasn't changed since last redraw, no need 
        // to do anything. Just return the existing div.
        /*if (!this.checkRedraw()) { 
            return this.div; 
        } */
        
        if (!this.isFirstRun){
            return this.div; 
        }
        this.isFirstRun = false;
        
        //console.log('redraw');

        //clear out previous layers 
        this.clearLayersArray("time");
        this.clearLayersArray("base");
        this.clearLayersArray("data");
        
        var containsOverlays = false;
        var containsBaseLayers = false;
        
        // Save state -- for checking layer if the map state changed.
        // We save this before redrawing, because in the process of redrawing
        // we will trigger more visibility changes, and we want to not redraw
        // and enter an infinite loop.
        var len = this.map.layers.length;
        this.layerStates = new Array(len);
        for (var i=0; i <len; i++) {
            var layer = this.map.layers[i];
            this.layerStates[i] = {
                'name': layer.name, 
                'visibility': layer.visibility,
                'inRange': layer.inRange,
                'id': layer.id
            };
        }
        
        // Redraw time div
        var timeLabels = new Array(OpenLayers.i18n('spring_morning'),OpenLayers.i18n('spring_noon'),OpenLayers.i18n('spring_evening'),OpenLayers.i18n('summer_morning'),OpenLayers.i18n('summer_noon'),OpenLayers.i18n('summer_evening'));
        var timeKey = ['spring_morning','spring_noon','spring_evening',
                'summer_morning','summer_noon','summer_evening'];
        defaultTimeKey = this.getDefaultTime();
        for( var i in timeKey ){
            var inputElem = document.createElement("input");
            inputElem.id = this.id + "_input_time";
            inputElem.name = timeLabels[i];
            inputElem.type = "radio";
            inputElem.value = timeKey[i];
            inputElem.checked = defaultTimeKey == timeKey[i];
            inputElem.defaultChecked = inputElem.checked;
            
            var context = {
                'inputElem': inputElem,
                'layerSwitcher': this
            };
            OpenLayers.Event.observe(inputElem, "mouseup", 
                OpenLayers.Function.bindAsEventListener(this.onTimeClick,
                                                            context)
            );
            var labelSpan = document.createElement("span");
            labelSpan.innerHTML = timeLabels[i];
            OpenLayers.Event.observe(labelSpan, "click", 
                OpenLayers.Function.bindAsEventListener(this.onTimeClick,
                                                        context)
            );
            // create line break
            var br = document.createElement("br");
            
            this.timeLayers.push({
                    //'layer': layer,
                    'inputElem': inputElem,
                    'labelSpan': labelSpan
                });
            
            this.timeLayersDiv.appendChild(inputElem);
            this.timeLayersDiv.appendChild(labelSpan);
            this.timeLayersDiv.appendChild(br);
        }

        var layers = this.map.layers.slice();
        if (!this.ascending) { layers.reverse(); }
        for(var i=0, len=layers.length; i<len; i++) {
            var layer = layers[i];
            var baseLayer = layer.isBaseLayer;

            if (layer.displayInLayerSwitcher) {

                if (baseLayer) {
                    containsBaseLayers = true;
                } else {
                    containsOverlays = true;
                }    

                // only check a baselayer if it is *the* baselayer, check data
                //  layers if they are visible
                var checked = (baseLayer) ? (layer == this.map.baseLayer)
                                          : layer.getVisibility();
    
                // create input element
                var inputElem = document.createElement("input");
                inputElem.id = this.id + "_input_" + layer.name;
                inputElem.name = (baseLayer) ? "baseLayers" : layer.name;
                inputElem.type = (baseLayer) ? "radio" : "checkbox";
                inputElem.value = layer.name;
                inputElem.checked = checked;
                inputElem.defaultChecked = checked;

                if (!baseLayer && !layer.inRange) {
                    inputElem.disabled = true;
                }
                var context = {
                    'inputElem': inputElem,
                    'layer': layer,
                    'layerSwitcher': this
                };
                OpenLayers.Event.observe(inputElem, "mouseup", 
                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
                                                            context)
                );
                
                // create span
                var labelSpan = document.createElement("span");
                //if (!baseLayer && !layer.inRange) { labelSpan.style.color = "gray";}
                labelSpan.innerHTML = layer.name;
                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" 
                                                            : "baseline";
                OpenLayers.Event.observe(labelSpan, "click", 
                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
                                                            context)
                );
                // create line break
                var br = document.createElement("br");
    
                
                var groupArray = (baseLayer) ? this.baseLayers
                                             : this.dataLayers;
                groupArray.push({
                    'layer': layer,
                    'inputElem': inputElem,
                    'labelSpan': labelSpan
                });
                                                     
    
                var groupDiv = (baseLayer) ? this.baseLayersDiv
                                           : this.dataLayersDiv;
                groupDiv.appendChild(inputElem);
                groupDiv.appendChild(labelSpan);
                
                if( typeof(layer.helpPopup)=='string' ){
                    groupDiv.appendChild( this.newHelpOnMouseover(layer.helpPopup) );
                }
                
                groupDiv.appendChild(br);
            }
        }

        // if no overlays, dont display the overlay label
        this.dataLbl.style.display = (containsOverlays) ? "" : "none";        
        
        // if no baselayers, dont display the baselayer label
        this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";        

        return this.div;
    },
    
    onTimeClick: function(e) {
        if (!this.inputElem.disabled && !this.inputElem.checked) {
            for( var i=0, len=this.layerSwitcher.timeLayers.length; i<len; i++) {
                var ele = this.layerSwitcher.timeLayers[i].inputElem;
                if( ele.value == this.inputElem.value ){
                    ele.checked = true;
                }
                else{
                    ele.checked = false;
                }
            }
            this.layerSwitcher.callTimeDependants(this.inputElem.value);
        }
        OpenLayers.Event.stop(e);
    },
    
    callTimeDependants: function(newTimeStr){
        //console.log('callTimeDependants');
        for(var i=0, len=this.map.layers.length; i<len; i++) {
            var layer = this.map.layers[i];
            if( layer.isTimeDependant ){
                layer.timeChanged( newTimeStr );
            }
        }
    },

    /** 
     * Method:
     * A label has been clicked, check or uncheck its corresponding input
     * 
     * Parameters:
     * e - {Event} 
     *
     * Context:  
     *  - {DOMElement} inputElem
     *  - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
     *  - {<OpenLayers.Layer>} layer
     */

    /**
     * Method: onLayerClick
     * Need to update the map accordingly whenever user clicks in either of
     *     the layers.
     * 
     * Parameters: 
     * e - {Event} 
     */

    /** 
     * Method: updateMap
     * Cycles through the loaded data and base layer input arrays and makes
     *     the necessary calls to the Map object such that that the map's 
     *     visual state corresponds to what the user has selected in 
     *     the control.
     */
    /** 
     * Method: maximizeControl
     * Set up the labels and divs for the control
     * 
     * Parameters:
     * e - {Event} 
     */
    /** 
     * Method: minimizeControl
     * Hide all the contents of the control, shrink the size, 
     *     add the maximize icon
     *
     * Parameters:
     * e - {Event} 
     */
    /**
     * Method: showControls
     * Hide/Show all LayerSwitcher controls depending on whether we are
     *     minimized or not
     * 
     * Parameters:
     * minimize - {Boolean}
     */
    /** 
     * Method: loadContents
     * Set up the labels and divs for the control
     */
    loadContents: function() {

        //configure main div
        this.div.style.position = "absolute";
        this.div.style.top = "25px";
        this.div.style.right = "0px";
        this.div.style.left = "";
        this.div.style.fontFamily = "sans-serif";
        this.div.style.fontWeight = "bold";
        this.div.style.marginTop = "3px";
        this.div.style.marginLeft = "3px";
        this.div.style.marginBottom = "3px";
        this.div.style.fontSize = "smaller";   
        this.div.style.color = "white";   
        this.div.style.backgroundColor = "transparent";
    
        OpenLayers.Event.observe(this.div, "mouseup", 
            OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
        OpenLayers.Event.observe(this.div, "click",
                      this.ignoreEvent);
        OpenLayers.Event.observe(this.div, "mousedown",
            OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
        OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
        
        // layers list div        
        this.layersDiv = document.createElement("div");
        this.layersDiv.id = this.id + "_layersDiv";
        this.layersDiv.style.paddingTop = "5px";
        this.layersDiv.style.paddingLeft = "10px";
        this.layersDiv.style.paddingBottom = "5px";
        this.layersDiv.style.paddingRight = "75px";
        this.layersDiv.style.backgroundColor = this.activeColor;        

        // had to set width/height to get transparency in IE to work.
        // thanks -- http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html
        //
        this.layersDiv.style.width = "100%";
        this.layersDiv.style.height = "100%";
        
        // Base layers
        this.baseLbl = document.createElement("div");
        this.baseLbl.innerHTML = OpenLayers.i18n("baseLayer");
        this.baseLbl.style.marginTop = "3px";
        this.baseLbl.style.marginLeft = "3px";
        this.baseLbl.style.marginBottom = "3px";
        
        this.baseLayersDiv = document.createElement("div");
        this.baseLayersDiv.style.paddingLeft = "10px";
        /*OpenLayers.Event.observe(this.baseLayersDiv, "click", 
            OpenLayers.Function.bindAsEventListener(this.onLayerClick, this));
        */
                     

        this.dataLbl = document.createElement("div");
        this.dataLbl.innerHTML = OpenLayers.i18n("overlays");
        this.dataLbl.style.marginTop = "3px";
        this.dataLbl.style.marginLeft = "3px";
        this.dataLbl.style.marginBottom = "3px";
        
        this.dataLayersDiv = document.createElement("div");
        this.dataLayersDiv.style.paddingLeft = "10px";

        if (this.ascending) {
            this.layersDiv.appendChild(this.baseLbl);
            this.layersDiv.appendChild(this.baseLayersDiv);
            this.layersDiv.appendChild(this.dataLbl);
            this.layersDiv.appendChild(this.dataLayersDiv);
        } else {
            this.layersDiv.appendChild(this.dataLbl);
            this.layersDiv.appendChild(this.dataLayersDiv);
            this.layersDiv.appendChild(this.baseLbl);
            this.layersDiv.appendChild(this.baseLayersDiv);
        }
        
        // opacity control
        this.baseLbl.appendChild(this.newOpacityControlButtons("baseLayers"));
        this.dataLbl.appendChild(this.newOpacityControlButtons("dataLayers"));
        
        // time changer
        this.timeLbl = document.createElement("div");
        this.timeLbl.innerHTML = OpenLayers.i18n('timePeriod');
        this.timeLbl.style.marginTop = "3px";
        this.timeLbl.style.marginLeft = "3px";
        this.timeLbl.style.marginBottom = "3px";
        this.timeLbl.appendChild(this.newHelpOnMouseover(OpenLayers.i18n("tt_timePeriod")));
        this.timeLayersDiv = document.createElement("div");
        this.timeLayersDiv.style.paddingLeft = "10px";
        
        this.layersDiv.appendChild(this.timeLbl);
        this.layersDiv.appendChild(this.timeLayersDiv);
 
        this.div.appendChild(this.layersDiv);

        OpenLayers.Rico.Corner.round(this.div, {corners: "tl bl",
                                        bgColor: "transparent",
                                        color: this.activeColor,
                                        blend: false});

        OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);

        var imgLocation = OpenLayers.Util.getImagesLocation();
        var sz = new OpenLayers.Size(18,18);        

        // maximize button div
        var img = imgLocation + 'layer-switcher-maximize.png';
        this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
                                    "OpenLayers_Control_MaximizeDiv", 
                                    null, 
                                    sz, 
                                    img, 
                                    "absolute");
        this.maximizeDiv.style.top = "5px";
        this.maximizeDiv.style.right = "0px";
        this.maximizeDiv.style.left = "";
        this.maximizeDiv.style.display = "none";
        OpenLayers.Event.observe(this.maximizeDiv, "click", 
            OpenLayers.Function.bindAsEventListener(this.maximizeControl, this)
        );
        
        this.div.appendChild(this.maximizeDiv);

        // minimize button div
        var img = imgLocation + 'layer-switcher-minimize.png';
        var sz = new OpenLayers.Size(18,18);        
        this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
                                    "OpenLayers_Control_MinimizeDiv", 
                                    null, 
                                    sz, 
                                    img, 
                                    "absolute");
        this.minimizeDiv.style.top = "5px";
        this.minimizeDiv.style.right = "0px";
        this.minimizeDiv.style.left = "";
        this.minimizeDiv.style.display = "none";
        OpenLayers.Event.observe(this.minimizeDiv, "click", 
            OpenLayers.Function.bindAsEventListener(this.minimizeControl, this)
        );

        this.div.appendChild(this.minimizeDiv);
    },
    
    newHelpOnMouseover: function(helpText) {
        var helpSpan = document.createElement("span");
        helpSpan.innerHTML = "&nbsp;"
        
        var helpButton = document.createElement("img");
        helpButton.src = OpenLayers.Util.getImagesLocation() + "questionmark.gif";
        helpButton.alt = "Help Button";
        
        OpenLayers.Event.observe(helpButton, "mouseover", 
                    OpenLayers.Function.bindAsEventListener(this.onMouseoverHelp, {layerSwitcher:this, text:helpText} ));
        OpenLayers.Event.observe(helpButton, "mouseout", 
                    OpenLayers.Function.bindAsEventListener(this.onMouseoutHelp, {layerSwitcher:this} ));
        helpSpan.appendChild(helpButton);
        
        
        
        return helpSpan;
    },
    
    onMouseoverHelp: function(e) {
        var tt = this.layerSwitcher.helpPopup;
        var id = 'tt';
        var maxw = 300;
        if(tt == null){
            tt = document.createElement('div');
            tt.setAttribute('id',id);
            document.body.appendChild(tt);
            tt.style.zIndex = '9999';
        }
        
        tt.style.visibility = 'visible';
        tt.innerHTML = this.text;
        
        //tt.style.width = 'auto';
        //tt.style.width = tt.offsetWidth;
        //if(tt.offsetWidth > maxw){tt.style.width = maxw + 'px'}
        tt.style.width = maxw + 'px';
			
        h = parseInt(tt.offsetHeight) + 3;
        var u = /*ie ? event.clientY + document.documentElement.scrollTop :*/ e.clientY;
        var l = /*ie ? event.clientX + document.documentElement.scrollLeft :*/ e.clientX;
        tt.style.top = (u - h) + 'px';
        tt.style.left = (l + 3 - maxw) + 'px';
        
        this.layerSwitcher.helpPopup = tt;
    },
    
    onMouseoutHelp: function(e) {
        this.layerSwitcher.helpPopup.style.visibility = 'hidden';
    },

    newOpacityControlButtons: function(layerGroupName) {    
        var opacitySpan = document.createElement("span");
        opacitySpan.setAttribute("id", "opacityValue_" + layerGroupName);
        opacitySpan.innerHTML = "&nbsp;"
        
        var opacityMinusButton = document.createElement("img");
        opacityMinusButton.src = OpenLayers.Util.getImagesLocation() + "opacity-decrease.png";
        opacityMinusButton.style.cursor = "pointer";
        opacityMinusButton.alt = OpenLayers.i18n("opacity_decrease");
        opacityMinusButton.title = OpenLayers.i18n("opacity_decrease");
        
        /*var opacityText = document.createElement("span");
        opacityText.setAttribute("id", "opacityValue_text_" + layerGroupName);
        opacityText.innerHTML = language=='de' ? 'Deckkraft' : 'opacity';*/
        
        var opacityText = document.createElement("img")
        opacityText.setAttribute("id", "opacityValue_text_" + layerGroupName);
        opacityText.src = OpenLayers.Util.getImagesLocation() + "eye.png";
        opacityText.alt = OpenLayers.i18n("opacity")
        opacityText.title = OpenLayers.i18n("opacity")
        
        var opacityPlusButton = document.createElement("img");
        opacityPlusButton.src = OpenLayers.Util.getImagesLocation() + "opacity-increase.png";
        opacityPlusButton.style.cursor = "pointer";
        opacityPlusButton.alt = OpenLayers.i18n("opacity_increase");
        opacityPlusButton.title = OpenLayers.i18n("opacity_increase");
        
        var opacityMinusContext = {
                    'layerGroup': layerGroupName,
                    'byOpacity': -0.1,
                    'textElement': opacityText,
                    'layerSwitcher': this};
        OpenLayers.Event.observe(opacityMinusButton, "click", 
                    OpenLayers.Function.bindAsEventListener(this.changeLayerOpacity, opacityMinusContext));
               
        var opacityPlusContext = {
                    'layerGroup': layerGroupName,
                    'byOpacity': 0.1,
                    'textElement': opacityText,
                    'layerSwitcher': this};
        OpenLayers.Event.observe(opacityPlusButton, "click", 
                    OpenLayers.Function.bindAsEventListener(this.changeLayerOpacity, opacityPlusContext));
        
        opacitySpan.appendChild(opacityMinusButton);
        opacitySpan.appendChild(opacityText);
        opacitySpan.appendChild(opacityPlusButton);
        
        return opacitySpan;
    },
    
    /**
     * Method: changeLayerOpacity
     * Changes opacity of a given layer for a given delta
     * 
     * Parameters: 
     * e - {Event} 
     *
     * Context:  
     *  - {string} amount to increase or decrease opacity value
     *  - {<OpenLayers.Layer>} layer
     *  - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
     */
    changeLayerOpacity: function(e) 
    {    
        var layers = this.layerSwitcher[this.layerGroup];
        var change = this.byOpacity; //parseFloat(this.byOpacity);
        for (i=0; i<layers.length; i++) {
            layer = layers[i].layer;
            var opacity = (layer.opacity != null) ? layer.opacity : 1.0;
            var newOpacity = Math.round( (opacity + change)*10 )/10.0;
            if (newOpacity>1 || newOpacity<0.1) {
                break;
            }
            newOpacityStr = newOpacity.toString(10);
            if (newOpacity==1.0) { newOpacityStr = "1.0"; };
            this.textElement.innerHTML = newOpacityStr;
            layer.setOpacity( newOpacity );
        }
    },

    /** 
     * Method: ignoreEvent
     * 
     * Parameters:
     * evt - {Event} 
     */
    /** 
     * Method: mouseDown
     * Register a local 'mouseDown' flag so that we'll know whether or not
     *     to ignore a mouseUp event
     * 
     * Parameters:
     * evt - {Event}
     */
    /** 
     * Method: mouseUp
     * If the 'isMouseDown' flag has been set, that means that the drag was 
     *     started from within the LayerSwitcher control, and thus we can 
     *     ignore the mouseup. Otherwise, let the Event continue.
     *  
     * Parameters:
     * evt - {Event} 
     */
    CLASS_NAME: "OpenLayers.Control.LayerSwitcherTimed"
});

