/*
  Leaflet.CameraViewMarker - specific marker with interactions like rotate and drag

  Copyright (C) 2017 Elphel Inc.

  License: GPLv3

  http://leafletjs.com
  https://www.elphel.com

*/
/**
 * @file leaflet.camera-view-marker.measure.js
 * @brief extends Leaflet.CameraViewMarker with distance measuring tool
 *
 * @copyright Copyright (C) 2017 Elphel Inc.
 * @author Oleg Dzhimiev <oleg@elphel.com>
 *
 * @licstart  The following is the entire license notice for the
 * JavaScript code in this page.
 *
 *   The JavaScript code in this page is free software: you can
 *   redistribute it and/or modify it under the terms of the GNU
 *   General Public License (GNU GPL) as published by the Free Software
 *   Foundation, either version 3 of the License, or (at your option)
 *   any later version.  The code is distributed WITHOUT ANY WARRANTY;
 *   without even the implied warranty of MERCHANTABILITY or FITNESS
 *   FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 *   As additional permission under GNU GPL version 3 section 7, you
 *   may distribute non-source (e.g., minimized or compacted) forms of
 *   that code without the copy of the GNU GPL normally required by
 *   section 4, provided you include this license notice and a URL
 *   through which recipients can access the Corresponding Source.
 *
 *  @licend  The above is the entire license notice
 *  for the JavaScript code in this page.
 */

// Reference plugins:
// * https://github.com/lvoogdt/Leaflet.awesome-markers
// * https://github.com/ppete2/Leaflet.PolylineMeasure

// * https://github.com/ewoken/Leaflet.MovingMarker/blob/master/MovingMarker.js
// * (not used) https://blog.webkid.io/rarely-used-leaflet-features/

