/****************************************************************************
**
** Copyright (C) 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
** Copyright (C) 2019-2023 General Magic B.V., info@generalmagic.com
**
** BSD License Usage
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Klarälvdalens Datakonsult AB nor the names of
**     its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
****************************************************************************/

//! [MapView code]
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
import GeneralMagic 2.0
import FpsCounter 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("MapCoverageMultiPoint")
    property var updater: ServicesManager.contentUpdater(ContentItem.Type.RoadMap)
    Component.onCompleted: {
        //! [Set token safely]
        ServicesManager.settings.token = __my_secret_token;
        //! [Set token safely]

        ServicesManager.logLevel = ServicesManager.Error;
        ServicesManager.settings.allowInternetConnection = true; // enable connection to online services

        updater.autoApplyWhenReady = true;
        updater.update();
    }

    FpsCounter {
        id: fpsCounter
    }

    // this type of marker does NOT group when rendered on a map and zooming out - ALL are rendered

    function createSketchesPoi(lat, lon)//sketches-type markers - cannot be grouped;
    {
        let coords = ServicesManager.createCoordinates(lat,lon,0);//lat,lon,alt

        /////////////////////////////////
        //the following optional block is used only to enable autocenter on landmark group
        //and to render a route between the individual landmarks/waypoints/icons;
        {
            //Creates a landmark that is owned by the routingWaypoints, for efficiency.
            //This is required because
            //routingWaypoints.append(lmk);
            //will clone the landmark unless the owner is the routingWaypoints list itself.
            let lmk = ServicesManager.createLandmark(routingWaypoints);
            lmk.coordinates = coords;
            routingWaypoints.append(lmk);
        }
        /////////////////////////////////

        return coords;
    }

    /////////////////////////////////
    //the following block is used only to enable autocenter on landmark group
    //and to render a route between the individual landmarks/waypoints/icons;
    //also, the map coverage check uses this list of landmarks;
    LandmarkList {
        id: routingWaypoints
    }
    /////////////////////////////////

    /////////////////////////////////
    //a RoutingService is defined, used in this example only to
    //compute and render a route plotted using list of waypoints/landmarks
    //in the order in which they were added to the list;
    //this block is not required to autocenter on the landmark group;
    //set internet connection to true in the Component.onCompleted block
    //for route computation and rendering to work;
    RoutingService {
        id: routingService
        type: Route.Type.Fastest
        transportMode: Route.TransportMode.Car
        // The list of waypoints is made available to the routing service.
        waypoints: routingWaypoints
        onFinished: {
            map.routeCollection.set(routeList);
            map.centerOnRouteList(routeList);
        }
    }
    /////////////////////////////////

    MapView {
        id: map
        anchors.fill: parent
        viewAngle: 25
        zoomLevel: 69
        viewPerspective: MapView.ViewPerspective.View3D
        buildingsVisibility: MapView.BuildingsVisibility.Show3D
        detailsQualityLevel: MapView.DetailsQualityLevel.Medium

        //////////////////////////////////////////////////////////////////////////////////
        //display x,y pixel position and lon,lat coordinate of clicked position on map
        //////////////////////////////////////////////////////////////////////////////////
        TapHandler {
            grabPermissions: PointerHandler.CanTakeOverFromAnything
            onTapped: {
                let coordinates = map.wgsForScreen(point.pressPosition);
                console.log("x,y (" + point.pressPosition.x + ", " + point.pressPosition.y + ")"
                            + " lon, lat " + coordinates.longitude + ", " + coordinates.latitude);
                lonlatPositionDisplay.text = "x,y (" + point.pressPosition.x + ", " + point.pressPosition.y + ")"
                        + " lon, lat " + coordinates.longitude + ", " + coordinates.latitude;
            }
        }
        //////////////////////////////////////////////////////////////////////////////////
        //4-line display: 1) fps 2) lon,lat 3) single point map coverage 4) multi point map coverage
        //////////////////////////////////////////////////////////////////////////////////
        ColumnLayout {
            anchors.right: parent.right
            anchors.top: parent.top
            Text {
                id: fpsDisplay
                text: "fps " + fpsCounter.fps
            }
            Text {
                id: lonlatPositionDisplay
                text: "Click on map to see lon,lat"
            }
            Text {
                id: singleCoordMapCoverage
                text: ""
            }
            Text {
                id: multiCoordsMapCoverage
                text: ""
            }
        }
        Button {
            anchors.left: parent.left
            anchors.bottom: parent.bottom
            enabled: routingWaypoints.length > 1
            text: qsTr("Render route")
            background: Rectangle {
                opacity: parent.hovered ? 1 : 0.5
                color: enabled ? parent.down ? "#aa00aa" :
                                               (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
            }
            palette { buttonText: "#ffffff"; }
            onClicked: {
                //render route when button is clicked only if there are waypoints in the list;
                if (routingWaypoints.length > 1)
                {
                    //compute and render a route plotted using list of waypoints/landmarks
                    //in the order in which they were added
                    routingService.update()
                }
            }
        }
        Button {
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            text: qsTr("Clear route")
            background: Rectangle {
                opacity: parent.hovered ? 1 : 0.5
                color: enabled ? parent.down ? "#aa00aa" :
                                               (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
            }
            palette { buttonText: "#ffffff"; }
            onClicked: {
                //delete route when button is clicked;
                //compute and render a route plotted using list of waypoints/landmarks
                //in the order in which they were added
                routingWaypoints.clear()
                routingService.update()
            }
        }
        ColumnLayout {
            Button {
                //anchors.left: parent.left
                //anchors.top: parent.top
                text: "Check map coverage for coordlist"
                background: Rectangle {
                    opacity: parent.hovered ? 1 : 0.5
                    color: enabled ? parent.down ? "#aa00aa" :
                                                   (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
                }
                palette { buttonText: "#ffffff"; }
                onClicked: {
                    //sketches-type markers - cannot be grouped;
                    //let marker = ServicesManager.createMarker();
                    let markerRenderSettings = ServicesManager.createMarkerRenderSettings();
                    markerRenderSettings.imageSize = 32;
                    //the following line sets a custom icon image;
                    //choose one icon image line and uncomment it;
                    //the icon image is configured in qml.qrc, and located in the project directory;
                    //if an icon image is not set, markers will be shown as blue dots;
                    markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/violetcircle.png");
                    //markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/redcircle.png")
                    //markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/greensquare.png")
                    //markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/bluetriangle.png")
                    //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.RedBall);
                    //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.GreenBall);
                    //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.BlueBall);

                    console.log(markerRenderSettings);

                    //if the list is not cleared, it will grow every time the button is clicked;
                    routingWaypoints.clear();//clear the list before adding points;

                    //set a map style configured in qml.qrc, and located in the project directory;
                    //choose one map style line and uncomment it;
                    //map.stylePath = "qrc:/Basic_1_Night_Blues_with_Elevation-1_5_688.style";
                    map.stylePath = "qrc:/Basic_1_Oldtime_with_Elevation-1_12_657.style";

                    //sketches-type markers - cannot be grouped;
                    //latitude and longitude of each icon to be added to the map

                    //////////////////////////////////////////////////////////////////////////////////
                    //check map coverage for one point - (latitude,longitude) coordinate
                    //////////////////////////////////////////////////////////////////////////////////
                    let onecoord = ServicesManager.createCoordinates(69.05635,20.55399,0);//lat,lon,alt
                    let mapcover = ServicesManager.mapDetails.coverage(onecoord);
                    let coverageResult = "Single coordinate point map coverage result: ";
                    switch ( mapcover )
                    {
                    case MapDetails.Unknown:
                        coverageResult = coverageResult + "MapDetails.Unknown"; break;
                    case MapDetails.Offline:
                        coverageResult = coverageResult + "MapDetails.Offline"; break;
                    case MapDetails.OnlineNoData:
                        coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
                    case MapDetails.OnlineTile:
                        coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
                    default:
                        coverageResult = coverageResult + "default case - undefined"; break;
                    }
                    singleCoordMapCoverage.text = coverageResult;
                    console.log(coverageResult);

                    //////////////////////////////////////////////////////////////////////////////////
                    //define a list containing multiple coordinates
                    //////////////////////////////////////////////////////////////////////////////////
                    let markercoordlist = ServicesManager.createMarker();
                    markercoordlist.append(createSketchesPoi(69.05997,20.54865));//lat,lon - no/se/fi border tripoint
                    markercoordlist.append(createSketchesPoi(69.06218,20.54471));//lat,lon - no
                    markercoordlist.append(createSketchesPoi(69.05635,20.55399));//lat,lon - se
                    markercoordlist.append(createSketchesPoi(69.06043,20.57157));//lat,lon - fi
                    markercoordlist.append(createSketchesPoi(68.9450, 21.5261 ));//lat,lon - fi
                    markercoordlist.append(createSketchesPoi(65.6339, 25.2500 ));//lat,lon - fi
                    markercoordlist.append(createSketchesPoi(65.6256, 21.9006 ));//lat,lo - se
                    markercoordlist.append(createSketchesPoi(63.3258, 9.4853  ));//lat,lon - no
                    markercoordlist.append(createSketchesPoi(68.0924, 33.3895 ));//lat,lon - ru
                    //////////////////////////////////////////////////////////////////////////////////
                    //check map coverage for multiple coordinates
                    //////////////////////////////////////////////////////////////////////////////////
                    let mapcovermulti = ServicesManager.mapDetails.coverageCoordList(markercoordlist)
                    coverageResult = "Multiple coordinate points map coverage result: ";
                    switch ( mapcovermulti )
                    {
                    case MapDetails.Unknown:
                        coverageResult = coverageResult + "MapDetails.Unknown"; break;
                    case MapDetails.Offline:
                        coverageResult = coverageResult + "MapDetails.Offline"; break;
                    case MapDetails.OnlineNoData:
                        coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
                    case MapDetails.OnlineTile:
                        coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
                    default:
                        coverageResult = coverageResult + "default case - undefined"; break;
                    }
                    multiCoordsMapCoverage.text = coverageResult;
                    console.log(coverageResult);

                    //////////////////////////////////////////////////////////////////////////////////
                    // for each coordinate in the list, print in the console output:
                    // index, map coverage status, country code, coordinate(lon,lat), country name
                    //////////////////////////////////////////////////////////////////////////////////
                    let countrycode = "";
                    for (let idx = 0; idx < markercoordlist.length; idx++) {
                      countrycode = ServicesManager.mapDetails.countryCode(markercoordlist.get(idx))
                        let mapcountrycover = ServicesManager.mapDetails.countryCoverage(countrycode)
                        coverageResult = "Country coverage result by coordinate point: ";
                        switch ( mapcountrycover )
                        {
                        case MapDetails.Unknown:
                            coverageResult = coverageResult + "MapDetails.Unknown"; break;
                        case MapDetails.Offline:
                            coverageResult = coverageResult + "MapDetails.Offline"; break;
                        case MapDetails.OnlineNoData:
                            coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
                        case MapDetails.OnlineTile:
                            coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
                        default:
                            coverageResult = coverageResult + "default case - undefined"; break;
                        }
                        console.log("[" + idx + "] " + coverageResult + " " + countrycode + " ("
                                    + markercoordlist.get(idx).longitude + ", " + markercoordlist.get(idx).latitude
                                    + ") " + ServicesManager.mapDetails.countryName(countrycode))
                    }

                    //SKETCHES-type markers - cannot be grouped, all markers are rendered at all zoom levels;
                    //render on the map the coordinate points for which map coverage is checked
                    let sketchlist = map.markerCollection.getExtendedList(MarkerList.Type.Point);
                    //add the settings, such as icon image size, to the markers;
                    sketchlist.append(markercoordlist, markerRenderSettings);

                    console.log("marker sketchlist len:" + sketchlist.length + " icon coords:" + sketchlist.get(0).length);
                    console.log("marker len:"+markercoordlist.length+" renderset:"+markerRenderSettings);

                    //the following block is used only to autocenter on the group of coordinates;
                    {
                        map.centerOnGeographicArea(routingWaypoints.boundingBox)
                    }
                }
            }
            Button {
                //anchors.left: parent.left
                //anchors.top: parent.top
                text: "Clear sketches-type markers"
                background: Rectangle {
                    opacity: parent.hovered ? 1 : 0.5
                    color: enabled ? parent.down ? "#aa00aa" :
                                                   (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
                }
                palette { buttonText: "#ffffff"; }
                onClicked: {
                    //show how to clear sketches-type marker icons from the map;
                    //clear the list of points used for centering on the bounding box
                    //containing all points/landmarks/waypoints/markers/icons;
                    routingWaypoints.clear();
                    //also clear the markerlist used for rendering the points on the map;
                    //the same set of coordinates is in each of these lists, so both must
                    //be cleared;
                    let sketchlist = map.markerCollection.getExtendedList(MarkerList.Type.Point);
                    sketchlist.clear();
                }
            }
        }
    }
}
//! [MapView code]
