/* 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
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.LayerSwitcher = 
  OpenLayers.Class(OpenLayers.Control, {

    /**  
     * Property: activeColor
     * {String}
     */
    activeColor: "darkblue",
    
    /**  
     * Property: layerStates 
     * {Array(Object)} Basically a copy of the "state" of the map's layers 
     *     the last time the control was drawn. We have this in order to avoid
     *     unnecessarily redrawing the control.
     */
    layerStates: null,
    

  // DOM Elements
  
    /**
     * Property: layersDiv
     * {DOMElement} 
     */
    layersDiv: null,
    
    /** 
     * Property: baseLayersDiv
     * {DOMElement}
     */
    baseLayersDiv: null,

    /** 
     * Property: baseLayers
     * {Array(<OpenLayers.Layer>)}
     */
    baseLayers: null,
    
    
    /** 
     * Property: dataLbl
     * {DOMElement} 
     */
    dataLbl: null,
    
    /** 
     * Property: dataLayersDiv
     * {DOMElement} 
     */
    dataLayersDiv: null,

    /** 
     * Property: dataLayers
     * {Array(<OpenLayers.Layer>)} 
     */
    dataLayers: null,


    categoryDivs: null,


    /** 
     * Property: minimizeDiv
     * {DOMElement} 
     */
    minimizeDiv: null,

    /** 
     * Property: maximizeDiv
     * {DOMElement} 
     */
    maximizeDiv: null,
    
    /**
     * APIProperty: ascending
     * {Boolean} 
     */
    ascending: false,
 
    /**
     * Constructor: OpenLayers.Control.LayerSwitcher
     * 
     * Parameters:
     * options - {Object}
     */
    initialize: function(options) {
        OpenLayers.Control.prototype.initialize.apply(this, arguments);
        this.layerStates = [];
        this.categoryDivs = [];
    },

    /**
     * APIMethod: destroy 
     */    
    destroy: function() {
        
        OpenLayers.Event.stopObservingElement(this.div);

        OpenLayers.Event.stopObservingElement(this.minimizeDiv);
        OpenLayers.Event.stopObservingElement(this.maximizeDiv);

        //clear out layers info and unregister their events 
        this.clearLayersArray("base");
        this.clearLayersArray("data"); 
        
        this.map.events.un({
            "addlayer": this.redraw,
            "changelayer": this.redraw,
            "removelayer": this.redraw,
            "changebaselayer": this.redraw,
            scope: this
        });
        
        OpenLayers.Control.prototype.destroy.apply(this, arguments);
    },

    /** 
     * Method: setMap
     *
     * Properties:
     * map - {<OpenLayers.Map>} 
     */
    setMap: function(map) {
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
	
        this.map.events.on({
            "addlayer": this.redraw,
            "changelayer": this.redraw,
            "removelayer": this.redraw,
            "changebaselayer": this.redraw,
            scope: this
        });
    },

    /**
     * Method: draw
     *
     * Returns:
     * {DOMElement} A reference to the DIV DOMElement containing the 
     *     switcher tabs.
     */  
    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this);

        // create layout divs
        this.loadContents();


        // populate div with current info
        this.redraw();    

        return this.div;
    },

    /** 
     * 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}  
     */
    clearLayersArray: function(layersType) {
        var layers = this[layersType + "Layers"];
        if (layers) {
            for(var i=0; i < layers.length; i++) {
                var layer = layers[i];
                OpenLayers.Event.stopObservingElement(layer.inputElem);
                OpenLayers.Event.stopObservingElement(layer.labelSpan);
            }
        }
	
	for(d in this.categoryDivs){ this.categoryDivs[d].innerHTML = "";}
        this[layersType + "LayersDiv"].innerHTML = "";
        this[layersType + "Layers"] = [];
    },


    /**
     * 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. 
     */
    checkRedraw: function() {
        var redraw = false;
        if ( !this.layerStates.length ||
             (this.map.layers.length != this.layerStates.length) ) {
            redraw = true;
        } else {
            for (var i=0; i < this.layerStates.length; i++) {
                var layerState = this.layerStates[i];
                var layer = this.map.layers[i];
                if ( (layerState.name != layer.name) || 
                     (layerState.inRange != layer.inRange) || 
                     (layerState.id != layer.id) || 
                     (layerState.visibility != layer.visibility) ) {	
                    redraw = true;
                    break;
                }    
            }
        }  
        return redraw;
    },
    
    /** 
     * 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 (!this.checkRedraw()) { 
            return this.div; 
        } 
 
        this.clearLayersArray("base");
        this.clearLayersArray("data");
        
        var containsOverlays = false;
        var containsBaseLayers = false;
        
        this.layerStates = new Array(this.map.layers.length);

        for (var i = 0; i < this.map.layers.length; i++) {

            var layer = this.map.layers[i];

            this.layerStates[i] = {
                'name': layer.name, 
                'visibility': layer.visibility,
                'inRange': layer.inRange,
                'id': layer.id
            };
        }    

        var layers = this.map.layers.slice();	

        if (!this.ascending) {
        	//layers.reverse();
        } 
	

        for( var i = 0; i < layers.length; i++) {

            var layer = layers[i];
            var baseLayer = layer.isBaseLayer;

            if (layer.displayInLayerSwitcher) {

            	if (baseLayer) {
                    containsBaseLayers = true;
                } else {
                    containsOverlays = true;
                }   
		
                var checked = (baseLayer) ? (layer == this.map.baseLayer) : layer.getVisibility();
    		
                var inputElem = document.createElement("input");
                inputElem.id = "input_" + layer.name;
				inputElem.style.float = (!baseLayer) ? "left":"";
				inputElem.style.width = (!baseLayer) ? "15px":"110px";
				inputElem.style.border = "1px solid black";
				inputElem.style.cursor = "pointer";
                inputElem.name = (baseLayer) ? "baseLayers" : layer.name;
                inputElem.type = (baseLayer) ? "button" : "checkbox";
                inputElem.value = layer.name;
                inputElem.checked = checked;
                inputElem.defaultChecked = checked;
                inputElem.style.marginTop = (baseLayer) ? "3px" : "3px";


                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");

                labelSpan.innerHTML = layer.name;
                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : "baseline";
				labelSpan.style.marginLeft = (!baseLayer) ? "0px" :"";
				labelSpan.style.width = (!baseLayer) ? "110px" :"";
				labelSpan.style.fontSize = "11px";

                OpenLayers.Event.observe(labelSpan, "click", 
                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
                                                            context)
                );
                
		
		var groupArray = (baseLayer) ? this.baseLayers : this.dataLayers;
                groupArray.push({
                    'layer': layer,
                    'inputElem': inputElem,
                    'labelSpan': labelSpan
                });


		if(layer.options.groupDiv){

			if(document.getElementById(layer.options.groupDiv)==null){

				var toogleButton = document.createElement("div");
                toogleButton.id = "toogle_" + layer.options.groupDiv;
				toogleButton.className = "toogle";
				toogleButton.style.color = "black";
				toogleButton.style.border = "solid 1px black";
				toogleButton.style.width = "118px";
				toogleButton.style.height = "18px";
				toogleButton.style.textAlign = "center";
				toogleButton.style.backgroundColor = "white";
				toogleButton.style.cursor = "pointer";
				var nome = document.createElement("span");
				nome.innerHTML = layer.options.groupLabel;
				toogleButton.appendChild(nome);
				
				var img = document.createElement("img");
				img.src = OpenLayers.Util.getImagesLocation()+"down-arrow.png";
				img.style.verticalAlign = "middle";
				img.style.marginLeft = "3px";

				toogleButton.appendChild(img);


//				var context = {
//                    	'layer': layer,
//                    	'layerSwitcher': this
//                };

                OpenLayers.Event.observe(img, "mouseup", 
                    	OpenLayers.Function.bindAsEventListener(this.toogleDisplayGroup,context)
                );
                
                OpenLayers.Event.observe(nome, "mouseup", 
                    	OpenLayers.Function.bindAsEventListener(this.onInputClick,context)
                );
 
				div = document.createElement("div");
				div.id = layer.options.groupDiv;
				div.className = 'group';
				div.style.width = '120px';
				div.style.margin = "2px";
				

				hidden = document.createElement("span");
				hidden.className = "hidden";
				hidden.id = layer.options.groupDiv+"Hidden";
				hidden.style.display = "none";
				hidden.style.backgroundColor = "white";
				hidden.style.textAlign = "center";
				hidden.style.padding = "3px";
				hidden.style.border = "solid 1px black";
				hidden.style.borderTop = "0px";

				div.appendChild(toogleButton);
				div.appendChild(hidden);
				
				this.layersDiv.appendChild(div);
				this.categoryDivs[this.categoryDivs.length] = hidden;
			}
			else{
				hidden = document.getElementById(layer.options.groupDiv+"Hidden");
			}

			
			if(document.getElementById("input_"+layer.name)==null){
			
				hidden.appendChild(inputElem);
			}
			
			if(!baseLayer){		

			hidden.appendChild(labelSpan);
			}
		}
		else{

			if(document.getElementById(layer.name) == null){

				div = document.createElement("div");
				div.id = layer.name;
				div.className = 'group';
				div.style.width = '120px';
				div.style.margin = "2px";

				if(baseLayer){

				
				var toogleButton = document.createElement("div");
                toogleButton.id = "toogle_" + layer.name;
				toogleButton.className = "toogle";
				toogleButton.style.color = "black";
				toogleButton.style.border = "solid 1px black";
				toogleButton.style.width = "118px";
				toogleButton.style.height = "18px";
				toogleButton.style.cursor = "pointer";
				toogleButton.style.textAlign = "center";
				toogleButton.style.backgroundColor = "white";
				toogleButton.innerHTML = layer.name;
				toogleButton.type ="button";				
	
				var context = {
						'inputElem': toogleButton,
                    				'layer': layer,
                    				'layerSwitcher': this
                		};

				OpenLayers.Event.observe(toogleButton, "mouseup", 
                    			OpenLayers.Function.bindAsEventListener(this.onInputClick,context)
                		);

				
				div.appendChild(toogleButton);
				this.layersDiv.appendChild(div);
				}
				else{
					
					div.appendChild(inputElem);
					div.appendChild(labelSpan);
					

					OpenLayers.Event.observe(div, "mouseup", 
                    				OpenLayers.Function.bindAsEventListener(this.onInputClick,context)
                			);
					
					this.layersDiv.appendChild(div);
				}
		     }
	
		}
    		
                
            }
        }
        
        return this.div;
    },	


    /** 
     * 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
     */

    onInputClick: function(e) {
	
        if (!this.inputElem.disabled) {
            if (this.inputElem.type == "button") {
                this.inputElem.checked = true;
                this.layer.map.setBaseLayer(this.layer);
            } else {
                this.inputElem.checked = !this.inputElem.checked;
                this.layerSwitcher.updateMap();
            }
        }
        OpenLayers.Event.stop(e);
    },

    toogleDisplayGroup: function(e) {

		if(document.getElementById(this.layer.options.groupDiv+"Hidden").style.display == "none"){
			
			document.getElementById(this.layer.options.groupDiv+"Hidden").style.display = "block";
			document.getElementById("toogle_" + this.layer.options.groupDiv).getElementsByTagName("img")[0].src = OpenLayers.Util.getImagesLocation()+"up-arrow.png";
		}
		else{
	
			document.getElementById(this.layer.options.groupDiv+"Hidden").style.display = "none";
			document.getElementById("toogle_" + this.layer.options.groupDiv).getElementsByTagName("img")[0].src = OpenLayers.Util.getImagesLocation()+"down-arrow.png";
		}
    },
    
    /**
     * Method: onLayerClick
     * Need to update the map accordingly whenever user clicks in either of
     *     the layers.
     * 
     * Parameters: 
     * e - {Event} 
     */
    onLayerClick: function(e) {
        this.updateMap();
    },


    /** 
     * 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.
     */
    updateMap: function() {

        // set the newly selected base layer        
        for(var i=0; i < this.baseLayers.length; i++) {
            var layerEntry = this.baseLayers[i];
            if (layerEntry.inputElem.checked) {
                this.map.setBaseLayer(layerEntry.layer, false);
            }
        }

        // set the correct visibilities for the overlays
        for(var i=0; i < this.dataLayers.length; i++) {
            var layerEntry = this.dataLayers[i];   
            layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
        }

    },

    
    
    /** 
     * Method: loadContents
     * Set up the labels and divs for the control
     */
    loadContents: function() {

        //configure main div
        
        this.div.style.marginTop = "3px";
        this.div.style.marginLeft = "3px";
        this.div.style.marginBottom = "3px";
        this.div.style.fontSize = "15px";    
        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 = "layersDiv";           
        
        this.baseLayersDiv = document.createElement("div");
                     
        this.dataLayersDiv = document.createElement("div");

        if (this.ascending) {
            this.layersDiv.appendChild(this.baseLayersDiv);
            this.layersDiv.appendChild(this.dataLayersDiv);
        } else {
            this.layersDiv.appendChild(this.dataLayersDiv);
            this.layersDiv.appendChild(this.baseLayersDiv);
        }    
 
        this.div.appendChild(this.layersDiv);
    },
    
    /** 
     * Method: ignoreEvent
     * 
     * Parameters:
     * evt - {Event} 
     */
    ignoreEvent: function(evt) {
        OpenLayers.Event.stop(evt);
    },

    /** 
     * Method: mouseDown
     * Register a local 'mouseDown' flag so that we'll know whether or not
     *     to ignore a mouseUp event
     * 
     * Parameters:
     * evt - {Event}
     */
    mouseDown: function(evt) {
        this.isMouseDown = true;
        this.ignoreEvent(evt);
    },

    /** 
     * 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} 
     */
    mouseUp: function(evt) {
        if (this.isMouseDown) {
            this.isMouseDown = false;
            this.ignoreEvent(evt);
        }
    },

    CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
});