(function (window, document, undefined) {
    "use strict";

    L.CameraViewMarker.include({

        createMeasureMarker: function(param,distance){

            var latlng = param;

            // param is event
            if(param.target){
                latlng = param.latlng;
            }

            var p1_ll = this._latlng;

            // param was angle then need distance
            if (!(latlng instanceof L.LatLng)){
                latlng = p1_ll.CoordinatesOf(param,distance);
            }

            var p2_ll = latlng;
            var l_d = Array(p1_ll,p2_ll);

            var pll = L.polyline(l_d, {
                    color: '#1f1',
                    weight:1,
                    dashArray:"5,5"
                }).addTo(this._layerPaint).bringToBack();

            //circle
            var tmp_point = new L.CircleMarker(latlng,{
                color: '#1f1',
                fillColor: '#0f3',
                weight: 2,
                fillOpacity: 0.5,
                radius: 5,
            }).addTo(this._layerPaint);

            var distance = latlng.distanceTo(this._latlng).toFixed(1);

            tmp_point.bindTooltip(distance+' m',{
                permanent:"true",
                direction:"right",
                className: "measurementtooltip",
                offset:[0,0],
            }).openTooltip();

            tmp_point.on('click',this._measureMarkerClick,this);
            tmp_point.on('mousedown',this._dragMeasureMarker,this);
            tmp_point._index = this._measureMarkers.length;

            this._measureMarkers.push(tmp_point);
            this._measureLines.push(pll);

            return tmp_point._index;

        },

        moveMeasureMarker: function(param,index){

            var latlng = param;

            if (param.target){
                index = this.draggedMarker._index;
                latlng = param.latlng;

                // prevent image getting grabbed by browser
                param.originalEvent.preventDefault();
            }

            var p1_ll = this._latlng;
            var p2_ll = latlng;
            var l_d = Array(p1_ll,p2_ll);

            this._measureMarkers[index].setLatLng(latlng);
            this._measureLines[index].setLatLngs(l_d);

            var distance = p2_ll.distanceTo(p1_ll).toFixed(1);
            this._measureMarkers[index]._tooltip.setContent(distance+' m');

            this.draggedMarker = {
                _index: index,
                _latlng: latlng
            };

            this._syncMeasureMarkersToBasePoint();

        },

        removeMeasureMarker: function(param){

            var index = param;

            if(param.target){
                index = param.target._index;
                L.DomEvent.stopPropagation(param);
            }

            this._layerPaint.removeLayer(this._measureMarkers[index]);
            this._layerPaint.removeLayer(this._measureLines[index]);

            this._measureMarkers.splice(index,1);
            this._measureLines.splice(index,1);

            this._updateMeasureMarkersIndices();

        },

        placeSlidingMarker: function(angle,distance){

            var p1_ll = this._measureBase;
            var p2_ll = p1_ll.CoordinatesOf(angle,distance);

            var l_d = Array(p1_ll,p2_ll);

            if (this._slidingMarker == undefined){
                this._slidingMarker = new L.CircleMarker(p2_ll,{
                    color: '#1b1',
                    fillColor: '#0f3',
                    weight: 2,
                    fillOpacity: 0.5,
                    radius: 5,
                }).addTo(this._layerPaint);

                this._slidingLine = L.polyline(l_d, {
                    color: '#1f1',
                    weight:1,
                    dashArray:"5,5"
                }).addTo(this._layerPaint).bringToBack();

                this._slidingMarker.bindTooltip(distance.toFixed(1)+' m',{
                    permanent:"true",
                    direction:"right",
                    className: "measurementtooltip",
                    offset:[0,0],
                }).openTooltip();

            }else{

                this._slidingMarker.setLatLng(p2_ll);
                this._slidingLine.setLatLngs(l_d);
                this._slidingMarker._tooltip.setContent(distance.toFixed(1)+' m');

            }

        },

        removeSlidingMarker: function(){

            if (this._slidingMarker != undefined){

                this._layerPaint.removeLayer(this._slidingMarker);
                this._layerPaint.removeLayer(this._slidingLine);
                delete this._slidingMarker;
                delete this._slidingLine;

            }

        },

        onAdd: function(){

            this._initCameraViewMarker();
            this._initCVM_M();

        },

        _initCVM_M: function(){

            this._measuring = false;

            this._measureMarkers = Array();
            this._measureLines = Array();

            this._map.doubleClickZoom.disable();

            this._registerEvents_M();

            this._measureBase = this._latlng;

            this.draggedMarker = {
                _index: null,
                _latlng: null
            };
            //turn on measure mode
            //this._toggleMeasureMode();
        },

        _registerEvents_M: function(){

            this._map.on('mousemove',this._mouseMove_M,this);
            this._map.on('click', this._toggleMeasureMode, this);
            this._map.on('mousemove',this._syncMeasureMarkersToBasePoint, this);

        },

        _mouseMove_M: function(e){

            if (e.originalEvent.ctrlKey){
                this._map._container.style.cursor = "pointer";
            }else{
                this._map._container.style.cursor = "default";
            }

        },

        _toggleMeasureMode: function(e){

            if (e.originalEvent.ctrlKey){
                this.createMeasureMarker(e);
            }

            /*
            self._measuring = !self._measuring;

            if(self._measuring){
            self._basePoint.off('mousedown',self._dragCamera, self);
            self._map._container.style.cursor = "crosshair";

            self._map.on('click', self._placeMeasurePoint, self);

            }else{
            self._basePoint.on('mousedown',self._dragCamera, self);
            self._map._container.style.cursor = "default";
            self._map.off('click', self._placeMeasurePoint, self);
            }
            */
        },

        _measureMarkerClick:function(e){

            if (e.originalEvent.ctrlKey){
                this.removeMeasureMarker(e);
            }

        },

        _syncMeasureMarkersToBasePoint: function(e){

            if (this._measureMarkers.length!=0){
                if (this._measureBase!=this._latlng){

                    var self = this;

                    this._measureMarkers.forEach(function(c,i){

                        var p1_ll = self._latlng;
                        var p2_ll = c.getLatLng();
                        var l_d = Array(p1_ll,p2_ll);

                        self._measureLines[i].setLatLngs(l_d);

                        var distance = p2_ll.distanceTo(p1_ll).toFixed(1);
                        c._tooltip.setContent(distance+' m');
                    });

                    this._measureBase=this._latlng;
                }
            }

        },

        _dragMeasureMarker: function(e){

            if (!e.originalEvent.ctrlKey){

                this.draggedMarker = {
                    _index: e.target._index,
                    _latlng: e.target._latlng
                };

                this._map.dragging.disable();

                this._map.off('mousemove',this._mouseMove,this);
                this._map.off('click',this._mouseClick,this);

                this._map.on('mousemove',this.moveMeasureMarker,this);

                this._map.on ('mouseup',this._mouseUp_M,this);
            }

        },

        _mouseUp_M: function(){

            this._map.off('mousemove',this.moveMeasureMarker,this);

            this._map.dragging.enable();

            this._map.on ('mousemove',this._mouseMove,this);

            this._map.off ('mouseup',this._mouseUp_M,this);

            this.draggedMarker._index = null;

        },

        _updateMeasureMarkersIndices:function(){

            var self = this;

            this._measureMarkers.forEach(function(c,i){
                self._measureMarkers[i]._index = i;
            });

        },

    });

}(this,document));
