/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/


/**
 * @file
 *   @brief QGC Map Background
 *   @author Gus Grubba <mavlink@grubba.com>
 */

import QtQuick          2.4
import QtQuick.Controls 1.3
import QtLocation       5.3
import QtPositioning    5.3

import QGroundControl                       1.0
import QGroundControl.FactSystem            1.0
import QGroundControl.Controls              1.0
import QGroundControl.FlightMap             1.0
import QGroundControl.ScreenTools           1.0
import QGroundControl.MultiVehicleManager   1.0
import QGroundControl.Vehicle               1.0
import QGroundControl.Mavlink               1.0

Map {
    id: _map

    property string mapName:            'defaultMap'
    property bool   isSatelliteMap:     activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1

    readonly property real  maxZoomLevel: 20
    property variant        scaleLengths: [5, 10, 25, 50, 100, 150, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000]

    function formatDistance(meters)
    {
        var dist = Math.round(meters)
        if (dist > 1000 ){
            if (dist > 100000){
                dist = Math.round(dist / 1000)
            }
            else{
                dist = Math.round(dist / 100)
                dist = dist / 10
            }
            dist = dist + " km"
        }
        else{
            dist = dist + " m"
        }
        return dist
    }

    function calculateScale() {
        var coord1, coord2, dist, text, f
        f = 0
        coord1 = _map.toCoordinate(Qt.point(0, scale.y))
        coord2 = _map.toCoordinate(Qt.point(0 + scaleImage.sourceSize.width, scale.y))
        dist = Math.round(coord1.distanceTo(coord2))
        if (dist === 0) {
            // not visible
        } else {
            for (var i = 0; i < scaleLengths.length - 1; i++) {
                if (dist < (scaleLengths[i] + scaleLengths[i+1]) / 2 ) {
                    f = scaleLengths[i] / dist
                    dist = scaleLengths[i]
                    break;
                }
            }
            if (f === 0) {
                f = dist / scaleLengths[i]
                dist = scaleLengths[i]
            }
        }
        text = formatDistance(dist)
        scaleImage.width = (scaleImage.sourceSize.width * f) - 2 * scaleImageLeft.sourceSize.width
        scaleText.text = text
    }

    zoomLevel:                  18
    center:                     QGroundControl.lastKnownHomePosition
    gesture.flickDeceleration:  3000

    plugin: Plugin { name: "QGroundControl" }

    ExclusiveGroup { id: mapTypeGroup }

    property bool _initialMapPositionSet: false

    Connections {
        target: mainWindow
        onGcsPositionChanged: {
            if (!_initialMapPositionSet) {
                _initialMapPositionSet = true
                center = mainWindow.gcsPosition
            }
        }
    }

    function updateActiveMapType() {
        var fullMapName = QGroundControl.flightMapSettings.mapProvider + " " + QGroundControl.flightMapSettings.mapType
        for (var i = 0; i < _map.supportedMapTypes.length; i++) {
            if (fullMapName === _map.supportedMapTypes[i].name) {
                _map.activeMapType = _map.supportedMapTypes[i]
                return
            }
        }
    }

    Component.onCompleted: updateActiveMapType()

    Connections {
        target:             QGroundControl.flightMapSettings
        onMapTypeChanged:   updateActiveMapType()
    }

    MapQuickItem {
        anchorPoint.x:  sourceItem.width  / 2
        anchorPoint.y:  sourceItem.height / 2
        visible:        mainWindow.gcsPosition.isValid
        coordinate:     mainWindow.gcsPosition
        sourceItem:     MissionItemIndexLabel {
            label: "Q"
        }
    }

    //---- Polygon drawing code

    //
    // Usage:
    //
    // Connections {
    //     target: map.polygonDraw
    //
    //    onPolygonCaptureStarted: {
    //      // Polygon creation has started
    //    }
    //
    //    onPolygonCaptureFinished: {
    //      // Polygon capture complete, coordinates signal variable contains the polygon points
    //    }
    // }
    //
    // map.polygonDraqw.startPolgyon() - begin capturing a new polygon
    // map.polygonDraqw.endPolygon() - end capture (right-click will also end capture)

    // Not sure why this is needed, but trying to reference polygonDrawer directly from other code doesn't work
    property alias polygonDraw: polygonDrawer

    QGCLabel {
        id:                     polygonHelp
        anchors.topMargin:      parent.height - ScreenTools.availableHeight
        anchors.top:            parent.top
        anchors.left:           parent.left
        anchors.right:          parent.right
        horizontalAlignment:    Text.AlignHCenter
        text:                   qsTr("Click to add point %1").arg(ScreenTools.isMobile || !polygonDrawer.polygonReady ? "" : qsTr("- Right Click to end polygon"))
        visible:                polygonDrawer.drawingPolygon

        Connections {
            target: polygonDrawer

            onDrawingPolygonChanged: {
                if (polygonDrawer.drawingPolygon) {
                    polygonHelp.text = qsTr("Click to add point")
                }
                polygonHelp.visible = polygonDrawer.drawingPolygon
            }

            onPolygonReadyChanged: {
                if (polygonDrawer.polygonReady && !ScreenTools.isMobile) {
                    polygonHelp.text = qsTr("Click to add point - Right Click to end polygon")
                }
            }

            onAdjustingPolygonChanged: {
                if (polygonDrawer.adjustingPolygon) {
                    polygonHelp.text = qsTr("Adjust polygon by dragging corners")
                }
                polygonHelp.visible = polygonDrawer.adjustingPolygon
            }
        }
    }

    MouseArea {
        id:                 polygonDrawer
        anchors.fill:       parent
        acceptedButtons:    Qt.LeftButton | Qt.RightButton
        visible:            drawingPolygon
        z:                  1000 // Hack to fix MouseArea layering for now

        property alias  drawingPolygon:     polygonDrawer.hoverEnabled
        property bool   adjustingPolygon:   false
        property bool   polygonReady:       polygonDrawerPolygon.path.length > 3 ///< true: enough points have been captured to create a closed polygon

        /// New polygon capture has started
        signal polygonCaptureStarted

        /// Polygon capture is complete
        ///     @param coordinates Map coordinates for the polygon points
        signal polygonCaptureFinished(var coordinates)

        /// Polygon adjustment has begun
        signal polygonAdjustStarted

        /// Polygon Vertex coordinate has been adjusted
        signal polygonAdjustVertex(int vertexIndex, var vertexCoordinate)

        /// Polygon adjustment finished
        signal polygonAdjustFinished

        property var _vertexDragList: []

        /// Begin capturing a new polygon
        ///     polygonCaptureStarted will be signalled
        function startCapturePolygon() {
            polygonDrawer.drawingPolygon = true
            polygonDrawer._clearPolygon()
            polygonDrawer.polygonCaptureStarted()
        }

        /// Finish capturing the polygon
        ///     polygonCaptureFinished will be signalled
        /// @return true: polygon completed, false: not enough points to complete polygon
        function finishCapturePolygon() {
            if (!polygonDrawer.polygonReady) {
                return false
            }

            var polygonPath = polygonDrawerPolygon.path
            polygonPath.pop() // get rid of drag coordinate
            polygonDrawer._clearPolygon()
            polygonDrawer.drawingPolygon = false
            polygonDrawer.polygonCaptureFinished(polygonPath)
            return true
        }

        function startAdjustPolygon(vertexCoordinates) {
            polygonDrawer.adjustingPolygon = true
            for (var i=0; i<vertexCoordinates.length; i++) {
                var mapItem = Qt.createQmlObject(
                            "import QtQuick                     2.5; " +
                            "import QtLocation                  5.3; " +
                            "import QGroundControl.ScreenTools  1.0; " +
                            "Rectangle {" +
                            "   id:     vertexDrag; " +
                            "   width:  _sideLength; " +
                            "   height: _sideLength; " +
                            "   color:  'red'; " +
                            "" +
                            "   property var coordinate; " +
                            "   property int index; " +
                            "" +
                            "   readonly property real _sideLength:     ScreenTools.defaultFontPixelWidth * 2; " +
                            "   readonly property real _halfSideLength: _sideLength / 2; " +
                            "" +
                            "   Drag.active:    dragMouseArea.drag.active; " +
                            "   Drag.hotSpot.x: _halfSideLength; " +
                            "   Drag.hotSpot.y: _halfSideLength; " +
                            "" +
                            "   onXChanged: updateCoordinate(); " +
                            "   onYChanged: updateCoordinate(); " +
                            "" +
                            "   function updateCoordinate() { " +
                            "       vertexDrag.coordinate = _map.toCoordinate(Qt.point(vertexDrag.x + _halfSideLength, vertexDrag.y + _halfSideLength), false); " +
                            "       polygonDrawer.polygonAdjustVertex(vertexDrag.index, vertexDrag.coordinate); " +
                            "   } " +
                            "" +
                            "   function updatePosition() { " +
                            "       var vertexPoint = _map.fromCoordinate(coordinate, false); " +
                            "       vertexDrag.x = vertexPoint.x - _halfSideLength; " +
                            "       vertexDrag.y = vertexPoint.y - _halfSideLength; " +
                            "   } " +
                            "" +
                            "   Connections { " +
                            "       target: _map; " +
                            "       onCenterChanged: updatePosition(); " +
                            "       onZoomLevelChanged: updatePosition(); " +
                            "   } " +
                            "" +
                            "   MouseArea { " +
                            "       id:             dragMouseArea; " +
                            "       anchors.fill:   parent; " +
                            "       drag.target:    parent; " +
                            "       drag.minimumX:  0; " +
                            "       drag.minimumY:  0; " +
                            "       drag.maximumX:  _map.width - parent.width; " +
                            "       drag.maximumY:  _map.height - parent.height; " +
                            "   } " +
                            "} ",
                            _map)
                mapItem.z = QGroundControl.zOrderMapItems + 1
                mapItem.coordinate = vertexCoordinates[i]
                mapItem.index = i
                mapItem.updatePosition()
                polygonDrawer._vertexDragList.push(mapItem)
                polygonDrawer.polygonAdjustStarted()
            }
        }

        function finishAdjustPolygon() {
            polygonDrawer.adjustingPolygon = false
            for (var i=0; i<polygonDrawer._vertexDragList.length; i++) {
                polygonDrawer._vertexDragList[i].destroy()
            }
            polygonDrawer._vertexDragList = []
            polygonDrawer.polygonAdjustFinished()
        }

        function _clearPolygon() {
            // Simpler methods to clear the path simply don't work due to bugs. This craziness does.
            var bogusCoord = _map.toCoordinate(Qt.point(height/2, width/2))
            polygonDrawerPolygon.path = [ bogusCoord, bogusCoord ]
            polygonDrawerNextPoint.path = [ bogusCoord, bogusCoord ]
            polygonDrawerPolygon.path = [ ]
            polygonDrawerNextPoint.path = [ ]
        }

        onClicked: {
            if (mouse.button == Qt.LeftButton) {
                if (polygonDrawerPolygon.path.length > 2) {
                    // Make sure the new line doesn't intersect the existing polygon
                    var lastSegment = polygonDrawerPolygon.path.length - 2
                    var newLineA = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment], false /* clipToViewPort */)
                    var newLineB = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment+1], false /* clipToViewPort */)
                    for (var i=0; i<lastSegment; i++) {
                        var oldLineA = _map.fromCoordinate(polygonDrawerPolygon.path[i], false /* clipToViewPort */)
                        var oldLineB = _map.fromCoordinate(polygonDrawerPolygon.path[i+1], false /* clipToViewPort */)
                        if (QGroundControl.linesIntersect(newLineA, newLineB, oldLineA, oldLineB)) {
                            return;
                        }
                    }
                }

                var clickCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))
                var polygonPath = polygonDrawerPolygon.path
                if (polygonPath.length == 0) {
                    // Add first coordinate
                    polygonPath.push(clickCoordinate)
                } else {
                    // Update finalized coordinate
                    polygonPath[polygonDrawerPolygon.path.length - 1] = clickCoordinate
                }
                // Add next drag coordinate
                polygonPath.push(clickCoordinate)
                polygonDrawerPolygon.path = polygonPath
            } else if (polygonDrawer.polygonReady) {
                finishCapturePolygon()
            }
        }

        onPositionChanged: {
            if (polygonDrawerPolygon.path.length) {
                var dragCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))

                // Update drag line
                polygonDrawerNextPoint.path = [ polygonDrawerPolygon.path[polygonDrawerPolygon.path.length - 2], dragCoordinate ]

                // Update drag coordinate
                var polygonPath = polygonDrawerPolygon.path
                polygonPath[polygonDrawerPolygon.path.length - 1] = dragCoordinate
                polygonDrawerPolygon.path = polygonPath
            }
        }
    }

    /// Polygon being drawn
    MapPolygon {
        id:         polygonDrawerPolygon
        color:      "blue"
        opacity:    0.5
        visible:    polygonDrawer.drawingPolygon
    }

    /// Next line for polygon
    MapPolyline {
        id:         polygonDrawerNextPoint
        line.color: "green"
        line.width: 5
        visible:    polygonDrawer.drawingPolygon
    }

    //---- End Polygon Drawing code
} // Map
