/* (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 the draw tool.
 *
 * To use the draw tool add the controller to the required classes
 * and to the conntrollers array in your app and activate the tool in the
 * {@link LGB.ext4map.view.Toolbar toolbar}.
 *
    Ext.application({
        requires: [
            'LGB.ext4map.controller.Draw',
            ...
        ],
        controllers: [
            'Draw'
            ...
        ],
        ...
    });
 */
Ext.define('LGB.ext4map.controller.Draw', {
    extend: 'Ext.app.Controller',
    requires: [
        'LGB.ext4map.view.DrawMenu',
        'LGB.ext4map.controller.Measure',
        'LGB.ext4map.controller.CoordinatePicker',
        'LGB.ext4map.controller.FeatureInfo'
    ],

    views: ['DrawMenu',
            'DrawInfo'],

    /**
     * The OpenLayers draw point feature control.
     */
    pointDraw: null,

    /**
     * The OpenLayers draw line feature control.
     */
    lineDraw: null,

    /**
     * The OpenLayers draw polygon feature control.
     */
    polygonDraw: null,

    /**
     * The OpenLayers draw box feature control.
     */
    boxDraw: null,

    /**
     * The OpenLayers modify feature control.
     */
    modify: null,

    /**
     * The OpenLayers layer to draw on.
     */
    drawLayer: null,

    /**
     * @private
     * Delete a feature on the map.
     */
    remove: null,

    features: null,

    style: null,

    toolbox: null,

    /**
     * @private
     * Initialize the controller.
     *
     * Create the OpenLayers layers and controls and map the events.
     */
    init: function() {
        var me = this;

        this.toolbox = Ext.create('LGB.ext4map.util.Toolbox');
        this.features = new ol.Collection();
        var source = new ol.source.Vector({
            features: this.features
        });
        this.drawLayer = new ol.layer.Vector({
            source: source,
            style: function(feature) {
                return [feature.customStyle];
            },
            name: 'Drawtool',
            zIndex: 2015
        });
        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
            }),
            image: new ol.style.Circle({
                radius: 6,
                fill: new ol.style.Fill({
                    color: 'rgba(255, 130, 37, 0.2)'
                }),
                stroke: new ol.style.Stroke({
                    color: 'rgba(255, 130, 37, 1)'
                })
            })
        });

        this.control({
            'drawmenu menu menucheckitem[action=point]': {
                click: me.drawPoint
            },
            'drawmenu menu menucheckitem[action=line]': {
                click: me.drawLine
            },
            'drawmenu menu menucheckitem[action=polygon]': {
                click: me.drawPolygon
            },
            'drawmenu menu menucheckitem[action=box]': {
                click: me.drawBox
            },
            'drawmenu menuitem[action=modify]': {
                click: me.modifyFeature
            },
            'drawmenu menuitem[action=delete]': {
                click: me.deleteFeature
            },
            'drawmenu menuitem[action=info]': {
                click: me.info
            },
            'drawmenu menuitem[action=removeall]': {
                click: me.removeAll
            },
            'drawmenu colormenu[itemId=linecolor]': {
                select: me.changeLineColor
            },
            'drawmenu colormenu[itemId=fillcolor]': {
                select: me.changeFillColor
            }
        });
    },

    /**
     * Set the OpenLayers map object and add the OpenLayers controls.
     */
    setMap: function(map) {
        this.map = map.map;
        this.map.addLayer(this.drawLayer);
        this.pointDraw = new ol.interaction.Draw({
            features: this.features,
            type: 'Point'
        });
        this.pointDraw.on('drawend', this.drawEnd, this);
        this.pointDraw.setActive(false);
        this.lineDraw = new ol.interaction.Draw({
            features: this.features,
            type: 'LineString'
        });
        this.lineDraw.on('drawend', this.drawEnd, this);
        this.lineDraw.setActive(false);
        this.polygonDraw = new ol.interaction.Draw({
            features: this.features,
            type: 'Polygon'
        });
        this.polygonDraw.on('drawend', this.drawEnd, this);
        this.polygonDraw.setActive(false);
        this.boxDraw = new ol.interaction.Draw({
            features: this.features,
            type: 'LineString',
            maxPoints: 2,
            geometryFunction: function(coordinates, geometry) {
                if (!geometry) {
                    geometry = new ol.geom.Polygon(null);
                }
                var start = coordinates[0];
                var end = coordinates[1];
                geometry.setCoordinates([
                    [start, [start[0], end[1]], end, [end[0], start[1]], start]
                ]);
                return geometry;
            }
        });
        this.boxDraw.on('drawend', this.drawEnd, this);
        this.boxDraw.setActive(false);
        this.modify = new ol.interaction.Modify({
            features: this.features
        });
        this.modify.setActive(false);
        this.remove = new ol.interaction.Select({
            layers: [this.drawLayer]
        });
        this.remove.setActive(false);
        this.remove.getFeatures().on('add', function(evt) {
            this.drawLayer.getSource().removeFeature(evt.element);
            this.remove.getFeatures().clear();
        }, this);

        this.map.addInteraction(this.pointDraw);
        this.map.addInteraction(this.lineDraw);
        this.map.addInteraction(this.polygonDraw);
        this.map.addInteraction(this.boxDraw);
        this.map.addInteraction(this.modify);
        this.map.addInteraction(this.remove);
    },

    /**
     * Deactivate all draw controls.
     */
    deactivate: function() {
        this.pointDraw.setActive(false);
        this.lineDraw.setActive(false);
        this.polygonDraw.setActive(false);
        this.boxDraw.setActive(false);
        this.modify.setActive(false);
        this.remove.setActive(false);
    },

    /**
     * Deactivate all other tools and controls.
     */
    deactivateOthers: function() {
        var measure = this.getController('Measure');
        if (measure) {
            measure.deactivate();
        }
        var coordPicker = this.getController('CoordinatePicker');
        if (coordPicker) {
            coordPicker.deactivate();
        }
        var toolbar = this.getController('Toolbar');
        if (toolbar) {
            toolbar.deactivateControls();
        }
        var featureInfo = this.getController('FeatureInfo');
        if (featureInfo) {
            featureInfo.deactivate();
        }
        var geomaerker = this.getController('Geomaerker');
        if (geomaerker && this.application.appParams.app.tools.geomaerker) {
            geomaerker.deactivate();
        }
    },

    /**
     * Activate draw feature control.
     */
    activate: function() {
        this.deactivate();
        this.deactivateOthers();
        if (Ext.getCmp('draw.point').checked) {
            this.pointDraw.setActive(true);
        }
        if (Ext.getCmp('draw.line').checked) {
            this.lineDraw.setActive(true);
        }
        if (Ext.getCmp('draw.polygon').checked) {
            this.polygonDraw.setActive(true);
        }
        if (Ext.getCmp('draw.box').checked) {
            this.boxDraw.setActive();
        }
    },

    /**
     * Activate the draw feature control.
     */
    drawPoint: function(button) {
        this.deactivate();
        this.deactivateOthers();
        if (button.checked) {
            this.pointDraw.setActive(true);
        }
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Activate the draw feature control.
     */
    drawLine: function(button) {
        this.deactivate();
        this.deactivateOthers();
        if (button.checked) {
            this.lineDraw.setActive(true);
        }
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Activate the draw feature control.
     */
    drawPolygon: function(button) {
        this.deactivate();
        this.deactivateOthers();
        if (button.checked) {
            this.polygonDraw.setActive(true);
        }
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Activate the draw feature control.
     */
    drawBox: function(button) {
        this.deactivate();
        this.deactivateOthers();
        if (button.checked) {
            this.boxDraw.setActive(true);
        }
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Activate the tool to modify previously drawn features.
     */
    modifyFeature: function() {
        this.deactivate();
        this.deactivateOthers();
        this.modify.setActive(true);
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Activate the tool to delete previously drawn features.
     */
    deleteFeature: function() {
        this.deactivate();
        this.deactivateOthers();
        this.remove.setActive(true);
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    removeFeature: function(evt) {
        var features =
            this.drawLayer.getSource().getFeaturesAtCoordinate(
                evt.coordinate);
        console.log(features);
        if (features.length > 0) {
            this.drawLayer.getSource().removeFeature(features[0]);
        }
    },

    /**
     * Remove all features drawn on the map.
     */
    removeAll: function() {
        this.drawLayer.getSource().clear();
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Change the line color used to draw a feature.
     */
    changeLineColor: function(item, color) {
        var opacity = this.toolbox.rgbaToOpacity(this.style.getStroke().getColor());
        var newColor = this.toolbox.hexToRgba(color, opacity);
        this.style.getStroke().setColor(newColor);
        this.style.getImage().getStroke().setColor(newColor);
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Change the fill color used to draw a feature.
     */
    changeFillColor: function(item, color) {
        console.log(this.style.getFill().getColor());
        var opacity = this.toolbox.rgbaToOpacity(this.style.getFill().getColor());
        var newColor = this.toolbox.hexToRgba(color, opacity);
        this.style.getFill().setColor(newColor);
        this.style.getImage().getFill().setColor(newColor);
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    /**
     * Show the window containing information about the features.
     */
    info: function() {
        var info = Ext.create('LGB.ext4map.view.DrawInfo', {
            map: this.map,
            layer: this.drawLayer
        });
        info.show();
        var draw = Ext.getCmp('draw.menu');
        var measure = Ext.getCmp('measure.menu');
        if (measure) {
            measure.toggle();
        }
        draw.toggle();
    },

    drawEnd: function(evt) {
        var style = new ol.style.Style({
            fill: new ol.style.Fill({
                color: this.style.getFill().getColor()
            }),
            stroke: new ol.style.Stroke({
                color: this.style.getStroke().getColor()
            }),
            image: new ol.style.Circle({
                radius: 6,
                fill: new ol.style.Fill({
                    color: this.style.getImage().getFill().getColor()
                }),
                stroke: new ol.style.Stroke({
                    color: this.style.getImage().getStroke().getColor()
                })
            })
        });
        console.log(evt);
        evt.feature.customStyle = style;
    }
});