/**
 * Roja.js -- RAS Openlayer Javascript Api library
 * Copyright (c) 2007-2009 - Regione Autonoma della Sardegna. 
 * Present contributors:
 *  - Core Soluzioni Informatiche srl (2007-2009) <http://www.corenet.it>
 * Please see http://webgis.regione.sardegna.it/roja/release-license.txt for the full text of the license.
 */
/*--------------------------------------------------------------------------*/

/** Contains portions of OpenLayers.js:
 *
 * OpenLayers.js -- OpenLayers Map Viewer Library
 *
 * Copyright 2005-2007 MetaCarta, Inc., released under the BSD license.
 * Please see http://svn.openlayers.org/trunk/openlayers/release-license.txt
 * for the full text of the license.
 *
 * Includes compressed code under the following licenses:
 *
 * (For uncompressed versions of the code used please see the
 * OpenLayers SVN repository: <http://openlayers.org/>)

/*--------------------------------------------------------------------------*/

/** Contains portions of Prototype.js:
 *
 * Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

/***  
 *  
 *  Contains portions of Rico <http://openrico.org/>
 * 
 *  Copyright 2005 Sabre Airline Solutions  
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License"); you
 *  may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *  
 *         http://www.apache.org/licenses/LICENSE-2.0  
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *  implied. See the License for the specific language governing
 *  permissions and limitations under the License. 
 *
**/



