<html>
<head>
    <title>Catalogue of web mapping services (alpha)</title>
    <link rel="stylesheet" type="text/css" href="../../externals/ext/resources/css/ext-all.css" />
    <link rel="stylesheet" type="text/css" href="../../externals/ext/resources/css/xtheme-gray.css" />
    <link rel="stylesheet" type="text/css" href="../../externals/openlayers/theme/default/style.css" />
    <link rel="stylesheet" type="text/css" href="../../core/theme/css/styler.css" />
    <link rel="stylesheet" type="text/css" href="../../core/theme/css/popup-gray.css" />
    <link rel="stylesheet" type="text/css" href="./theme/column-tree.css" />
        
    <script type="text/javascript" src="../../externals/ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../../externals/ext/ext-all-debug.js"></script>
    <script type="text/javascript" src="../../externals/openlayers/OpenLayers.js"></script>
    <!-- <script type="text/javascript" src="../../externals/openlayers/lib/OpenLayers.js"></script> -->
    <script>
    window.scriptLocation = "../../core/";
    </script>
    <script type="text/javascript" src="../../core/lib/GeoExt.js"></script> 
    <script type="text/javascript" src="./AddLayerWindow.js"></script> 
    <script type="text/javascript" src="./CustomFilterBuilder.js"></script>
    <script type="text/javascript" src="./LayerTree.js"></script>
    <script type="text/javascript" src="./LayerNodeUI.js"></script>
    <script type="text/javascript" src="./MaxFeaturesWarning.js"></script>

    <script>

    Ext.BLANK_IMAGE_URL = "../../externals/ext/resources/images/default/s.gif";

    // These should go in a better spot.
    function recordize(attrs){
        var records = new Array();
            var mapping = {
            "double": "float",
            "string": "string",
            "long" :  "int",
            "MultiSurfacePropertyType": "auto"
        }
    
        for (var i = 0; i < attrs.length; i++){
            var a = attrs[i];
            var k = a.type.replace(/.*:/, '');

            if (mapping[k]){
                records.push({
                     name: a.name,  
                     mapping: a.name,
                     type: mapping[k]
                });
            } 
        }

        return Ext.data.Record.create(records);
    }

    function columnize(attrs){
        var cols = new Array();
        for (var i = 0; i < attrs.length; i++){
            var a = attrs[i];
            if (a.type){
            cols.push({
                id: a.name,
                header: a.name, 
                dataIndex: a.name, 
                hidden: (i>11 | a.type.startsWith('gml:')),
                sortable: true
            });
            } else {
                console.log(a.name + " has no type");
            }
        }

        return cols;
    }

    GeoExt.Drake = {
        filterBuilder: null,
        grid: null,
        
        filter: null,
        store: null,
        fields: null,
        
        map: null,
        wfsStoreLayer: null,
        
        load: function(config) {
            OpenLayers.Util.extend(this, config);
            
            // Show the error window on network failures.
            GeoExt.RequestMgr.on("requestexception", function(request, url) {
                var errorWindow = new GeoExt.ErrorWindow({
                    request: request,
                    url: url,
                    modal: true
                });
                
                errorWindow.show();
            }, this);
            
            var attributeStore = new GeoExt.data.AttributesStore({
                url: this.wfsUrl + "?typename=" + this.getFullType() + "&request=describefeaturetype"
            });
    
            attributeStore.load({
                // TODO: Rename x to something meaningful.
                callback: function(x){
                    this.fields = [];
    
                    for (var i = 0; i < x.length; i++){
                        this.fields.push(x[i].data);
                    }
    
                    this.initFilter();
                    this.initFeatureStore();
                    this.initWMSStore();
                    this.initMap();
                    
                    this.initFilterBuilder();
                    this.initPagingBar();
                    this.initFeatureGrid();
                    this.initLayerTree();
                    this.initLegendPanel();
                    
                    new Ext.Viewport({
                        layout: 'border',
                        items: [
                            new Ext.Panel({
                                region: "west",
                                layout: "border",
                                items: [
                                    this.filterBuilder,
                                    this.layerTree
                                ],
                                width: 370,
                                collapsible: true,
                                collapseMode: "mini",
                                split: true
                            }),
                            this.mapPanel,
                            //this.grid,
                            this.legendPanel
                        ]
                    });
                }, 
                scope: this
            });
        },
        
        initFilter: function() {
            this.filter = new OpenLayers.Filter.Logical({
                type: OpenLayers.Filter.Logical.OR,
                filters: []
            });
        },
        
        createProxy: function(params) {
            params = params || {};
            var type = params.type || this.featureType;
            var ns = params.namespace || 'http://emsmaps.intranet.who.int:8080/geoserver/WHO';
            var prefix = params.prefix || this.featurePrefix;

            var proto = new OpenLayers.Protocol.WFS({
                url: this.wfsUrl,
                featureType: type,
                featureNS: ns,
                featurePrefix: prefix,
                srsName: "EPSG:4326",
                version: "1.1.0",
                maxFeatures: this.maxFeatures
            });
        
            return new GeoExt.data.ProtocolProxy({protocol: proto});
        },
        
        initFeatureStore: function() {
            // create the data store
            this.featureStore = new Ext.data.Store({
                proxy: this.createProxy(),
                remoteSort: true,
                reader: new Ext.data.JsonReader({}, [])
            });
            
            var showMaxFeaturesWarning = true;
            
            this.featureStore.on("load", function() {
                if (showMaxFeaturesWarning && this.featureStore.getTotalCount() >= this.maxFeatures) {
                    var maxFeaturesWarning = new GeoExt.drake.MaxFeaturesWarning({
                        maxFeatures: this.maxFeatures
                    });
                    
                    maxFeaturesWarning.on("donotshowchange", function(newValue) {
                        showMaxFeaturesWarning = !newValue;
                    }, this);
                    
                    maxFeaturesWarning.show();
                }
            }, this);
        },
        
        initWMSStore: function() {
            this.wmsStore = new Ext.data.GroupingStore({
                url: this.wmsUrl + "?request=getcapabilities",
                reader: new GeoExt.data.WMSCapabilitiesReader(),
                sortInfo: {field: 'prefix'},
                groupField: 'prefix'
            });
        },
        
        initFilterBuilder: function() {
            this.filterBuilder = new GeoExt.drake.CustomFilterBuilder({
                title: "Filter Builder",
                region: "south",
                height: 175,
                autoScroll: true,
                filter: this.filter.clone(),
                attributes: new GeoExt.data.AttributesStore({
                    url: this.getWFSLayerURL(this.getFullType()), 
                    ignore: {name: "the_geom"}
                }),
                addToToolbar: ["->", new Ext.form.Checkbox({
                    boxLabel: "Use Filter",
                    enableToggle: true, 
                    handler: function(checkbox, checked) {
                        if (checked){
                            this.featureStore.proxy.setOGCFilter(this.filterBuilder.getFilter());
                            this.filterBuilder.on("change", this.updateQueryFilter, this);
                        } else {
                            this.featureStore.proxy.setOGCFilter(null);
                            this.filterBuilder.un("change", this.updateQueryFilter, this);
                        }
                        this.reloadFeatureStore();
                    },
                    scope: this
                })] 
            });
        },
        
        initPagingBar: function() {
            this.pagingBar = new Ext.PagingToolbar({
                pageSize: 7, 
                store: this.featureStore,
                displayInfo: true,
                displayMsg: 'Displaying features {0} - {1} of {2}',
                emptyMsg: 'No features to display'
            });
        },
        
        initMap: function() {
            this.map = new OpenLayers.Map({
                theme: null,
                controls: [],
                units: "m",
                projection: new OpenLayers.Projection("EPSG:4326"),
                // maxExtent: new OpenLayers.Bounds(-139.53227612499998,20.816194750000008,-59.55180737499998,55.44510100000001) 
                maxExtent: new OpenLayers.Bounds(-180,-90,180,90) 
            });
                  
            this.wfsStoreLayer = new GeoExt.layer.Vector("Vector Layer", {
                    store: this.featureStore,
                    displayInLayerSwitcher: false
                }
            );
            /*
            var baseLayer = new OpenLayers.Layer.WMS(
                "OpenStreetMap",
                "http://demo.opengeo.org/geoserver_openstreetmap/gwc/service/wms",
                {layers: 'openstreetmap', format:'image/png'}, {isBaseLayer: true}
            );
    
            var vmap0 = new OpenLayers.Layer.WMS(
                "Metacarta Vmap0",
                "http://labs.metacarta.com/wms/vmap0",
                {layers: 'basic'}, {isBaseLayer: true}
            );
    */
    
            var countries = new OpenLayers.Layer.WMS(
                "WHO Official Political Boundaries",
                "/geoserver/wms?",
                {layers: 'WHO:ith_list_polygon'}, {isBaseLayer: true}
            );
                        
                        var gaul = new OpenLayers.Layer.WMS(
                "FAO Admin 1 Level (GAUL)",
                "http://geonetwork3.fao.org/ows/12691_1?",
                {layers: 'gaul_first_level', format:'image/png'}, {isBaseLayer: false, visibility:false}
            );
                        
                        var gpd = new OpenLayers.Layer.WMS(
                "FAO Global Poultry Density",
                "http://geonetwork3.fao.org/ows/12720?",
                {layers: 'poultry_density', format:'image/png'}, {isBaseLayer: false, visibility:false}
            );
                        
                        var pig = new OpenLayers.Layer.WMS(
                "FAO Global Pig Density",
                "http://geonetwork3.fao.org/ows/12719?",
                {layers: 'pig_density', format:'image/png'}, {isBaseLayer: false, visibility:false}
            );
                        var pop = new OpenLayers.Layer.WMS(
                "Landscan Global Population",
                "http://geonetwork3.fao.org/ows/1261?",
                {layers: 'landscan_global_population_2000', format:'image/png'}, {isBaseLayer: false}
            );
                        
                        var apcp = new OpenLayers.Layer.WMS("IRI 6-day Forecast Precipitation","http://iridl.ldeo.columbia.edu/expert/home/.mbell/.IRI/.MD/.IFRC/.ESRL/.PSD/.refcst/.tot6day/.apcp/S/last/VALUE/X/Y/fig-/colors/black/thin/countries_gaz/-fig//color_smoothing/null/psdef/wmsfigmap",
                {layers: 'apcp', transparent: 'false', wrapDateLine: 'true', srs: 'EPSG:4326' }, {isBaseLayer: false, visibility:false});
                        
                        var prcpa = new OpenLayers.Layer.WMS("IRI Precipitation Anomaly","http://iridl.ldeo.columbia.edu/SOURCES/.IRI/.MD/.CID/wmsmap",
                {layers: 'prcp_anomaly', transparent: 'false', wrapDateLine: 'true', srs: 'EPSG:4326' }, {isBaseLayer: false, visibility:false});
                        
                        var csmt = new OpenLayers.Layer.WMS("IRI Months Suitable for Malaria Transmission","http://iridl.ldeo.columbia.edu/SOURCES/.IRI/.MD/.SERVIR/wmsmap?",
                {layers: 'CSMT.Annual_Sum', transparent: 'false', wrapDateLine: 'true', srs: 'EPSG:4326' }, {isBaseLayer: false, visibility:false});
                        
                        var prcp = new OpenLayers.Layer.WMS("FEWS estimated precipitation","http://iridl.ldeo.columbia.edu/expert/SOURCES/.NOAA/.NCEP/.CPC/.FEWS/.Africa/.TEN-DAY/.RFEv2/.est_prcp/MEWSprcp_colors/X/Y/fig-+colors+grey+verythin+mews_dist+black+verythin+mews_prov+black+thin+countries_gaz+black+thinnish+coasts_gaz+-fig+//antialias+true+psdef/wmsfigmap",
                {layers: 'est_prcp', transparent: 'false', wrapDateLine: 'true', srs: 'EPSG:4326' }, {isBaseLayer: false, visibility:false});
                        
                                
            // Add some layers with a dummy base layer.
            this.map.addLayers([
                countries,
                                gaul,
                                gpd,
                                pig,
                                pop,
                                apcp,
                                prcpa,
                                csmt,
                                prcp,
                this.wfsStoreLayer
            ]);
            
            this.map.addControl(new OpenLayers.Control.Navigation());
            this.map.addControl(new OpenLayers.Control.PanZoomBar());
            
            this.mapPanel = new GeoExt.MapPanel({
                region: "center",
                map: this.map,
                zoom: 4,
                center: new OpenLayers.LonLat(-99.54204174999998,38.13064787500001)
            });
        },
        
        initFeatureGrid: function() {

            this.grid = new Ext.grid.GridPanel({
                title: "Feature Query Results",
                stripeRows: true,
                height:230,
                region: "south",
                collapsible: true,
                collapseMode: "mini",
                loadMask: {
                    msg: "Loading features...",
                    store: this.featureStore
                },
                columns: [],
                store: this.featureStore,
                selModel: new GeoExt.grid.FeatureSelectionModel({
                        layer: this.wfsStoreLayer
                }),
                bbar: this.pagingBar
            });
            
            this.grid.on("rowdblclick", function(grid, index, evt) {
                var record = grid.getSelectionModel().getSelected();
                
                if (record) {
                    var bounds = record.data.feature.geometry.getBounds();
                    this.map.zoomToExtent(bounds);
                }
            }, this);
            
    
            ///////////// POPUP STUFF
             
            this.grid.getSelectionModel().on("rowselect", function (model, row, record){
                var feature = record.data.feature;
    
                var content = "<p> You selected " + feature.fid + "! I am truly impressed! </p>";    

                feature.popup = new GeoExt.popup.Popup({
                    title: feature.fid,
                    feature: feature,
                    width: 235,
                    height: 70,
                    html: content,
                    collapsible: true,
                    collapsed: true,
                    expandOnShow: false
                });

                var popup = feature.popup;
                this.grid.store.on("load", function(store, records, options){
                    var record;
                    for(var i = 0; i < records.length; i++){
                        if(records[i].data.feature == feature){
                            return;
                        }
                    }
                    if(popup.anc){
                        popup.close();
                    }
                });
    
                feature.popup.addToMapPanel(this.mapPanel);
            }, this);
    
            this.grid.getSelectionModel().on("rowdeselect", function(model, row, record){
                var feature = record.data.feature;
                if(feature.popup.anc){
                    feature.popup.close();
                }
            });

        },
        
        initLayerTree: function() {
            var addLayerButton = new Ext.Button({
                text: "Add Layer...",
                disabled: true,
                handler: function() {
                    var win = new GeoExt.drake.AddLayerWindow({
                        capsStore: this.wmsStore
                    });
                    
                    win.on("layerschosen", function(layers) {
                        
                        var layer;
                        for (var index = 0; index < layers.length; index++) {
                            var layerRecord = layers[index];
                            var name = layerRecord.data.name;
                            var tilesOrigin = layerRecord.data.llbbox[0] + "," + layerRecord.data.llbbox[1];
                            
                            layer = new OpenLayers.Layer.WMS(name, this.wmsUrl, {
                                layers: name,
                                format: "image/png",
                                transparent: "true",
                                tiled: true,
                                tilesOrigin: tilesOrigin
                            }, {
                                isBaselayer: false,
                                maxExtent: OpenLayers.Bounds.fromArray(layerRecord.data.llbbox)
                            });

                            layer.drakestyles = layerRecord.data.styles; 
                            
                            var found = false;
                            for (var layersIndex = 0; layersIndex < this.map.layers.length; layersIndex++) {
                                if (this.map.layers[layersIndex] instanceof OpenLayers.Layer.WMS) {
                                    if (layer.params.LAYERS == this.map.layers[layersIndex].params.LAYERS) {
                                        found = true;
                                        break;
                                    }
                                }
                            }
                            
                            if (!found) {
                                this.map.addLayer(layer);
                            }
                        } 
                    }, this);
                    
                    win.show();
                },
                scope: this
            });
            
            
            var root = new Ext.tree.TreeNode({});
            
            var baseLayerContainer = new GeoExt.tree.BaseLayerContainer({
                map: this.map
            });
            
            var wfsStore = new Ext.data.Store({
                reader: new GeoExt.data.WFSCapabilitiesReader(),
                url: this.wfsUrl + "?request=GetCapabilities" 
            });
            
            // TODO: We should probably have some UI that shows the layer tree is loading,
            // as the overlayContainer will not be added to the layerTree until the 
            // wfsStore's request returns. This is not Hugely Important Right Now, but 
            // experience tells me that for some user, at some point, this request
            // is gonna hang.
            wfsStore.load({
                callback: function(response) {
                    var overlayContainer = new GeoExt.tree.OverlayLayerContainer({
                        map: this.map
                    });
                    
                    overlayContainer.on("customizeconfig", function(config, layer) {
                        config.uiProvider = GeoExt.drake.LayerNodeUI;
                        config.queryable = wfsStore.find("name", layer.params.LAYERS) >= 0;
                    });
                    
                    root.appendChild(overlayContainer);
                    
                    // Don't allow them to click the Add Layer button until we
                    // have all the data we need. (i.e., we have it all now,
                    // so enable the button).
                    addLayerButton.setDisabled(false);
                }
            })
            
            root.appendChild(baseLayerContainer);
            
            this.layerTree = new GeoExt.tree.LayerTree({
                border: false,
                split: true,
                rootVisible: false,
                title: "Layers",
                region: "center",
                autoScroll: true,
                root: root,
                bbar: [
                    addLayerButton,
                    new Ext.Button({
                        text: "Remove selected",
                        handler: function() {
                            var nodes = layerTree.getSelectionModel().getSelectedNodes();
                            for (var i = 0; i < nodes.length; i++){
                                var layerName = nodes[i].text;
                                for (var j = 0; j < map.layers.length; j++) {
                                    if (map.layers[j] instanceof OpenLayers.Layer.WMS) {
                                        if (layerName == map.layers[j].params.LAYERS) {
                                            map.layers[j].destroy();
                                            break;
                                        }                                 }
                                    }
                                }
                            }
                        })
                ]
            });
    
            this.layerTree.on("contextmenu", function(node, e){
                if (node.layer){
                    var menuConfig = [{
                        id: "zoomtobounds",
                        text: "Zoom to layer bounds",
                        handler: function(evt){
                                this.map.zoomToExtent(node.layer.maxExtent);
                        },
                        scope: this
                    }];

                    if (node.layer.drakestyles && node.layer.drakestyles.length > 1){
                        for (var i = 0; i < node.layer.drakestyles.length; i++){
                            var style = node.layer.drakestyles[i];
                            menuConfig.push({id: style.name,
                                text: "Render by \"" + style.title + '"',
                                handler: function(style){
                                    return function(evt){
                                        node.layer.params.STYLES = style.name;
                                        node.layer.redraw();
                                    };
                                }(style),
                                scope: this
                            });
                        }
                    }

                    var menu = new Ext.menu.Menu(menuConfig);
                    menu.showAt(e.getPoint());
                }
            }, this);  

            this.layerTree.on("layeractivated", this.activateLayer, this);
        },
        
        addLayerHandler: function() {
            
        },
        
        initLegendPanel: function() {
            this.legendPanel = new GeoExt.LegendPanel({
                map: this.map,
                region: "east",
                title: "Legend",
                width: 200,
                bodyStyle: "padding: 5px",
                collapsible: true,
                autoScroll: true
            });
        },
        
        getFullType: function() {
            return this.featurePrefix + ":" + this.featureType;
        },

        getWFSLayerURL: function(type) { 
            return this.wfsUrl + "?request=DescribeFeatureType&typename=" + type;
        }, 

        activateLayer: function(layer) {
            this.filterBuilder.attributes = new GeoExt.data.AttributesStore({
                url: this.getWFSLayerURL(layer.name),
                ignore: {name: "the_geom"}
            });
            this.filterBuilder.setFilter(null);

            var typename = layer.params.LAYERS;
                        // update fields
            var attributeStore = new GeoExt.data.AttributesStore({
                url: this.wfsUrl + "?typename=" + typename + "&request=describefeaturetype"
            });
    
            attributeStore.load({
                // TODO: Rename x to something meaningful.
                callback: function(x){
                    this.fields = [];
    
                    for (var i = 0; i < x.length; i++){
                        this.fields.push(x[i].data);
                    }

                    this.finishActivating(attributeStore.reader.namespace, typename);
                },
                scope: this
            });
        },

        finishActivating: function(namespace, typename) {
            var parts = typename.split(':');
            this.featurePrefix = parts[0];
            this.featureType   = parts[1];

            this.featureStore.proxy = this.createProxy({prefix: parts[0], type: parts[1], namespace: namespace});
            this.featureStore.reader = new GeoExt.data.FeatureReader({}, recordize(this.fields));
 
            this.grid.setTitle(typename + " - " + namespace);
            this.grid.colModel.setConfig(columnize(this.fields));

            this.reloadFeatureStore();
        },

        updateQueryFilter: function(builder){
            this.featureStore.proxy.setOGCFilter(builder.getFilter());
            this.reloadFeatureStore();
        },
        
        reloadFeatureStore: function() {
            this.featureStore.load({
                params: {
                    start: 0, 
                    limit: this.featuresPerPage
                }
            });
        }
    };

    Ext.onReady(function() {
        GeoExt.Drake.load({
            featurePrefix: "topp",
            featureType: "states",
            
            geoserverUrl: "/geoserver",
            wmsUrl: "/geoserver/wms",
            wfsUrl: "/geoserver/wfs",
            
            maxFeatures: 300,
            featuresPerPage: 7
        });
    });

    </script>
</head>
<body>
</body>
</html>