﻿/**
* Class: OpenLayers.Control.StyledLayerSwitcher
*
* Inherits from:
*  - <OpenLayers.Control.LayerSwitcher>
*/
OpenLayers.Control.StyledLayerSwitcher =
    OpenLayers.Class(OpenLayers.Control.LayerSwitcher, {

        /**  
        * Property: activeColor
        * {String}
        */
        activeColor: "#99BA34",

        /**  
        * Property: mapConfig
        * {String}
        */
        mapConfig: null,

        /**  
        * Property: filters
        * {String[]}
        */
        filters: null,

        /**  
        * Property: filtersDiv
        * {DOMElement}
        */
        filtersDiv: null,

        /**
        * Constructor: OpenLayers.Control.PanZoomBar
        */
        initialize: function(mapConfig) {

            this.mapConfig = mapConfig;
            this.filters = this.getFilters();
            OpenLayers.Control.LayerSwitcher.prototype.initialize.apply(this, arguments);
        },

        /**
        * Method: showControls
        * Hide/Show all LayerSwitcher controls depending on whether we are
        *     minimized or not
        * 
        * Parameters:
        * minimize - {Boolean}
        */
        showControls: function(minimize) {

            this.maximizeDiv.style.display = minimize ? "" : "none";
            this.minimizeDiv.style.display = minimize ? "none" : "";
            this.layersDiv.style.display = minimize ? "none" : "";
            //this.filtersDiv.style.display = minimize ? "none" : "";
        },

        /**
        * 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();

            // set mode to minimize
            if (!this.outsideViewport) {
                this.minimizeControl();
            }

            // populate filters div(s)
            if (this.filters.length > 0) this.fillFilterContainers();

            // populate div with current info
            this.redraw();

            return this.div;
        },

        /** 
        * Method: loadContents
        * Set up the labels and divs for the control
        */
        loadContents: function() {

            //configure main div
            this.div.className = "olLayerSwitcher_mainDiv";

            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.className = "olLayerSwitcher_layersDiv";
            this.layersDiv.id = "layersDiv";

            this.baseLayersDiv = document.createElement("div");
            this.baseLayersDiv.className = "olLayerSwitcher_baseLayersDiv";

            this.dataLayersDiv = document.createElement("div");
            this.dataLayersDiv.className = "olLayerSwitcher_dataLayersDiv";

            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);
            OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75); // set opacity

            // filter groups div
            if (this.filters.length > 0) {
                this.filtersDiv = document.createElement("div");
                this.filtersDiv.className = "olLayerSwitcher_filtersDiv";
                this.filtersDiv.id = "filtersDiv";
                //
                this.dataLayersDiv.className = "olLayerSwitcher_baseLayersDiv";
                //
                for (var i = 0; i < this.filters.length; i++) {
                    var filterDiv = document.createElement("div");
                    filterDiv.id = "filterDiv_" + this.filters[i];
                    filterDiv.className = "olLayerSwitcher_baseLayersDiv";
                    this.filtersDiv.appendChild(filterDiv);
                }

                this.filtersDiv.lastChild.className = "olLayerSwitcher_dataLayersDiv";
                this.div.appendChild(this.filtersDiv);

                OpenLayers.Rico.Corner.changeOpacity(this.filtersDiv, 0.75); // set opacity
            }

            // maximize button div
            var imgLocation = OpenLayers.Util.getImagesLocation();
            var sz = new OpenLayers.Size(207, 18);
            var img = imgLocation + 'layer-switcher-maximize.png';
            this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
                                      "OpenLayers_Control_MaximizeDiv",
                                      null,
                                      sz,
                                      img,
                                      "absolute");
            this.maximizeDiv.style.top = "0px";
            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(207, 18);
            this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
                                      "OpenLayers_Control_MinimizeDiv",
                                      null,
                                      sz,
                                      img,
                                      "absolute");
            this.minimizeDiv.style.top = "0px";
            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);
        },

        /** 
        * Method: maximizeControl
        * Set up the labels and divs for the control
        * 
        * Parameters:
        * e - {Event} 
        */
        maximizeControl: function(e) {

            this.div.style.width = "207px"; //20em
            this.div.style.height = "";

            this.showControls(false);

            if (e != null) {
                OpenLayers.Event.stop(e);
            }
        },

        /** 
        * 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;
            }

            //clear out previous layers 
            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.
            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;
                    }

                    // 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 = "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 = "&nbsp;" + layer.name + "&nbsp;&nbsp;&nbsp;";
                    labelSpan.style.verticalAlign = (baseLayer) ? "3px"
                                                              : "3px";
                    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
                    });

                    // Choose the map or theme layerDIV
                    var groupDiv = (baseLayer) ? this.baseLayersDiv
                                               : this.dataLayersDiv;
                    groupDiv.appendChild(inputElem); // Add elements radiobutton or checkbox
                    groupDiv.appendChild(labelSpan);

                    if (layer.options.extra != null && layer.options.extra.legend != null) {
                        var legend = layer.options.extra.legend;
                        var legendImg = document.createElement("img");
                        legendImg.src = legend.src;
                        if (legend.style != null)
                            legendImg.style = legend.style;
                        if (legend.width != null)
                            legendImg.width = legend.width;
                        if (legend.height != null)
                            legendImg.height = legend.height;
                        groupDiv.appendChild(legendImg);
                    }

                    groupDiv.appendChild(br);
                }
            }

            return this.div;
        },

        onInputClick: function(evt) {

            if (!this.inputElem.disabled) {
                if (this.inputElem.type == "radio") {
                    this.inputElem.checked = true;
                    this.layer.map.setBaseLayer(this.layer);
                } else {
                    this.inputElem.checked = !this.inputElem.checked;
                    this.layerSwitcher.updateMap();
                }
            }

            if (this.layerSwitcher.filters != null) {
                this.layerSwitcher.setLayerFilters();
            }
            OpenLayers.Event.stop(evt);
        },

        onInputKeyEvent: function(layer, element, layerswitcher) {
            if (!element.disabled) {
                if (element.type == "radio") {
                    element.checked = true;
                    layer.map.setBaseLayer(layer);
                } else {
                    element.checked = !element.checked;
                    layerswitcher.updateMap();
                }
            }
            if (layerswitcher.filters != null) {
                layerswitcher.setLayerFilters();
            }
        },


        /** 
        * Method: getFilters
        * Return list of filter group names in current layer list if there are any
        * 
        * Parameters:
        */
        getFilters: function() {

            var filterGroupList = [];
            for (var i = 0; i < this.mapConfig.mapconfig.layerlist.layer.length; i++) {
                if (this.mapConfig.mapconfig.layerlist.layer[i].options.extra != null &&
                    this.mapConfig.mapconfig.layerlist.layer[i].options.extra.filterRef != null) {
                    var filterGroup = this.mapConfig.mapconfig.layerlist.layer[i].options.extra.filterRef;
                    if (!contains(filterGroupList, filterGroup))
                        filterGroupList.push(filterGroup);
                }
            }

            // internal function for locating an array element
            function contains(a, e) {
                for (var j = 0; j < a.length; j++) if (a[j] == e) return true;
                return false;
            }

            return filterGroupList;
        },

        /** 
        * Method: fillFilterContainers
        * Generate filter lists and place them in their respective filter divs
        * 
        * Parameters:
        */
        fillFilterContainers: function() {

            // get filter group list from mapConfig
            var filterGroups = this.mapConfig.mapconfig.filterlist["filter"];

            // make filterGroups an array if it's not
            if (filterGroups[0] == null) {
                var temp = filterGroups;
                filterGroups = [];
                filterGroups.push(temp);
            }

            createFilters = OpenLayers.Function.bind(createFilters, this);

            // generate filter lists for all filter containers
            if (this.filters.length > 0) {
                for (var i = 0; i < this.filtersDiv.childNodes.length; i++) {
                    if (this.filtersDiv.childNodes[i].id.split('_')[1] != null) {
                        for (var j = 0; j < this.filters.length; j++) {
                            if (this.filtersDiv.childNodes[i].id.split('_')[1] == this.filters[j]) {
                                createFilters(this.filters[j], this.filtersDiv.childNodes[i]);
                            }
                        }
                    }
                }
            }

            // internal function for generating filters for one filter div
            function createFilters(filterGroupName, filterGroupDiv) {
                for (var f in filterGroups) {
                    var filterGroup = filterGroups[f];

                    // if the filter matches, fill up the div
                    if (filterGroup["@id"] == filterGroupName) {
                        // create group title
                        var labelTitleSpan = document.createElement("span");
                        labelTitleSpan.innerHTML = "&nbsp;Filter:  " + filterGroupName.substring(0, 1).toUpperCase() + filterGroupName.substring(1);
                        labelTitleSpan.style.verticalAlign = "3px";

                        // create line break
                        var br = document.createElement("br");

                        // add title to div
                        filterGroupDiv.appendChild(labelTitleSpan);
                        filterGroupDiv.appendChild(br);

                        // fill up the div with filter content
                        for (var e in filterGroup.property) {
                            var element = filterGroup.property[e];
                            if (element.displayName == null) continue;

                            // create input element
                            var inputFilterElem = document.createElement("input");
                            inputFilterElem.id = "input_" + element.name;
                            inputFilterElem.name = element.name;
                            inputFilterElem.type = "checkbox";
                            inputFilterElem.value = element.name;
                            //inputFilterElem.checked = true;
                            inputFilterElem.style.marginLeft = "15px";

                            var context = {
                                'inputElem': inputFilterElem,
                                'layerSwitcher': this
                            };

                            OpenLayers.Event.observe(inputFilterElem, "mouseup",
								OpenLayers.Function.bindAsEventListener(this.onFilterClick, context)
							);

                            // create span
                            var labelFilterSpan = document.createElement("span");
                            labelFilterSpan.innerHTML = "&nbsp;" + element.displayName;
                            labelFilterSpan.style.verticalAlign = "3px";
                            labelFilterSpan.style.opacity = "1";
                            OpenLayers.Event.observe(labelFilterSpan, "click",
    							OpenLayers.Function.bindAsEventListener(this.onFilterClick, context)
    						);

                            // create line break
                            var br = document.createElement("br");

                            // add elements to div
                            filterGroupDiv.appendChild(inputFilterElem);
                            filterGroupDiv.appendChild(labelFilterSpan);
                            filterGroupDiv.appendChild(br);
                        }
                    }
                }
            }
        },

        onFilterClick: function(evt) {
            this.inputElem.checked = !this.inputElem.checked; //needed because event is stopped before checkmark is set (see ignoreEvent method)
            this.layerSwitcher.setLayerFilters();
        },

        setLayerFilters: function() {
            var mapLayers = this.map.layers;
            var filterDivs = this.filtersDiv.childNodes;

            // run through map layers
            for (var i = 0; i < mapLayers.length; i++) {
                if (mapLayers[i].isBaseLayer == false &&
    				mapLayers[i].displayInLayerSwitcher == true &&
    				mapLayers[i].visibility == true &&
    				mapLayers[i].options.extra != null &&
    				mapLayers[i].options.extra.filterRef != null) {

                    // run through filterDivs to locate the corresponding filterDiv according to layer filter reference name
                    var layerFilterDiv = null;
                    for (var j = 0; j < filterDivs.length; j++) {
                        if (filterDivs[j].id.split('_')[1] == mapLayers[i].options.extra.filterRef) {
                            layerFilterDiv = filterDivs[j];
                            break;
                        }
                    }

                    // if layer filter div exists add filter params to layer url and refresh layer
                    if (layerFilterDiv != null) {
                        //var compareFilters = Array();
                        var filterUrl = "FILTER=";
                        var filterParams = "<Filter xmlns=\"http://www.opengis.net/ogc\"><And>";
                        var filterParamsTemplate = "<PropertyIsEqualTo><PropertyName>##PropertyName##</PropertyName><Literal>true</Literal></PropertyIsEqualTo>";

                        var filterDivInputs = layerFilterDiv.getElementsByTagName("INPUT");
                        for (var j = 0; j < filterDivInputs.length; j++) {
                            if (filterDivInputs[j].type == "checkbox" &&
    							filterDivInputs[j].checked == true) {
                                filterParams += filterParamsTemplate.replace("##PropertyName##", filterDivInputs[j].id.split('_')[1]);
                                //compareFilters[compareFilters.length] = this.set_Filter_EQUAL_TO(filterDivInputs[j].value, "true");
                            }
                        }

                        filterParams += "</And></Filter>";
                        filterUrl = "&" + filterUrl + escape(filterParams);

                        var layerUrl = mapLayers[i].protocol.url;
                        // remove old filter params from layer url
                        if (layerUrl.match("PropertyIsEqualTo")) {
                            layerUrl = layerUrl.substring(0, layerUrl.lastIndexOf("&"));
                        }
                        // add new filter params to url
                        if (filterParams.match("PropertyIsEqualTo")) {
                            layerUrl += filterUrl;
                        }
                        // add filter params to layer url
                        mapLayers[i].protocol.options.url = layerUrl;
                        mapLayers[i].refresh({ force: true });
                    }
                }
            }
        },

        /**
        * Method: set_Filter_EQUAL_TO
        * Creates a equal filter
        */
        set_Filter_EQUAL_TO: function(propertyName, compareValue) {
            var filter = new OpenLayers.Filter.Comparison({
                type: OpenLayers.Filter.Comparison.EQUAL_TO,
                property: propertyName,
                value: compareValue
            });
            return filter
        },

        /**
        * Method: set_Filter_BBOX
        * Creates a bbox filter
        */
        set_Filter_BBOX: function(map_projection, bounds) {
            var filter = new OpenLayers.Filter.Spatial({
                type: OpenLayers.Filter.Spatial.BBOX,
                value: bounds,
                projection: map_projection
            });
            return filter;
        },

        CLASS_NAME: "OpenLayers.Control.StyledLayerSwitcher"
    });
