/* (C) GeoBasis-DE/LGB
 * Copyright by Landesvermessung und Geobasisinformation Brandenburg (LGB)
 *
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * LICENSE for details.
 */

/**
 * The controller for handling the printing tool.
 *
 * To use the printing tool add the controller to the required classes
 * and to the controllers array in your app and activate the tool in the
 * {@link LGB.ext4map.view.Toolbar toolbar}.
 *
    Ext.application({
        requires: [
            'LGB.ext4map.controller.PrintPlus',
            ...
        ],
        controllers: [
            'PrintPlus'
            ...
        ],
        ...
    });
 */
Ext.define('LGB.ext4map.controller.PrintPlus', {
    extend: 'Ext.app.Controller',
    requires: [
        'LGB.ext4map.view.PrintPlus',
        'LGB.ext4map.view.PrintPlusInfo',
        'LGB.ext4map.view.PrintPlusPolicy',
        'LGB.ext4map.util.PrintPlus'
    ],

    /**
     * @private
     * The print view container.
     */
    printPlusView: null,

    /**
     * The OpenLayers map object.
     */
    map: null,

    /**
     * The printing module visual layer for capturng the printing extent.
     */
    printerExtentLayer: null,

    /**
     * The printing scale.
     */
    scale: null,

    /**
     * Value set if the specific extent of Brandenburg is selected.
     */
    brandenburg: null,

    /**
     * The layer blacklist.
     * Layers in this list are excluded from printing.
     */
    blacklist: [],    

    /**
     * @private
     * The url of the printing service.
     */
    url: null,

    /**
     * @private
     * Initialize the controller and map the events to function.
     */
    init: function() {
        var me = this;
        this.feature = new ol.Collection();
        var source = new ol.source.Vector({
            features: this.feature
        });
        this.style = new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 0.2)'
            }),
            stroke: new ol.style.Stroke({
                color: 'rgba(255, 130, 37, 1)',
                width: 2
            })
        });
        this.drawLayer = new ol.layer.Vector({
            source: source,
            style: this.style
        });
        this.control({
            'printpluspolicy button[action=accepted]': {
                click: me.policyAccepted
            },
            'printpluspolicy button[action=close]': {
                click: me.policyClosed
            },
            'printplus combo[action=format]': {
                change: function() {
                    this.layout = Ext.getCmp('idFormatCombo').value;
                    this.drawRectangle();
                }
            },
            'printplus fieldcontainer radio[action=radiodefault]': {
                change: function(evt) {
                    if (evt.checked){
                        this.drawRectangle(evt);
                        this.brandenburg = false;
                    }
                }
            },
            'printplus fieldcontainer radio[action=radiobrandenburg]': {
                change: function(evt) {
                    if (evt.checked){
                        me.scale = 4000000;
                        me.brandenburg = true;
                        this.drawRectangle(evt);
                    }
                }
            },
            'printplus fieldcontainer radio[action=radioscales]': {
                change: function(evt) {
                    if (evt.checked){
                        me.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
                        this.drawRectangle(evt);
                        this.brandenburg = false;
                    }
                }
            },
            'printplus combo[action=combo1]': {
                change: function(evt) {
                    me.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
                    this.drawRectangle(evt);
                }
            },
            'printplus button[action=print]': {
                click: me.print
            },
            'printplus': {
                close: me.printClosed
            }
        });
    },

    policyAccepted: function() {
        this.printPlusInfoView = Ext.create('LGB.ext4map.view.PrintPlusInfo');
        this.printPlusInfoView.show();
    },

    policyClosed: function() {
        this.printPlusPolicy.close();
        this.printClosed();
    },

    /**
    * Function for numerical formatting
    * 
    * Author: Robert Hashemian
    * http://www.hashemian.com/
    *
    * You can use this code in any manner so long as the author's
    * name, Web address and this disclaimer is kept intact.
    ********************************************************
    *
    **/
    FormatNumberBy3: function(num, decpoint, sep) {
      if (arguments.length == 2) {
        sep = ",";
      }
      if (arguments.length == 1) {
        sep = ",";
        decpoint = ".";
      }
      num = num.toString();
      a = num.split(decpoint);
      x = a[0]; // decimal
      y = a[1]; // fraction
      z = "";
      if (typeof(x) != "undefined") {
        for (i=x.length-1;i>=0;i--)
          z += x.charAt(i);
        z = z.replace(/(\d{3})/g, "$1" + sep);
        if (z.slice(-sep.length) == sep)
          z = z.slice(0, -sep.length);
        x = "";
        for (i=z.length-1;i>=0;i--)
          x += z.charAt(i);
        if (typeof(y) != "undefined" && y.length > 0)
          x += decpoint + y;
      }
      return x;
    },

    /**
     * Function to prepare printing scales in the right format
     */
    getScales: function(scales) {
        if (scales){
            var r = scales.split(",");
            var scales = [];
            for (i in r){
                var m = Number(r[i]);
                var n = {'scale': '1 : '+this.FormatNumberBy3(m,",",".")};
                scales.push(n);
            }
            return scales
        }
    },

    /**
     * Function to prepare printing formats in the right format
     */
    getFormats: function(formats) {
        if (formats){
            var r = formats.split(",");
            var formats = [];
            for (i in r){
                var n = {'format':r[i],'name':r[i]};
                formats.push(n);
            }
            return formats
        }
    },

    /**
     * Function handling toggle of the printing tool in the toolbar
     */
    toggle: function(toggle, pos) {
        var me = this;
        if (!this.printPlusView){
            this.printPlusView = Ext.create('LGB.ext4map.view.PrintPlus', {
                policy: this.application.appParams.app.tools.printPlus.policy,
                formats: this.getFormats(this.application.appParams.app.tools.printPlus.formats),
                scales: this.getScales(this.application.appParams.app.tools.printPlus.scales)
            });
        }
        if (toggle) {
            var toolbar = this.getController('Toolbar');
            this.drawRectangle();
            this.map.on("moveend", this.drawRectangle, this.map);
            this.printPlusView.show();
            
            if (this.application.appParams.app.tools.printPlus.policy){
                this.printPlusPolicy = Ext.create('LGB.ext4map.view.PrintPlusPolicy');
                this.printPlusPolicy.show();
            }
            else{
                this.printPlusInfoView = Ext.create('LGB.ext4map.view.PrintPlusInfo');
                this.printPlusInfoView.show();
            }            
        }
        else {
            this.deactivate();
            this.printPlusView.hide();
        }
    },

    /**
     * Set the OpenLayers map object and add the OpenLayers controls.
     */
    setMap: function(map) {
        var me = this;
        this.map = map.map;
    },

    /**
     * Set the print layer blacklist.
     */
    setBlacklist: function(list) {
        this.blacklist = list;
    },

    /**
     * Function to handle the printing map extent selection and view
     */
    drawRectangle: function (evt) {
        var map;
        if (this.map){map = this.map} else {map = this;}

        var toolbox = Ext.create('LGB.ext4map.util.Toolbox');

        if (!evt || !evt.id){
            if (Ext.getCmp('radio1').checked) {
                this.scale = toolbox.getScaleFromResolution(map.getView().getResolution(),map.getView().getProjection().getUnits());
                this.brandenburg = false;
            }
            else if (Ext.getCmp('radio2').checked){
                this.scale = 4000000;
                this.brandenburg = true;
            }
            else if (Ext.getCmp('radio3').checked){
                    this.scale = Ext.getCmp('idScalesCombo').value;
                    this.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
                    this.brandenburg = false;
            }
        }
        else {

            if (evt.checked && evt.id == 'radio1') {
                this.scale = toolbox.getScaleFromResolution(map.getView().getResolution(),map.getView().getProjection().getUnits());
                this.brandenburg = false;
            }
            else if (evt.checked && evt.id == 'radio2'){
                this.scale = 4000000;
                this.brandenburg = true;
            }
            else if (evt.checked && evt.id == 'radio3'){
                this.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
                this.brandenburg = false;
            }
            else if (evt.id == 'idScalesCombo'){
                this.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
                this.brandenburg = false;
            }
        }

        map.getLayers().forEach(function(lyr){
            // if (lyr.values_.name == 'Print_Extent'){
            if (lyr.getProperties().name == 'Print_Extent'){
                map.removeLayer(lyr);
            }
        });

        var geojson_obj = {
            'type': 'FeatureCollection',
            'features': [
            {
            'type': 'Feature',
            'properties': {},
            'geometry': {
            'type': 'Polygon',
            'crs': 'urn:ogc:def:crs:EPSG::25833',
            'coordinates': []
            }
        }]};

        proj4.defs('EPSG:4326', "+proj=longlat +datum=WGS84 +no_defs");
        proj4.defs('EPSG:25833', "+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");
        proj4.defs('EPSG:25832', "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");

        var center = map.getView().getCenter();
        var zoom = map.getView().getZoom()    
        var extent = map.getView().calculateExtent(map.getSize());
        
        var proj = map.getView().getProjection();
        switch (proj.getCode()){
            case ('EPSG:4326'):
                if (this.brandenburg == true) {
                    switch(Ext.getCmp('idFormatCombo').value) {
                        case ('A4 Hochformat'):
                            inner_coords_sw = [11.233683921388279, 50.630056231943044];
                            inner_coords_no = [14.795788975371723, 54.310898121058955];
                        break;
                        case ('A4 Querformat'):
                            inner_coords_sw = [10.817458685261881, 51.324028056671935];
                            inner_coords_no = [15.732973172858118, 53.60225139601006];
                        break;    
                        case ('A3 Hochformat'):
                            inner_coords_sw = [11.227937340317393, 50.22570655662017];
                            inner_coords_no = [14.809091084428609, 54.54499704320183];
                        break;    
                        case ('A3 Querformat'):
                            inner_coords_sw = [11.077578866181309, 51.330439263451275];
                            inner_coords_no = [15.45084064145869, 53.58850273907073];
                        break;
                    }
                    inner_coords_so = [inner_coords_no[0], inner_coords_sw[1]];
                    inner_coords_nw = [inner_coords_sw[0], inner_coords_no[1]];
                } 
                else {
                    switch (Ext.getCmp('idFormatCombo').value){
                        case ('A4 Hochformat'):
                            var xfactor = 0.0000016731099495981408574893491659844;
                            var yfactor = 0.0000016191386609015662110781863795388;
                        break;
                        case ('A4 Querformat'):
                            var xfactor = 0.0000011683196611990354959111525782898;
                            var yfactor = 0.0000025207766603057622776635934248029;
                        break;    
                        case ('A3 Hochformat'):
                            var xfactor = 0.0000028795269910544473499099830919402;
                            var yfactor = 0.0000023874358294074771992520601010564;
                        break;    
                        case ('A3 Querformat'):
                            var xfactor = 0.0000018064507804955605721522219324973;
                            var yfactor = 0.0000034986094202219042460219814936978;
                        break;
                    }
                    inner_coords_sw = [center.lon-((yfactor*this.scale)/2), center.lat-((xfactor*this.scale)/2)];
                    inner_coords_so = [center.lon+((yfactor*this.scale)/2), center.lat-((xfactor*this.scale)/2)];
                    inner_coords_no = [center.lon+((yfactor*this.scale)/2), center.lat+((xfactor*this.scale)/2)];
                    inner_coords_nw = [center.lon-((yfactor*this.scale)/2), center.lat+((xfactor*this.scale)/2)];
                }
                                
                inner_rectangle_coords = [inner_coords_sw, inner_coords_so, inner_coords_no, inner_coords_nw, inner_coords_sw];                
                extent_coords_sw = [map.getLonLatFromPixel(new OpenLayers.Pixel(0,h)).lon, map.getLonLatFromPixel(new OpenLayers.Pixel(0,h)).lat];
                extent_coords_so = [map.getLonLatFromPixel(new OpenLayers.Pixel(w,h)).lon, map.getLonLatFromPixel(new OpenLayers.Pixel(w,h)).lat];
                extent_coords_no = [map.getLonLatFromPixel(new OpenLayers.Pixel(w,0)).lon, map.getLonLatFromPixel(new OpenLayers.Pixel(w,0)).lat];
                extent_coords_nw = [map.getLonLatFromPixel(new OpenLayers.Pixel(0,0)).lon, map.getLonLatFromPixel(new OpenLayers.Pixel(0,0)).lat];                
                outer_rectangle_coords = [extent_coords_sw, extent_coords_so, extent_coords_no, extent_coords_nw, extent_coords_sw];
            break;
            case ('EPSG:25833'): case ('EPSG:25832'):
                if (this.brandenburg == true) {
                    switch(proj.getCode()) {
                        case ('EPSG:25833'):
                            switch(Ext.getCmp('idFormatCombo').value) {
                                case ('A4 Hochformat'):
                                    inner_coords_sw = [247432.15066717, 5936942.4963858];
                                    inner_coords_no = [486832.15066717, 5689562.4963858];
                                break;
                                case ('A4 Querformat'):
                                    inner_coords_sw = [128268.69830006, 5937402.4963858];
                                    inner_coords_no = [663068.69830006, 5689102.4963858];
                                break;    
                                case ('A3 Hochformat'):
                                    inner_coords_sw = [247474.48570098, 5957660.161352];
                                    inner_coords_no = [485974.48570098, 5669660.161352];
                                break;    
                                case ('A3 Querformat'):
                                    inner_coords_sw = [148373.72380729998, 5937872.4963858];
                                    inner_coords_no = [630733.7238073, 5688632.4963858];
                                break;
                            }
                        inner_coords_so = [inner_coords_no[0], inner_coords_sw[1]];
                        inner_coords_nw = [inner_coords_sw[0], inner_coords_no[1]];
                        break;                         
                        case ('EPSG:25832'):
                            switch(Ext.getCmp('idFormatCombo').value) {
                                case ('A4 Hochformat'):
                                    inner_coords_sw = [648895.59535478, 5954938.8320926];
                                    inner_coords_no = [902695.59535478, 5692678.8320926];
                                break;
                                case ('A4 Querformat'):
                                    inner_coords_sw = [525978.84366399, 5948035.837194];
                                    inner_coords_no = [1066378.84366399, 5697135.837194];
                                break;    
                                case ('A3 Hochformat'):
                                    inner_coords_sw = [648595.59535478, 5973332.1824307];
                                    inner_coords_no = [902995.59535478, 5666132.1824307];
                                break;    
                                case ('A3 Querformat'):
                                    inner_coords_sw = [546938.86917123, 5948210.837194];
                                    inner_coords_no = [1033188.86917123, 5696960.837194];
                                break;
                            }
                        inner_coords_so = [inner_coords_no[0], inner_coords_sw[1]];
                        inner_coords_nw = [inner_coords_sw[0], inner_coords_no[1]];
                        break;                         
                    }
                } 
                else {
                    // Angabe der Laenge/Breite des Kartenbildes im PDF in m 
                    // Angabe der Hoehe des Kartenbildes im PDF in m  
                    switch (Ext.getCmp('idFormatCombo').value){
                        case ('A4 Hochformat'):
                            breite = 0.18 * this.scale;
                            hoehe = 0.186 * this.scale;
                        break;
                        case ('A4 Querformat'):
                            breite = 0.28 * this.scale;
                            hoehe = 0.13 * this.scale;
                        break;    
                        case ('A3 Hochformat'):
                            breite = 0.265 * this.scale;
                            hoehe = 0.32 * this.scale;
                        break;    
                        case ('A3 Querformat'):
                            breite = 0.389 * this.scale;
                            hoehe = 0.201 * this.scale;
                        break;
                    }
                    
                    inner_coords_sw = [center[0]-(breite/2), center[1]-(hoehe/2)];
                    inner_coords_so = [center[0]+(breite/2), center[1]-(hoehe/2)];
                    inner_coords_no = [center[0]+(breite/2), center[1]+(hoehe/2)];
                    inner_coords_nw = [center[0]-(breite/2), center[1]+(hoehe/2)];
                    }

                inner_rectangle_coords = [inner_coords_sw, inner_coords_so, inner_coords_no, inner_coords_nw, inner_coords_sw];
                extent_coords_sw = [extent[0], extent[1]];
                extent_coords_so = [extent[2], extent[1]];
                extent_coords_no = [extent[2], extent[3]];
                extent_coords_nw = [extent[0], extent[3]];
                outer_rectangle_coords = [extent_coords_sw, extent_coords_so, extent_coords_no, extent_coords_nw, extent_coords_sw];
            break;
        }        
        
        var for_geojson_array = [outer_rectangle_coords, inner_rectangle_coords];

        var fill = new ol.style.Fill({
           color: 'rgba(0,0,0,0.3)'
         });
        var style = [
            new ol.style.Style({
                fill: fill
            }),
            new ol.style.Style({
              stroke: new ol.style.Stroke({
                  color: 'black',
                  width: 1
                }),
              geometry: function(feature) {
                var coordinates = feature.getGeometry().getCoordinates()[1];
                return new ol.geom.LineString(coordinates);
              }
            })            
        ];

        geojson_obj.features[0].geometry.coordinates = for_geojson_array;
        
        this.printerExtentLayer = new ol.layer.Vector({
            name: 'Print_Extent',
            source: new ol.source.Vector({features: (new ol.format.GeoJSON()).readFeatures(geojson_obj)}),
            visible: true,
            style: style,
            zIndex: 2020
        });
        

        map.addLayer(this.printerExtentLayer); 
    },

    /**
     * Function for rounding the scale.
     */
    roundingscale: function(scale) {
        switch (Math.round(scale)){
            case (500): case (1500): case (3000):
                return '1 : 1.000';
            break;
            case (5000): case (7000):
                return '1 : 5.000';
            break;
            case (10000):
                return '1 : 10.000';
            break;
            case (25000):
                return '1 : 25.000';
            break;
            case (50000):
                return '1 : 50.000';
            break;
            case (100000):
                return '1 : 100.000';
            break;
            case (288896):
                return '1 : 250.000';
            break;
            case (577792): case (1155583):
                return '1 : 500.000';
            break;
        }
    },

    /**
     * Print the current map configuration.
     */
    print: function() {
        var me = this;
        var map = this.map;

        Ext.getCmp('idPrintButton').setText('<span><img style="width:16px;height:16px" src="resources/img/basic/ajax-loader.gif"></img></span>');

        var toolbox = Ext.create('LGB.ext4map.util.Toolbox');
        if (Ext.getCmp('radio2') && Ext.getCmp('radio2').checked){
            this.scale = 1380000;
            this.brandenburg = true;
        }
        else if (Ext.getCmp('radio3') && Ext.getCmp('radio3').checked){
            this.scale = parseInt(Ext.getCmp('idScalesCombo').value.substring(4, Ext.getCmp('idScalesCombo').value.length)) * 1000;
            this.brandenburg = false;
        }
        else {
            this.scale = toolbox.getScaleFromResolution(map.getView().getResolution(),map.getView().getProjection().getUnits());
        }

        // visible layer for printing
        dienste = "";
        var proj = map.getView().getProjection();
        var layers = this.map.getLayers().getArray();
        var printLayers = [];
        for(i = layers.length-1 ; i >= 0; i--) {
            var layer = layers[i];
            if (this.blacklisted(layer)) {
                continue;
            }
            // continue when layer is activated only
            // if(!layer.getVisible() || !(layer instanceof ol.layer.Image)) {
                // continue;
            // }
            if(!layer.getVisible() || !layer instanceof ol.layer.Image || layer instanceof ol.layer.Vector) {
            // if(!layer.getVisible() || !layer instanceof ol.layer.Image || !layer instanceof ol.layer.Tile) {
                continue;
            }
            else {
                printLayers.push(layer);
            }
        }
        printLayers.sort(function(a,b){
            return a.get('zIndex') - b.get('zIndex')
        })
        for (var i = 0; i < printLayers.length; i++) {
            dienste += printLayers[i].get('name') +", ";
        }
        dienste = dienste.slice(0,-2);
        
        var dpis = [96];
        options = {
            printUrl: this.url,
            method: 'POST',
            layers: printLayers,
            projection: proj.getCode(),
            services: dienste,
            dpi: this.dpi,
            layout: Ext.getCmp('idFormatCombo').value,
            scale: this.scale,
            brandenburg: this.brandenburg,
            map: map
        };
        // this.scale = null;
        this.printer = Ext.create('LGB.ext4map.util.PrintPlus',options);
        this.printer.print();
    },

    /**
     * Closes the Print Window
     */
    printClosed: function() {
        var printview = Ext.getCmp('idprint');
        printview.toggle();
        this.deactivate();
    },

    /**
     * Set the URL to the print service.
     */
    setPrintUrl: function(url) {
        this.url = url;
    },

    /**
     * Check if a layer is on the blacklist.
     */
    blacklisted: function(layer) {
        for (var i = 0; i < this.blacklist.length; i++) {
            // if (this.blacklist[i].id === layer.id) {
            if (this.blacklist[i].getProperties().layerID === layer.getProperties().layerID) {
                return true;
            }
        }
        return false;
    },

    /**
     * Deactivates printer view and printer layer
     */
    deactivate: function() {
        if(this.printPlusView) {
            this.printPlusView.hide();
        }
        this.map.getLayers().forEach(function(lyr){
            // if (lyr.values_.name == 'Print_Extent'){
            if (lyr.getProperties().name == 'Print_Extent'){
                layer = lyr;
            }
        });
        this.map.removeLayer(layer);
        this.map.un("moveend", this.drawRectangle, this.map);
    }
});
;