import QtQuick 2.0
import QtLocation 5.9
import QtPositioning 5.9

import com.mapbox.cheap_ruler 1.0

Item {
    id: mapWindow

    property int disOffset: 70
    property real rotateAngle: 0
    property var startPoint
    property var endPoint

    // Turn by turn board view
    TbtBoard {
        id: tbt_board
        z: 1
        visible: false
        anchors.fill: parent
    }

    Plugin {
        id: mapbox
        name: "mapbox"
        PluginParameter {
            name: "mapbox.mapping.items.insert_before"
            value: "road-label-small"
        }

        PluginParameter {
            name: "mapbox.mapping.additional_style_urls"
            value: fileOperation.getMapStyleUrls()
        }

        PluginParameter {
            name: "mapbox.access_token"
            value: fileOperation.getMapAccessToken()
        }
        PluginParameter {
            name: "mapbox.mapping.cache.directory"
            value: fileOperation.getCachePath("mapbox")
        }
    }

    Plugin {
        id: osm
        name: "osm"
        PluginParameter {
            name: "osm.mapping.host";
            value: "https://a.tile.openstreetmap.org/"
        }
        PluginParameter {
            name: "osm.mapping.cache.directory"
            value: fileOperation.getCachePath("osm")
        }
    }

    // Map and route views
    Map {
        id: map
        anchors.fill: parent

        plugin: fileOperation.isOSMEnabled() ? osm : mapbox
        center: ruler.currentPosition
        zoomLevel: maximumZoomLevel < 20 ? maximumZoomLevel : 20
        tilt: 60
        gesture.acceptedGestures:MapGestureArea.NoGesture
        copyrightsVisible: false

        RotationAnimation on bearing {
            id: bearingAnimation

            duration: 250
            alwaysRunToEnd: false
            direction: RotationAnimation.Shortest
            running: true
        }

        Location {
            id: previousLocation
            coordinate: QtPositioning.coordinate(0, 0);
        }

        onCenterChanged: {
            if (previousLocation.coordinate === center)
                return;

            bearingAnimation.to = previousLocation.coordinate.azimuthTo(center);
            bearingAnimation.start();

            previousLocation.coordinate = center;
        }

        MapQuickItem {
            id: startMarker

            sourceItem: Image {
                id: greenMarker
                source: "qrc:///marker-green.png"
            }
            anchorPoint.x: greenMarker.width / 2
            anchorPoint.y: greenMarker.height / 2
            z: 11
        }

        MapQuickItem {
            id: endMarker

            sourceItem: Image {
                id: redMarker
                source: "qrc:///marker-end.png"
            }
            anchorPoint.x: redMarker.width / 2
            anchorPoint.y: redMarker.height / 2
            z: 11
        }

        MapItemView {
            model: routeModel

            delegate: MapRoute {
                route: routeData
                line.color: "#4658da"
                line.width: map.zoomLevel - 5
                opacity: (index == 0) ? 1.0 : 0.8
                smooth: true
                z: 5

                onRouteChanged: {
                    ruler.path = routeData.path;
                }
            }
        }

        MapQuickItem {
            zoomLevel: map.zoomLevel

            sourceItem: Image {
                id: carMarker
                source: "qrc:///car-marker.png"
                transform: Rotation {
                                origin.x: carMarker.width / 2;
                                origin.y: carMarker.height / 2;
                                angle: rotateAngle
                }
            }

            coordinate: ruler.currentPosition
            anchorPoint.x: carMarker.width / 2
            anchorPoint.y: carMarker.height / 2
            z: 12

            Location {
                id: previousCarLocation
                coordinate: QtPositioning.coordinate(0, 0);
            }

            onCoordinateChanged: {
                if(coordinate === mapWindow.startPoint)
                    return;
                rotateAngle = previousCarLocation.coordinate.azimuthTo(coordinate);
                previousCarLocation.coordinate = coordinate;
            }
        }

        // Add route view in the map
        function updateRoute() {
            routeQuery.clearWaypoints();
            routeQuery.addWaypoint(startMarker.coordinate);
            routeQuery.addWaypoint(endMarker.coordinate);
            map.addMapItem(startMarker)
            map.addMapItem(endMarker)
        }

        // Clear route view in the map
        function clearRoute() {
            routeQuery.clearWaypoints();
            routeModel.reset();
            map.removeMapItem(startMarker)
            map.removeMapItem(endMarker)
        }

        CheapRuler {
            id: ruler

            onCurrentDistanceChanged: {
                var total = 0;
                var i = 0;
                var alldistance = ruler.distance * 1000;

                if((routeModel.status === RouteModel.Ready) &&
                   (routeModel.count === 1))
                {
                    // XXX: Use car speed in meters to pre-warn the turn instruction
                    while (total < ruler.currentDistance && i < routeModel.get(0).segments.length)
                    {
                        total += routeModel.get(0).segments[i++].maneuver.distanceToNextInstruction;
                    }

                    // Show the tbt board (it will be always shown when demo start)
                    tbt_board.visible = true

                    // Set turn instruction
                    tbt_board.do_setTurnInstructions(routeModel.get(0).segments[i].maneuver.instructionText)
                    tbt_board.state = routeModel.get(0).segments[i].maneuver.direction

                    // When goto the last instruction, set the state to "arriveDest"
                    if(i >= (routeModel.get(0).segments.length-1))
                    {
                        total = alldistance;
                        tbt_board.state = "arriveDest";
                    }

                    var dis = (total - ruler.currentDistance).toFixed(1);

                    // Set distance
                    tbt_board.do_setDistance(dis)

                    // Set board status
                    if(dis < mapWindow.disOffset && i < routeModel.get(0).segments.length)
                    {
                        // Show the full-size tbt board
                        tbt_board.do_showTbtboard(true)
                    }
                    else
                    {
                        // Hide the full-size tbt board
                        tbt_board.do_showTbtboard(false)
                    }
                }
            }
        }
    }

    // The route view display by RouteModel
    RouteModel {
        id: routeModel

        plugin: map.plugin
        autoUpdate: true
        query: routeQuery
    }

    RouteQuery {
        id: routeQuery
    }

    Component.onCompleted: {
        // Request route info when map load finishes
        if (ruler) {
            ruler.initRouteInfo();
            ruler.setCurrentPosition(fileOperation.getStartLatitude(), fileOperation.getStartLongitude());
        }
    }

    //
    // Externally callable functions
    //

    // Handle add route signal
    function do_addRoutePoint(poi_Lat_s, poi_Lon_s, poi_Lat_e, poi_Lon_e) {
        // Set the startPoint and endPoint
        startPoint= QtPositioning.coordinate(poi_Lat_s,poi_Lon_s);
        endPoint = QtPositioning.coordinate(poi_Lat_e,poi_Lon_e);
        startMarker.coordinate = startPoint;
        endMarker.coordinate = endPoint;

        // Update the route view
        if (map) {
            map.updateRoute();
        }
    }

    // Set the current position
    function do_setCoordinate(latitude,longitude,direction,distance) {
        ruler.setCurrentPosition(latitude, longitude);
        ruler.setCurrentDistance(distance);
    }

    // Handle stop navidemo signal
    function do_stopnavidemo() {
        // Hide the tbt board
        tbt_board.visible = false

        // Clear the route view
        if (map) {
            map.clearRoute();
        }
    }

    // Handle arrive at destination signal
    function do_arrivedest() {
        // Hide the tbt board
        tbt_board.visible = false

        // Clear the route view
        if (map) {
            map.clearRoute();
        }
    }
}