﻿/** 
* Global variable: viskort
* (<VisKort.Application>) Holds the application 
*/
var viskort;

VisKort = {};
// VisKort.GlobalVars = {}

/** 
* Class: VisKort.Application
*
* The application holds the map, all the layers and all the components.
* viskort is the main entry to all javascript in the solution.
*
* Only one instance of this class should be created. All access to underlaying 
* objects should be through this instance.
*
* The constructor of the class initializes the map.
*/
VisKort.Application = OpenLayers.Class({

    /** 
    * Property: map
    * {<VisStedet.Map>} The OpenLayers/VisStedet map.
    */
    map: null,

    /** 
    * Property: infoBox
    * {<OpenLayers.Control.InfoBox>} The reference to the infobox to show popup balloon information
    */
    infoBox: null,

    /** 
    * Property: active_theme
    * {<String>} Name of the active layout theme (ASP.NET)
    */
    active_theme: null,

    /**
    * Property: zoomlevels
    * {<Number>} Number of zoom levels available on the map
    */
    zoomlevels: 12,

    /**
    * Property: components
    * {Object} Hashtable of available components <VisKort.Component>. 
    */
    components: {},

    /**
    * Property: activeComponentName
    * {String} The key of the active component in the components-hashtable. 
    */
    activeComponentName: null,

    /**
    * Property: pagemode
    * {String} Can either be "iframe", "popup" or "print". 
    */
    pagemode: "popup",

    /**
    * Property: clientLayersKml
    * {String} Holds original Kml strings sent from a parent window. 
    */
    clientLayersKml: "popup",

    /**
    * Property: baseQuerystring
    * (String) constant parameters
    */
    baseQuerystring: null,

    /**
    * Property: internalprojection
    * (String) holds the projection code of the map
    */
    internalprojection: "EPSG:25832",

    /**
    * Constructor: VisKort.Application
    * Initializes the map, the map controls, and the layers
    *
    * Parameters:
    * mapDivId - <String> The id of the HTML DIV tag to hold the map
    * activeTheme - <String>
    * mapConfig - <Object> The relevant subset of the MapConfig.xml file content (all layers needed in the current request). JSON formatted.
    * pagemode - <String>
    * baseQuerystring - <String> contains the querystring
    */
    initialize: function(mapDivId, activeTheme, mapConfig, pagemode, baseQuerystring, parentMapDivHeight, parentMapDivWidth, searchResultLayerId, infoBoxSettings) {
        if (pagemode)
            this.pagemode = pagemode;

        // Setup proj4j projections
        Proj4js.defs["EPSG:25832"] = "+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs ";
        Proj4js.defs["EPSG:4326"] = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ";

        // Setup proxy location and active theme
        OpenLayers.ProxyHost = "Proxy.ashx?url=";
        OpenLayers.ImgPath = '/VisKort/App_Themes/' + activeTheme + '/Images/OpenLayers/';
        this.active_theme = activeTheme;

        this.baseQuerystring = baseQuerystring;

        // Setup boundings definition
        var maxExt = new OpenLayers.Bounds(420000, 6025000, 905000, 6450000);

        // Set InfoBox area (covers Denmark)
        var infoBoxRing = new OpenLayers.Geometry.LinearRing();
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(440000, 6040000)); // SW
        // infoBoxRing.addComponent(new OpenLayers.Geometry.Point(440000, 6330000)); // W old borgerdk
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(350000, 6330000)); // W
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(610000, 6430000)); // N
        //infoBoxRing.addComponent(new OpenLayers.Geometry.Point(730000, 6220000)); // NE 1
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(750000, 6220000)); // NE 1
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(750000, 6140000)); // NE 2
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(900000, 6160000)); // E
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(900000, 6100000)); // SE
        infoBoxRing.addComponent(new OpenLayers.Geometry.Point(710000, 6040000)); // S
        var infoBoxArea = new OpenLayers.Geometry.Polygon(infoBoxRing);

        // Initialize controls
        var layerSwitcher = new OpenLayers.Control.StyledLayerSwitcher(mapConfig);
        var scaleLineOptions = { bottomOutUnits: "", bottomInUnits: "" };
        var scaleLine = new OpenLayers.Control.ScaleLineBugFixed(scaleLineOptions);
        var navigation = new OpenLayers.Control.ModifiedNavigator();
        var panZoomBar = new OpenLayers.Control.PanZoomBarBugFix();
        var shortcuts = new OpenLayers.Control.ModifiedKeyboard();
        var overviewMapOptions = { projection: this.internalprojection, units: 'm', maxExtent: maxExt };
        var overviewMap = new OpenLayers.Control.StyledOverviewMap({ minRatio: 32, maxRatio: 64, mapOptions: overviewMapOptions });
        var infoBoxLinkGenerators = null;
        var mousecontrol = new OpenLayers.Control.MousePosition();
        var printButtonOptions = { displayClass: "olControlPrintButton", trigger: "" };
        var printButton = new OpenLayers.Control.StyledPrintButton(printButtonOptions);
        printButton.baseQuerystring = this.baseQuerystring;
        printButton.parent_theme = this.active_theme;

        if (pagemode == "popup")
            infoBoxLinkGenerators = [new VisKort.Utils.LinkGenerator.Route(false),
                                     new VisKort.Utils.LinkGenerator.Rejseplanen("TwoLinks", false)];
        else
            infoBoxLinkGenerators = [new VisKort.Utils.LinkGenerator.Rejseplanen("TwoLinks", false)];
        
        infoBox = new OpenLayers.Control.InfoBox({}, infoBoxArea, infoBoxLinkGenerators, infoBoxSettings);

        // Initialize mapcontrols
        mapcontrols = [layerSwitcher, scaleLine, panZoomBar, navigation, overviewMap, infoBox, printButton, shortcuts];
        // For test
        //mapcontrols = [layerSwitcher, scaleLine, panZoomBar, navigation, mousecontrol, infoBox, printButton, shortcuts];
        if (this.pagemode == "print") {
            mapcontrols = [scaleLine, infoBox, panZoomBar, navigation, shortcuts];
        }

        var maxresolution = null;

        if (this.pagemode == "print") {
            var printmapDiv = document.getElementById(mapDivId);
            try {
                if (parentMapDivHeight >= printmapDiv.clientHeight || parentMapDivWidth >= printmapDiv.clientWidth) {
                    maxresolution = (maxExt.top - maxExt.bottom) / 164;
                } else {
                    maxresolution = (maxExt.top - maxExt.bottom) / 256;
                }
            } catch (err) {
                maxresolution = (maxExt.top - maxExt.bottom) / 164;
            }
        } else {
            maxresolution = (maxExt.top - maxExt.bottom) / 256;
        }

        var options = {
            controls: mapcontrols,
            projection: "EPSG:25832",
            numZoomLevels: this.zoomlevels,
            units: "m",
            maxResolution: maxresolution,
            maxExtent: maxExt
        };
        this.map = new VisStedet.Map(mapDivId, options);

        if (this.pagemode != "print") {
            printButton.activate();
            printButton.active_print();
        }

        // Add KML layers from clientside scripting (except searchLayerKml)
        if (window.parent && window.parent.loadData) {
            var clientLayers = window.parent.loadData();
            var clientLayerLoadEndCallback = function() {
                if (this.formatObject && this.formatObject.kmlDocumentName) {
                    this.name = this.formatObject.kmlDocumentName;
                    this.displayInLayerSwitcher = true;
                }
            }

            if (clientLayers.editKml) {
                var editLayer = new OpenLayers.Layer.KML("editKml", null,
                        			    { isBaseLayer: false,
                        			        formatOptions: { extractStyles: true, extractAttributes: true },
                        			        projection: "EPSG:4326",
                        			        displayInLayerSwitcher: false
                        			    },
                        			    this.internalprojection, clientLayers.editKml);
                this.map.addLayer(editLayer);
            }

            if (clientLayers.viewKml) {
                var currentViewLayer;
                for (var i = 0; i < clientLayers.viewKml.length; i++) {
                    currentViewLayer = new OpenLayers.Layer.KML("viewKml_" + i, null,
                        			    { isBaseLayer: false,
                        			        formatOptions: { extractStyles: true, extractAttributes: true },
                        			        projection: "EPSG:4326",
                        			        displayInLayerSwitcher: false
                        			    }, this.internalprojection, clientLayers.viewKml[i]);
                    this.map.addLayer(currentViewLayer);
                    currentViewLayer.events.register('loadend', currentViewLayer, clientLayerLoadEndCallback);
                }
            }

            this.clientLayersKml = clientLayers;
        }

        // Add layers
        var layers = mapConfig.mapconfig.layerlist.layer;
        if (layers == null)
            alert("Kortlag mangler at blive inkluderet");
        else if (layers[0] == null)
            this.addLayer(layers);
        else {
            for (var i = 0; i < layers.length; i++) {
                if (layers[i]["@id"] == searchResultLayerId) {
                    this.addLayer(layers[i], clientLayers.searchLayerKml);
                }
                else
                    this.addLayer(layers[i]);
            }
        }

        // Zoom to all of denmark
        this.map.zoomToMaxExtent();
       
        infoBox.activate();
        this.infoBox = infoBox;
    },

    /**
    * Method: addLayer
    * Method to add a layer. Invoked by the constructor during the initialization
    *
    * Parameters:
    * layerConfig - <Object> Subset of the MapConfig.xml file content corresponding to the layer. JSON formatted
    */
    addLayer: function(layerConfig, clientKml) {
        var layer, selectControl;
        if (layerConfig["@type"] == "WMS") {
            layer = new OpenLayers.Layer.WMS(layerConfig.name, layerConfig.url, layerConfig.params, layerConfig.options);
            layer.strategies = new OpenLayers.Strategy.BBOX();
        }

        if (layerConfig["@type"] == "WMS.Untiled") {
            layer = new OpenLayers.Layer.WMS.Untiled(layerConfig.name, layerConfig.url, layerConfig.params, layerConfig.options);
        }
        else if (layerConfig["@type"] == "WFS") {
            layer = new OpenLayers.Layer.WFS(layerConfig.name, layerConfig.url, layerConfig.params, layerConfig.options);
        }
        else if (layerConfig["@type"] == "KML") {
            if (clientKml)
                layer = new OpenLayers.Layer.KML(layerConfig.name, null, layerConfig.options, this.internalprojection, clientKml);
            else
                layer = new OpenLayers.Layer.KML(layerConfig.name, layerConfig.url, layerConfig.options, this.internalprojection);
        }
        else if (layerConfig["@type"] == "BBOXKML") {
            layer = new OpenLayers.Layer.Vector(layerConfig.name, layerConfig.options, {
                projection: this.internalProjection,
                strategies: [new OpenLayers.Strategy.BBOX()],
                protocol: new OpenLayers.Protocol.HTTP({
                    url: layerConfig.url,
                    format: new OpenLayers.Format.KML()
                })
            });



            //            layer = new OpenLayers.Layer.Vector(layerConfig.name, layerConfig.options);
            //            layer.protocol = new OpenLayers.Protocol.HTTP({ url: layerConfig.url, format: new OpenLayers.Format.KML(), internalProjection: this.internalProjection });
            //layer.strategies = new OpenLayers.Strategy.BBOX();

            var i = 1;
        }

        layer.addOptions({ mapConfigId: layerConfig["@id"] });

        this.map.addLayer(layer);

        if (layer.isBaseLayer && layerConfig.options && layerConfig.options.visibility) {
            this.map.setBaseLayer(layer);
        }
    },

    /**
    * Method: addComponent
    * Method to add components (<VisKort.Component> sub classes). Must be called after component initialization.
    *
    * Parameters:
    * name - <String> name (key) of the component
    * component - <VisKort.Component>
    */
    addComponent: function(name, component) {
        component.setContext(this, this.map, this.pagemode);
        this.components[name] = component;

        component.startup();
    },

    /**
    * Method: activateComponent
    * Method to activate a component. Must be invoked when a component gets focus.
    * Only one component can be active at a time.
    *
    * Parameters:
    * name - <String> name (key) of the component
    */
    activateComponent: function(name) {
        if (this.activeComponentName != name) {
            if (this.activeComponentName && this.components[this.activeComponentName])
                this.components[this.activeComponentName].deActivate();

            if (this.components[name])
                this.components[name].activate();

            this.activeComponentName = name;
        }
    },

    /**
    * Method: getActiveComponent
    * Method to return the active compoent <VisKort.Component>.
    */
    getActiveComponent: function() {
        if (this.activeComponentName)
            return this.components[this.activeComponentName]
        else
            return null;
    },

    /**
    * Method: getLayerById
    * Method to get the layer <OpenLayers.Layer> by a layer id from the MapConfig.xml file
    *
    * Parameters:
    * id - <String> 
    */
    getLayerById: function(id) {
        var layerList = this.map.layers;
        for (var i = 0; i < layerList.length; i++) {
            if (layerList[i].mapConfigId == id)
                return layerList[i];
        }
        return null;
    },

    /**
    * Method: openPopup
    * Method to open a "popup" map from the current "iframe" map - transfer the current state of the map
    *
    * Parameters:
    * baseQuerystring - <string> part of the original querystring that is readonly (not affected by user interaction)
    */
    openPopup: function() {
        var currentstate = "PanToEasting=" + this.map.getCenter().lon + "&PanToNorthing=" + this.map.getCenter().lat + "&ZoomLevel=" + Math.round(this.map.getZoom());

        var activeLayers = "";
        var includeComma = false;
        for (var q = 0; q < this.map.layers.length; q++) {
            if (this.map.layers[q].visibility && this.map.layers[q].options.mapConfigId != null) {
                if (includeComma)
                    activeLayers += ",";
                else
                    includeComma = true;

                activeLayers += this.map.layers[q].options.mapConfigId;
            }
        }

        var qs = currentstate;
        if (qs.length > 0 && activeLayers.length > 0)
            qs += "&";
        qs += "DefaultOn=" + activeLayers;
        if (qs.length > 0 && this.baseQuerystring.length > 0)
            qs += "&";
        qs += this.baseQuerystring;

        window.open('PopupMap.aspx?' + qs, '', 'location=no,status=no,width=850,height=550,resize=yes', false);
    },

    /**
    * Method: openAboutPage
    * Method to open the "about" page
    */
    openAboutPage: function() {
        window.open('About.aspx?CallingApp=' + this.active_theme, '', 'status=no,width=800,height=800,resize=yes', false);
    },

    CLASS_NAME: "VisKort.Application"
});