/*
 * Fred 2014
 * extended de styledLayerControl
 */



L.Control.ExtendedLayerControl = L.Control.Layers.extend({
    options: {
        collapsed: true,
        position: 'topright',
        autoZIndex: true
    },
    initialize: function(baseLayers, groupedOverlays, options) {
        var i,
                j;
        L.Util.setOptions(this, options);

        this._layers = {};
        this._lastZIndex = 0;
        this._handlingClick = false;
        this._groupList = [];
        this._domGroups = [];
        this.identifyLayer;

        for (i in baseLayers) {
            for (var j in baseLayers[i].layers) {
                this._addLayer(baseLayers[i].layers[j], j, baseLayers[i], false);
            }
        }

        for (i in groupedOverlays) {
            for (var j in groupedOverlays[i].layers) {
                this._addLayer(groupedOverlays[i].layers[j], j, groupedOverlays[i], true);
            }
        }


    },
    onAdd: function(map) {
        this._initLayout();
        this._update();

        map
                .on('layeradd', this._onLayerChange, this)
                .on('layerremove', this._onLayerChange, this);

        return this._container;
    },
    onRemove: function(map) {
        map
                .off('layeradd', this._onLayerChange)
                .off('layerremove', this._onLayerChange);
    },
    addBaseLayer: function(layer, name, group) {
        this._addLayer(layer, name, group, false);
        this._update();
        return this;
    },
    addOverlay: function(layer, name, group) {
        this._addLayer(layer, name, group, true);
        this._update();
        return this;
    },
    removeLayer: function(layer) {
        var id = null;
        if (layer.ExtendedLayerControl !== undefined && layer.ExtendedLayerControl.layerTypeId === 0) {
            id = layer._leaflet_id; // cluster
        } else {
            id = layer.layer._leaflet_id;
        }
        //id = layer.layer._leaflet_id;
        delete this._layers[id];
        this._update();
        return this;
    },
    removeGroup: function(group_Name) {
        for (group in this._groupList) {
            if (this._groupList[group].groupName == group_Name) {
                for (layer in this._layers) {
                    if (this._layers[layer].group && this._layers[layer].group.name == group_Name) {
                        delete this._layers[layer];
                    }
                }
                delete this._groupList[group];
                this._update();
                break;
            }
        }
    },
    _initLayout: function() {
        var className = 'leaflet-control-layers',
                container = this._container = L.DomUtil.create('div', className);

        //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
        container.setAttribute('aria-haspopup', true);

        if (!L.Browser.touch) {
            L.DomEvent.disableClickPropagation(container);
            L.DomEvent.on(container, 'wheel', L.DomEvent.stopPropagation);
        } else {
            L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
        }

        var section = document.createElement('section');
        section.className = 'ac-container ' + className + '-list';

        var form = this._form = L.DomUtil.create('form');

        section.appendChild(form);

        if (this.options.collapsed) {
            if (!L.Browser.android) {
                L.DomEvent
                        .on(container, 'mouseover', this._expand, this)
                        .on(container, 'mouseout', this._collapse, this);
            }
            var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
            link.href = '#';
            link.title = 'Layers';

            if (L.Browser.touch) {
                L.DomEvent
                        .on(link, 'click', L.DomEvent.stop)
                        .on(link, 'click', this._expand, this);
            } else {
                L.DomEvent.on(link, 'focus', this._expand, this);
            }

            this._map.on('click', this._collapse, this);
            // TODO keyboard accessibility

        } else {
            this._expand();
        }

        this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
        this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);

        container.appendChild(section);

        // process options of ac-container css class - to options.container_width and options.container_maxHeight
        for (var c = 0; c < (containers = container.getElementsByClassName('ac-container')).length; c++) {
            if (this.options.container_width) {
                containers[c].style.width = this.options.container_width;
            }

            // set the max-height of control to y value of map object
            this._default_maxHeight = this.options.container_maxHeight ? this.options.container_maxHeight : (this._map._size.y - 70);
            containers[c].style.maxHeight = this._default_maxHeight + "px";

        }

        window.onresize = this._on_resize_window.bind(this);

    },
    _on_resize_window: function() {
        // listen to resize of screen to reajust de maxHeight of container
        for (var c = 0; c < containers.length; c++) {
            // input the new value to height
            containers[c].style.maxHeight = (window.innerHeight - 90) < this._default_maxHeight ? (window.innerHeight - 90) + "px" : this._default_maxHeight + "px";
        }
    },
    _addLayer: function(layer, name, group, overlay) {
        var id = L.Util.stamp(layer);

        this._layers[id] = {
            layer: layer,
            name: name,
            overlay: overlay
        };

        if (group) {
            var groupId = this._groupList.indexOf(group);

            // if not find the group search for the name
            if (groupId === -1) {
                for (g in this._groupList) {
                    if (this._groupList[g].groupName == group.groupName) {
                        groupId = g;
                        break;
                    }
                }
            }

            if (groupId === -1) {
                groupId = this._groupList.push(group) - 1;
            }

            this._layers[id].group = {
                name: group.groupName,
                id: groupId,
                expanded: group.expanded
            };
        }

        if (this.options.autoZIndex && layer.setZIndex) {
            this._lastZIndex++;
            layer.setZIndex(this._lastZIndex);
        }
    },
    _update: function() {
        if (!this._container) {
            return;
        }

        this._baseLayersList.innerHTML = '';
        this._overlaysList.innerHTML = '';
        this._domGroups.length = 0;

        var baseLayersPresent = false,
                overlaysPresent = false,
                i,
                obj;

        for (i in this._layers) {
            obj = this._layers[i];
            this._addItem(obj);
            overlaysPresent = overlaysPresent || obj.overlay;
            baseLayersPresent = baseLayersPresent || !obj.overlay;
        }

    },
    _onLayerChange: function(e) {
        var obj = this._layers[L.Util.stamp(e.layer)];

        if (!obj) {
            return;
        }

        if (!this._handlingClick) {
            this._update();
        }

        var type = obj.overlay ?
                (e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
                (e.type === 'layeradd' ? 'baselayerchange' : null);

        if (type) {
            this._map.fire(type, obj);
        }
    },
    // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
    _createRadioElement: function(name, checked) {

        var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
        if (checked) {
            radioHtml += ' checked="checked"';
        }
        radioHtml += '/>';

        var radioFragment = document.createElement('div');
        radioFragment.innerHTML = radioHtml;

        return radioFragment.firstChild;
    },
    _addItem: function(obj) {
        var label = document.createElement('div'),
                input,
                checked = this._map.hasLayer(obj.layer),
                container;


        if (obj.overlay) {
            input = document.createElement('input');
            input.type = 'checkbox';
            input.className = 'leaflet-control-layers-selector';
            input.defaultChecked = checked;

            label.className = "menu-item-checkbox";

        } else {
            input = this._createRadioElement('leaflet-base-layers', checked);

            label.className = "menu-item-radio";
        }


        input.layerId = L.Util.stamp(obj.layer);

        L.DomEvent.on(input, 'click', this._onInputClick, this);

        var name = document.createElement('span');
        name.innerHTML = ' ' + obj.name;

        label.appendChild(input);
        label.appendChild(name);

        // configure the delete button for layers with attribute removable = true
        if (obj.layer.ExtendedLayerControl && obj.layer.ExtendedLayerControl.removable) {
            var bt_delete = document.createElement("button");
            bt_delete.setAttribute("class", "fa fa-trash bt_properties bt_deleteLayer");
            L.DomEvent.on(bt_delete, 'click', this._onDeleteClick, this);
            label.appendChild(bt_delete);
        }
        // configure the propoerties button for layers with attribute haveProperties = true
        if (obj.layer.ExtendedLayerControl && obj.layer.ExtendedLayerControl.haveProperties) {
            var bt_properties = document.createElement("button");
            bt_properties.setAttribute("class", "fa fa-list-ul bt_properties");
            bt_properties.setAttribute("style", "color: blue;");
            L.DomEvent.on(bt_properties, 'click', this._onPropertiesClick, this);
            label.appendChild(bt_properties);
        }
        // configure the propoerties button for layers with attribute activeIdentify = true
        if (obj.layer.ExtendedLayerControl && obj.layer.ExtendedLayerControl.activeIdentify) {
            var bt_identify = document.createElement("button");
            bt_identify.setAttribute("class", "fa fa-info bt_properties bt_identify");
            bt_identify.setAttribute("value", "off");
            L.DomEvent.on(bt_identify, 'click', this._onIdentifyClick, this);
            label.appendChild(bt_identify);
        }


        if (obj.overlay) {
            container = this._overlaysList;
        } else {
            container = this._baseLayersList;
        }

        var groupContainer = this._domGroups[obj.group.id];

        if (!groupContainer) {

            groupContainer = document.createElement('div');
            groupContainer.id = 'leaflet-control-accordion-layers-' + obj.group.id;

            // verify if group is expanded
            var s_expanded = obj.group.expanded ? ' checked = "true" ' : '';

            // verify if type is exclusive
            var s_type_exclusive = this.options.exclusive ? ' type="radio" ' : ' type="checkbox" ';

            inputElement = '<input id="ac' + obj.group.id + '" name="accordion-1" class="menu" ' + s_expanded + s_type_exclusive + '/>';
            inputLabel = '<label for="ac' + obj.group.id + '">' + obj.group.name + '</label>';

            article = document.createElement('article');
            article.className = 'ac-large';
            article.appendChild(label);

            // process options of ac-large css class - to options.group_maxHeight property
            if (this.options.group_maxHeight) {
                article.style.maxHeight = this.options.group_maxHeight;
            }

            groupContainer.innerHTML = inputElement + inputLabel;
            groupContainer.appendChild(article);
            container.appendChild(groupContainer);

            this._domGroups[obj.group.id] = groupContainer;
        } else {
            groupContainer.lastElementChild.appendChild(label);
        }

        return label;
    },
    _onInputClick: function() {
        var i,
                input,
                obj,
                inputs = this._form.getElementsByTagName('input'),
                inputsLen = inputs.length;

        this._handlingClick = true;

        for (i = 0; i < inputsLen; i++) {
            input = inputs[i];
            obj = this._layers[input.layerId];

            if (!obj) {
                continue;
            }

            if (input.checked && !this._map.hasLayer(obj.layer)) {
                this._map.addLayer(obj.layer);

            } else if (!input.checked && this._map.hasLayer(obj.layer)) {
                this._map.removeLayer(obj.layer);
            }
        }

        this._handlingClick = false;
    },
    _onDeleteClick: function(obj) {
        var node = obj.target.parentElement.childNodes[0];
        n_obj = this._layers[node.layerId];

        // verify if obj is a basemap and checked to not remove
        if (!n_obj.overlay) {
            return false;
        }

        obj.target.parentNode.remove();
        this.removeLayer(n_obj);
        if (this._map.hasLayer(n_obj.layer)) {
            this._map.removeLayer(n_obj.layer);
        }

        return false;
    },


    resetIdentify: function() { 
            $(".bt_identify").val('off');
            this.identifyLayer = undefined;
            return false;  
    },


    _onIdentifyClick: function(obj) {       
        
        obj.preventDefault();
        
        var node = obj.target.parentElement.childNodes[0];
        this.identifyLayer = this._layers[node.layerId].layer;
        
        if ($(obj.target).val() === 'on') {
            this.resetIdentify();
            return false
        }
        
        $(".bt_identify").val('off');
        $(obj.target).val('on');
        
        $('#map').css('cursor', 'crosshair');

        return false;
        
    },
    
    
    _onPropertiesClick: function(obj) {
        
        obj.preventDefault();
        
        var node = obj.target.parentElement.childNodes[0];
        n_obj = this._layers[node.layerId];

        //var layerPropertyDiv = document.getElementById("layerProperty");
        var layerPropertyDiv = $("#layerProperty");
        //$( "#layerProperty" ).empty();
        layerPropertyDiv.empty();

        var p = document.createElement('p');

        var l_name = document.createTextNode("Name: " + n_obj.name);
        p.appendChild(l_name);
        p.appendChild(document.createElement('br'));

        var l_type = document.createTextNode("Type: " + n_obj.layer.ExtendedLayerControl.layerTypeName);
        p.appendChild(l_type);
        p.appendChild(document.createElement('br'));


        // serv url (except cluster)
        if (n_obj.layer.ExtendedLayerControl.layerTypeId > 0) {
            var l_url = document.createTextNode("Layer URL");
            var a = document.createElement('a');
            a.appendChild(l_url);
            a.title = "Layer URL";
            a.href = n_obj.layer._url;
            a.target = "_blank";
            p.appendChild(a);
            layerPropertyDiv.append(p);
        }

        // legend (except cluster)
        if (n_obj.layer.ExtendedLayerControl.layerTypeId > 0) {
            layerPropertyDiv.append(document.createElement('hr'));
            layerPropertyDiv.append(document.createTextNode("Legend:"));
            layerPropertyDiv.append(document.createElement('p'));
            if (!n_obj.layer.ExtendedLayerControl.fromColor) {
                var wmsName = n_obj.layer.wmsParams.layers;
                var legend_url = n_obj.layer._baseUrl + "service=WMS&request=GetLegendGraphic&version=1.1.1&format=image%2Fpng&layer=" + wmsName;
                var img = document.createElement("IMG");
                img.setAttribute("src", legend_url);
                layerPropertyDiv.append(img);
            } else { // color ramp
                var myspan = document.createElement('i');
                myspan.setAttribute("class", "fa fa-square fa-2x");
                myspan.setAttribute("style", "color: #" + n_obj.layer.ExtendedLayerControl.fromColor + ";");
                layerPropertyDiv.append(myspan);
                var label1 = document.createTextNode("   Low");
                layerPropertyDiv.append(label1);
                layerPropertyDiv.append(document.createElement('p'));
                var myspan2 = document.createElement('i');
                myspan2.setAttribute("class", "fa fa-square fa-2x");
                myspan2.setAttribute("style", "color: #" + n_obj.layer.ExtendedLayerControl.toColor + ";");
                layerPropertyDiv.append(myspan2);
                var label2 = document.createTextNode("   Hight");
                layerPropertyDiv.append(label2);
            }
        }
        
        layerPropertyDiv.append(document.createElement('hr'));
        layerPropertiesBar.show();

        return false;
    },
    _expand: function() {
        L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
    },
    _collapse: function() {
        this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
    },
    
    
    getFeatureInfoEvent: function(e) {
        if (this.identifyLayer) this.getFeatureInfo(e.containerPoint, e.latlng,this.identifyLayer,this.showFeatureInfo);
    },

    getFeatureInfo: function(point, latlng, layer, callback) {
        var params = this.getFeatureInfoParams(point, layer),
                url = layer._baseUrl + L.Util.getParamString(params, layer._url);

        this.showWaiting();
        this.ajax(url, done);

        function done(result) {
            this.hideWaiting();
            var text = this.parseFeatureInfo(result, url);
            callback.call(this, latlng, text);
        }
    },
    ajax: function(url, callback) {
        ajax.call(this, url, callback);
    },
//    getIdentifyLayers: function() {
//        if (this.options.identifyLayers)
//            return this.options.identifyLayers;
//        return Object.keys(this._subLayers);
//    },
    
    getFeatureInfoParams: function(point, layer) {

        var wmsParams = layer.wmsParams;
        var map = layer._map;
        var bounds = map.getBounds();
        var size = map.getSize();
        var wmsVersion = parseFloat(wmsParams.version);
        var crs = layer.options.crs || map.options.crs;
        var projectionKey = wmsVersion >= 1.3 ? 'crs' : 'srs';
        var nw = crs.project(bounds.getNorthWest());
        var se = crs.project(bounds.getSouthEast());
        
        // Assemble WMS parameter string
        var params = {
            'width': size.x,
            'height': size.y
        };
        params[projectionKey] = crs.code;
        params.bbox = (
            wmsVersion >= 1.3 && crs === L.CRS.EPSG4326 ?
            [se.y, nw.x, nw.y, se.x] :
            [nw.x, se.y, se.x, nw.y]
        ).join(',');

        L.extend(wmsParams, params);
        
        var infoParams = {
            'request': 'GetFeatureInfo',
            'info_format': 'text/html',
            //'info_format': 'application/json',
            //'query_layers': layers.join(','),
            'query_layers': layer.wmsParams.layers,
            'X': point.x,
            'Y': point.y,
            'FEATURE_COUNT':50
        };
        return L.extend({}, wmsParams, infoParams);
    },
    parseFeatureInfo: function(result, url) {
        if (result == "error") {
            // AJAX failed, possibly due to CORS issues.
            // Try loading content in <iframe>.
            result = "<iframe src='" + url + "' style='border:none'>";
        }
        return result;
    },
    showFeatureInfo: function(latlng, info) {
        if (!this._map) {
            return;
        }
        if (info.length == 0) {
            return;
        }
        var myPop = this._map.openPopup(info, latlng);
    },
    showWaiting: function() {
        if (!this._map) return;
        this._map._container.style.cursor = "progress";
    },
    hideWaiting: function() {
        if (!this._map) return;
        this._map._container.style.cursor = "default";
    }
});

L.Control.extendedLayerControl = function(baseLayers, overlays, options) {
    return new L.Control.ExtendedLayerControl(baseLayers, overlays, options);
};

// Simple AJAX helper (since we can't assume jQuery etc. are present)
function ajax(url, callback) {
    var context = this,
        request = new XMLHttpRequest();
    request.onreadystatechange = change;
    
    url = OpenLayers.ProxyHost + encodeURIComponent(url) ;
    
    request.open('GET', url);
    request.send();

    function change() {
        if (request.readyState === 4) {
            if (request.status === 200) {
                callback.call(context, request.responseText);
            } else {
                callback.call(context, "error");
            }
        }
    }
}