/** 
 * @requires OpenLayers/Control.js
 * @requires Roja.Control.FloatingPanel.LayerSwitcher
 * 
 * Class: Roja.Control.WMSSwitcher
 * To create a custom wms layer switcher.
 * This wms switcher allows to set layers into groups; 
 * each layer could be on, off, and invisible at the current scale value.
 *
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */
Roja.Control.WMSSwitcher = 
  OpenLayers.Class(OpenLayers.Control, {
    
    /** 
     * Property: layers
     * {Array(<OpenLayers.Layer>)} array of layers
     */
    layers: null,
    
    // DOM Elements
   
    /**
     * Property: labelDiv
     * {DOMElement} div element with id WMSlabelDiv 
     */
    labelDiv: null,
    
    /** 
     * Property: layersDiv
     * {DOMElement} div element with id WMSlayersDiv
     */
    layersDiv: null,

    /** 
     * Property: layerSwitcherDiv
     * {DOMElement} div element of the layer Switcher
     */
    layerSwitcherDiv: null,
  
    
     /**
     * @private 
     * Property: groups
     * Object with {DOMElements}, {Booleans} and {Strings}
     */
     groups: {
      groupDivs:{},
      checked: {},
      layers:{},
      display: {}
	},
     
       /** 
     * @private 
     * Property: dataLayers
     * {Array(<OpenLayers.Layer>)} 
     */
    dataLayers: [],
     
 
    /**
     * Constructor: OpenLayers.Control.WMSSwitcher
     * Create a new WMSSwitcher
     * 
     * Parameters:
     * options - {Object}
     */
    initialize: function(layerSwitcher) {
    	this.groups.groupDivs = {};
    	this.groups.checked = {};
    	this.groups.layers = {};
    	this.groups.display = {};
    	this.layerSwitcherDiv = layerSwitcher.layersDiv;
        this.layerSwitcher = layerSwitcher;
    },

    /**
     * APIMethod: destroy 
     * Remove Roja.Control.WMSSwitcher object
     */    
    destroy: function() {
        //clear out layers info and unregister their events 
        this.clearLayersArray();
        
        this.map.events.unregister("addlayer", this, this.redraw);
        this.map.events.unregister("changelayer", this, this.redraw);
        this.map.events.unregister("removelayer", this, this.redraw);
        this.map.events.unregister("changebaselayer", this, this.redraw);
        
        OpenLayers.Control.prototype.destroy.apply(this, arguments);
    },

    /** 
     * Method: setMap
     * invoke method setMap of OpenLayers 
     * Properties:
     * map - {<OpenLayers.Map>} 
     */
    setMap: function(map) {
        OpenLayers.Control.prototype.setMap.apply(this, arguments);

        this.map.events.register("addlayer", this, this.redraw);
        this.map.events.register("changelayer", this, this.redraw);
        this.map.events.register("removelayer", this, this.redraw);
        this.map.events.register("changebaselayer", this, this.redraw);
    },

    /**
     * Method: draw
     *
     * Returns:
     * {DOMElement} A reference to the DIV DOMElement containing the 
     *     switcher tabs.
     */  
    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this);

        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() {
      /*
        this.groups= {
	      groupDivs:{},
	      checked: {},
	      layers:{},
	      display: {},
	      names: []
	    };*/
	   
	    this.groups.groupDivs = {};
	    this.dataLayers=[];
    },

    
    /** 
     * 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(layerVisible) {
        //clear out previous layers 
               
        this.clearLayersArray();
        if (this.layerSwitcher.dataLayersDiv.childNodes.length < 2)
        {
        	this.labelDiv= document.createElement("div");
	        this.labelDiv.className = "WMSlabelDiv";
	        this.labelDiv.id = "WMSlabelDiv";
	        this.labelDiv.innerHTML = "WMS Layers";
	        
	        this.layersDiv = document.createElement("div");
	        this.layersDiv.id = "WMSlayersDiv";
	        this.layersDiv.className = "WMSlayersDiv";
	
	        this.layerSwitcher.dataLayersDiv.appendChild(this.labelDiv);
	        this.layerSwitcher.dataLayersDiv.appendChild(this.layersDiv); 
        }
      
        this.layersDiv.innerHTML = ''; 
        this.divImgLoad = document.createElement("div");
        this.divImgLoad.style.margin = "5px";
        this.layersDiv.appendChild(this.divImgLoad);  
        this.imgLoad = document.createElement("img");
       
        this.imgLoad.src= OpenLayers.ImgPath + 'loading.gif';
        this.divImgLoad.appendChild(this.imgLoad);       
        this.layers = this.getWMSLayers();
       
        for( var i = 0; i < this.layers.length; i++)
        {
    	   if (i==0) {
    	     	this.layersDiv.removeChild(this.divImgLoad); 
    	    }
            var layer = this.layers[i];
                // create group divs
            if (layer.group) {
                layer.group = layer.group.replace(/\/$/,"");
                layer.group = layer.group.replace(/^\//,"");
                this.createGroupDiv(layer.group);
            }
        }   
          
        for( var i = 0; i < this.layers.length; i++)
        {
        	    var layer = this.layers[i];
            	if (layerVisible)
            	{
            		 for( var ii = 0; ii < layerVisible.length; ii++)
			         {
			            	if (layer.physicalName == layerVisible[ii])
			            	{
			            		layer.visibility = true;
			            		break;
			            	}
			         }  	
            	}
		           
                if (layer.displayInLayerSwitcher)
                {
                	
                	var checked = layer.visibility;        	
		            
		            var divcontainer = document.createElement("div");
		            divcontainer.style.width="auto";
		            // create input element
		            var inputElem = document.createElement("input");
		            inputElem.id = "input_" + layer.logicalName;
		            inputElem.name = layer.logicalName;
		            inputElem.type = "checkbox";
		            inputElem.value = layer.logicalName;
		            inputElem.checked = checked;
		            inputElem.defaultChecked = checked;
		            
		            layer.inRange = layer.calculateInRange(this.map.getZoom());
		            
		            if (!layer.inRange) {
		                inputElem.disabled = true;
		            }
		                                   
		            var context = {
		                'inputElem': inputElem,
		                'layer': layer,
		                'WMSSwitcher': this
		            }
		            	            
		            OpenLayers.Event.observe(inputElem, "mouseup", 
		                OpenLayers.Function.bindAsEventListener(this.onInputClick,
		                                                        context)
		            );
		            
		                       
		            // create span
		            var labelSpan = document.createElement("span");
		            if (!layer.inRange) {
		                labelSpan.style.color = "gray";                  
		            }
		            labelSpan.innerHTML = layer.logicalName;
		            labelSpan.style.verticalAlign = "baseline";
		            labelSpan.className = "labelSpan";
		            OpenLayers.Event.observe(labelSpan, "click", 
		                OpenLayers.Function.bindAsEventListener(this.onInputClick,
		                                                        context)
		            );
		            // create line break
		           
		            var br = document.createElement("br");
		            
		            var groupArray = this.dataLayers;
		            groupArray.push({
		                'layer': layer,
		                'inputElem': inputElem,
		                'labelSpan': labelSpan
		            });
		           
		            if (!layer.group)
		            {
		            	this.layersDiv.appendChild(divcontainer);
			            divcontainer.appendChild(inputElem);
			            divcontainer.appendChild(labelSpan);
			            divcontainer.appendChild(br);
		            }    
		            else
		            {
		            	
		                var groupname = layer.group;
		                var div = this.groups.groupDivs[groupname];
		                // append layer to the group
		                this.appendLayerToGroups(layer);
		                div.appendChild(divcontainer);               
		                divcontainer.appendChild(inputElem);
			            divcontainer.appendChild(labelSpan);
			            divcontainer.appendChild(br);	                
		            }  
                }	         
        } 
   
      	//Added for explorer maxheight problem
		this.layerSwitcher.layersDiv.style.height = this.layerSwitcher.layersDiv.style.maxHeight;
		/*
		if (this.layerSwitcher.layersDiv.offsetHeight > this.layerSwitcher.size.h)
		{
		  this.layerSwitcher.layersDiv.style.height = this.layerSwitcher.layersDiv.style.maxHeight;
		}*/
		this.layerSwitcher.layersDiv.style.overflowX = 'auto';	
		this.layerSwitcher.layersDiv.style.overflowY = 'auto';	
        return this.div;
    },
    
     /** 
     * Method: getWMSLayers
     * fill the array layers with the wms layers
     *
     * Returns: 
     * {Array} array of layers
     */  
    getWMSLayers: function() {
        var WMSLayers = [];
        for (var i = 0; i < this.map.layers.length; i++) {
            if (this.map.layers[i].CLASS_NAME == "Roja.Layer.WMS" && (!this.map.layers[i].isBaseLayer)) {            	
                for (var y = 0; y < this.map.layers[i].layers.length; y++) {                	   
                       this.map.layers[i].layers[y].WMSLayer = this.map.layers[i]; 
                               	 
                }
                this.map.layers[i].WMSSwitcher  = this;     
                WMSLayers = WMSLayers.concat(this.map.layers[i].layers);
            }
        }
        return WMSLayers;
    },

    /** 
     * Method:
     * A label has been clicked, check or uncheck its corresponding input
     * 
     * Parameters:
     * e - {Event} 
     *
     * Context:  
     *  - {DOMElement} inputElem
     *  - {<OpenLayers.Control.WMSSwitcher>} WMSSwitcher
     *  - {<OpenLayers.Layer>} layer
     */

    onInputClick: function(e) {
        if (!this.inputElem.disabled) {
            this.layer.visibility = !this.inputElem.checked;
            this.inputElem.checked = !this.inputElem.checked;
           
            /* 
            var moveLayer = false;
        	for (var y = 0; y < this.layer.WMSLayer.layers.length; y++)
        	{        		 			        		 
        	     var inRange = this.layer.WMSLayer.layers[y].calculateInRange(this.WMSSwitcher.map.getZoom());
        	     if (inRange && this.layer.WMSLayer.layers[y].visibility)
        	     {
        	    	moveLayer = (inRange && this.layer.WMSLayer.layers[y].visibility);    
        	     }            	 		          	 
            }
           
            if (moveLayer)
            {
            	this.layer.WMSLayer.visibility = true;
            	this.layer.WMSLayer.display(true);
            }
            else
            {
            	this.layer.WMSLayer.visibility = false;
            	this.layer.WMSLayer.display(false);
            }            
            */
            this.layer.WMSLayer.redraw();
           
            this.WMSSwitcher.map.events.triggerEvent("changelayer"); 
        }
        
           
        OpenLayers.Event.stop(e);
    },  
    
    /** 
     * 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 WMSSwitcher 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);
        }
    },
    
    
     /** 
     * @private 
     * Method: createGroupDiv
     * Creates <div></div> element for group of layers defined by input string.
     * 
     * Parameters:
     * layergroup - {String} with group structure as "Parent Group/It's child"
     *  
     * Returns:
     * {DOMElement} <div></div> object for this group of layers
     */
    createGroupDiv: function(layergroup) {
        var groupNames = layergroup.split("/"); // array with layer names
        var groupName = groupNames[groupNames.length-1]; // name of the last group in the line
        var groupDiv = this.groups.groupDivs[layergroup];
        var groupNameDiv =  document.createElement("div");

        groupNameDiv.className = "groupName";
        
        // groupDiv does not exist: create
        if (!groupDiv) {

            // search for the parent div - it can be another group div, or 
            // this dataLayersDiv directly
            var parentDiv = this.groups.groupDivs[groupNames.slice(0,groupNames.length-1).join("/")];

            if (!parentDiv) {

                // dataLayersDiv is parent div
                if (groupNames.length == 1) {
                    parentDiv = this.layersDiv;
                }
                // there is no such thing, like parent div,
                else {
                    parentDiv = this.createGroupDiv( groupNames.slice(0,groupNames.length-1).join("/"));
                }
            }

            // create the div

            groupDiv = document.createElement("div");
            groupDiv.className = "layerGroup";
            if (!this.groups.display[layergroup]) {
                this.groups.display[layergroup] = "none";
            }
                     
            groupDiv.style.display= this.groups.display[layergroup];
            this.groups.groupDivs[layergroup] = groupDiv;
            
            // create the label
            var groupLbl = document.createElement("span");
            groupLbl.className = "groupLabel";
            groupLbl.innerHTML=groupName;

            // setup mouse click event on groupLbl
            OpenLayers.Event.observe(groupLbl, "mouseup", 
                OpenLayers.Function.bindAsEventListener(
                    this.onGroupClick, {layergroup: layergroup, groups:
                    this.groups,layerswitcher:this}));
            
            // create input checkbox
            var groupInput = document.createElement("input");
            groupInput.id = "input_" + groupNames.join("_");
            groupInput.name = groupNames.join("_");
            groupInput.type = "checkbox";
            groupInput.value = layergroup;
            groupInput.checked = false;
            groupInput.defaultChecked = false;
            if (!this.groups.checked[layergroup]) {
                this.groups.checked[layergroup] = false;
            }

            if (this.groups.layers[layergroup]) 
            {
	            this.groups.checked[layergroup] = false;
            	for (var i=0; i<this.groups.layers[layergroup].length;i++)
            	{
            		if (this.groups.layers[layergroup][i].visibility == true)
            		{
    			        this.groups.checked[layergroup]=true;
    			        break;
            		}
            	}
            }
            
            groupInput.checked = this.groups.checked[layergroup];
            groupInput.defaultChecked = this.groups.checked[layergroup];

            // create empty array of layers
            if (!this.groups.layers[layergroup]) {
                this.groups.layers[layergroup] = [];
            }
            
            // setup mouse click event on groupInput
            var context = {groupDiv: groupDiv,
                            layerSwitcher: this,
                            inputElem: groupInput
                            };

            OpenLayers.Event.observe(groupInput, "mouseup", 
                OpenLayers.Function.bindAsEventListener(
                    this.onInputGroupClick, context));
            
            // append to parent div
            groupNameDiv.appendChild(groupInput);
            groupNameDiv.appendChild(groupLbl);
            parentDiv.appendChild(groupNameDiv);
            parentDiv.appendChild(groupDiv);

        }

        return this.groups.groupDivs[layergroup];
    },
    
  /**
     * @private 
     * Method: onGroupClick
     * On group label was clicked
     * 
     * Context: 
     * layergroup - {String} 
     * groups - {Array} of {DOMElements}
     */
    onGroupClick: function(e) {
        var layergroup = this.layergroup;
        var div = this.groups.groupDivs[layergroup];
        if (div) {
            var colapse = (div.style.display != "block" ? true : false);
            this.layerswitcher.colapseGroup(layergroup,colapse);
        }
		//Added for explorer maxheight problem
		this.layerswitcher.layersDiv.style.height = '';
		
    },
    
    
      /** 
     * @private 
     * Method: addLayerToGroups
     * each group has own {Array} with list of layrs. E.g. layer with group
     * "group1/group2" is member of two groups: "group1" and
     * "group1/group2"
     * 
     * Parameters:
     * layer 
     *  
     */
    appendLayerToGroups: function(layer) {
        var groupNames = layer.group.split("/");
        var groupName = null;

        for (var i = 1; i <= groupNames.length; i++) {
            groupName = groupNames.slice(0,i).join("/");
            if (!this.isInGroup(groupName,layer)) {
                this.groups.layers[groupName].push(layer);
		        //Added to set group visibility
		        if (layer.visibility == true)
		        {
			        this.groups.checked[groupName]=true;
		        }
            }
        }
    },
    
    /** 
     * @private 
     * Method: isInGroup
     * 
     * 
     * Parameters:
     * groupName - {String} name of the group
     * layer 
     *  
     * Returns:
     * {Boolean} -- the layer is available in this group with specified
     * name or not
     */
    isInGroup: function (groupName, layer) {
        for (var j = 0; j < this.groups.layers[groupName].length; j++) {
            if (this.groups.layers[groupName][j].physicalName == layer.physicalName) {
                return true;
            }
        }
        return false;
    },

    
    /**
     * Method: colapseGroup
     * Toggle group div with layers visibility
     * 
     * Context: 
     * layergroup - {String} 
     * colapse - {Boolean}
     */
    colapseGroup: function(layergroup,colapse) {
        var div = this.groups.groupDivs[layergroup];
        if (div) {
            div.style.display = (colapse === true ? "block" : "none");
            this.groups.display[layergroup] = div.style.display;
        }
    },
        
     /** 
     * @private 
     * Method:
     * A group label has been clicked, check or uncheck its corresponding input
     * 
     * Parameters:
     * e - {Event} 
     *
     * Context:  
     *  - {DOMElement} inputElem
     *  - {<Roja.Control.LayerSwitcher>} layerSwitcher
     *  - {DOMElement} groupDiv
     */
    onInputGroupClick: function(e) {
        // setup the check value
        var check = !this.inputElem.checked;

        // get all <input></input> tags in this div
        var inputs = this.groupDiv.getElementsByTagName("input");

        // check the group input, other inputs are in groupDiv,
        // inputElem is in parent div      
        this.inputElem.checked=check;

        // store to groupCheckd structure, where it can be later found
        this.layerSwitcher.groups.checked[this.inputElem.value] = check;

        for (var i = 0; i < inputs.length; i++) {
            // same as above
            inputs[i].checked=check;
            this.layerSwitcher.groups.checked[inputs[i].value] = check;
        }  
       
        var layerRedraw = null;
        // groups are done, now the layers
        var dataLayers = this.layerSwitcher.dataLayers;
        for (var j = 0; j < dataLayers.length; j++) {
            var layerEntry = dataLayers[j];   
            if (this.layerSwitcher.isInGroup(this.inputElem.value,layerEntry.layer)) 
	        {
                layerEntry.inputElem.checked = check;
				layerEntry.layer.visibility = check;
				layerRedraw = layerEntry.layer.WMSLayer;						
	        }
        }
        
        if (layerRedraw!=null)
        {
        	   /* 
        		var moveLayer = false;
	        	for (var y = 0; y < layerRedraw.layers.length; y++)
	        	{    	        					        		 
	        	     var inRange = layerRedraw.layers[y].calculateInRange(this.layerSwitcher.map.getZoom());
	        	     if (inRange && layerRedraw.layers[y].visibility)
	        	     {
	        	     	moveLayer = (inRange && layerRedraw.layers[y].visibility);  
	        	     }            		  		          	 
	            }
	          
	            if (moveLayer)
	            {
	            	layerRedraw.visibility = true;
	            	layerRedraw.display(true);
	            }
	            else
	            {
	            	layerRedraw.visibility = false;
	            	layerRedraw.display(false);
	            }         
	            */
	            layerRedraw.redraw();	 	
	            
        }
            
       	this.layerSwitcher.map.events.triggerEvent("changelayer");
      	
        OpenLayers.Event.stop(e);    
       
        
    },
    
    
    CLASS_NAME: "Roja.Control.WMSSwitcher"
});

