/*
    blueROCK - for digital rock
    Copyright (C) 2019  Dorian Zedler

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

import QtQuick 2.10
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.1
import QtGraphicalEffects 1.0

Item {
    id: control

    property var flowchartData
    property var allFlowchartData
    property int rounds: 0

    property int refreshes: 0
    property int roundRefreshes: 1

    property int roundCount: 0

    onFlowchartDataChanged: {
        prepareData()
    }

    function prepareData() {

        if(!control.enabled || control.flowchartData === undefined || control.flowchartData['route_names'] === undefined)
            return
        /*refreshes += 1

        if(refreshes > 2){
            roundRefreshes += 1
        }

        console.log("refreshes: " + refreshes + " rounds: " + roundRefreshes)

        // create competition like data (just testing)
        for(var part in flowchartData['participants']){
            if(flowchartData['participants'].hasOwnProperty(part)){

                for(var r = 2 + roundRefreshes; r < 7; r++){
                    delete flowchartData['participants'][part]["result"+r]
                    delete flowchartData['participants'][part]["result_rank"+r]
                }

                if(parseInt(flowchartData['participants'][part]["result_rank0"]) > 14 + refreshes) {
                    delete flowchartData['participants'][part]["result_rank2"]
                }
            }
        }


        delete flowchartData['route_names'][2]
        delete flowchartData['route_names'][3]
        delete flowchartData['route_names'][4]
        delete flowchartData['route_names'][5]
        delete flowchartData['route_names'][6]
        */

        //flowchartData['route_names'] = flowchartData['route_names'].slice(0,)

        // array to store the restructured data
        var allData = []
        control.allFlowchartData = []

        control.rounds = Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0

        //console.log(JSON.stringify(flowchartData['route_names']))

        for(var round in flowchartData['route_names']){
            if(flowchartData['route_names'].hasOwnProperty(round) && parseInt(round) >= 0){
                //console.log(round)

                if(parseInt(round) === 0){
                    // this is the first round

                    // find pairs (always wors vs. best (1-16; 1-15; ...)) (they are sorted by the rank of the better athlete (1-2-3-4-5-6-7-8)

                    var qualificationResults = []

                    for(var x = 0; x < flowchartData['participants'].length; x++){
                        qualificationResults.push(flowchartData['participants'][x])
                    }

                    qualificationResults.sort(function(a, b) {
                        return parseInt(a["result_rank0"]) - parseInt(b["result_rank0"]);
                    });

                    var nextRoundPairs = []
                    var totalMatches = (parseInt(Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0) + 2)
                    var nextRoundMatches = Math.pow(2, totalMatches-1)

                    for(var i = 0; i < nextRoundMatches; i++){
                        nextRoundPairs.push([qualificationResults[i], qualificationResults[nextRoundMatches*2-i-1]])
                    }

                    // build second round pairs (sorted by the rank of the better athlete and worst vs. best (1-8; 2-7; ... ))

                    var sortedFirstRoundPairs = []

                    for(i = 0; i < nextRoundMatches; i += 1){
                        sortedFirstRoundPairs.push([nextRoundPairs.shift(), nextRoundPairs.pop()])
                    }

                    // sort these pairs (containing two pairs of athletes) by the rank of the better athlete (1-4;2-3)

                    var finalSortedFirstRoundPairs = []

                    for(i=0; i < nextRoundMatches/4; i++){
                        finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[i])
                        finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[nextRoundMatches/2-i-1])
                    }

                    // convert the list of pairs of pairs of athletes back to a single list of pairs of athletes

                    var finalFirstRoundPairs = []

                    for(i=0; i < finalSortedFirstRoundPairs.length; i++){
                        finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][0])
                        finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][1])
                    }

                    // push the first round to all data
                    finalFirstRoundPairs.push(2)
                    finalFirstRoundPairs.push(flowchartData['route_names'][2])
                    allData.push(finalFirstRoundPairs)

                }
                else if(parseInt(round) > 0 ){
                    // this is not the first round

                    var nextRound = []

                    // only used when  the current round is the 1/2 final
                    var smallFinal = []
                    var Final = []

                    for(var i = 0; i < allData[allData.length-1].length-2; i+=1){

                        var thisPair = allData[allData.length-1][i]
                        var thisWinner
                        var thisLooser
                        var thisWinnerIsFirstOfNewPair = i%2 === 0

                        if(thisPair[0] === undefined || thisPair[1] === undefined){
                            continue
                        }

                        if(thisWinnerIsFirstOfNewPair){
                            nextRound.push([])
                        }

                        //thisPair[0]["result_rank"] = thisPair[0]["result_rank"+round]
                        //thisPair[1]["result_rank"] = thisPair[1]["result_rank"+round]

                        if(parseInt(thisPair[0]["result_rank"+round]) < parseInt(thisPair[1]["result_rank"+round])){
                            thisWinner = thisPair[0]
                            thisLooser = thisPair[1]
                        }
                        else if(parseInt(thisPair[0]["result_rank"+round]) > parseInt(thisPair[1]["result_rank"+round])) {
                            thisWinner = thisPair[1]
                            thisLooser = thisPair[0]
                        }
                        else {
                            // no result yet!!
                            //console.log("got no winner yet, rank 0: " + thisPair[0]["result_rank"+round] + " rank 1: " + thisPair[1]["result_rank"+round])
                            continue
                        }

                        //console.log(thisWinner['firstname']+" has won in round " + round)

                        if(round - control.rounds === 2){
                            // if we are in the 1/2 final

                            Final.push(thisWinner)
                            smallFinal.push(thisLooser)
                        }
                        else {
                            nextRound[nextRound.length-1].push(thisWinner)
                        }
                    }

                    if(smallFinal.length > 0 && Final.length > 0){

                        // Final
                        allData.push([Final, parseInt(round)+2, flowchartData['route_names'][String(parseInt(round)+2)] + " / " + flowchartData['route_names'][String(parseInt(round)+1)] ])
                        // small Final
                        allData.push([smallFinal, parseInt(round)+1])

                        //break
                    }
                    else {
                        nextRound.push(parseInt(round) + 1 )
                        nextRound.push(flowchartData['route_names'][parseInt(round) + 1])
                        allData.push(nextRound)
                    }
                }
            }
        }

        control.allFlowchartData = allData
        control.roundCount = (parseInt(Object.keys(control.flowchartData['route_names']).length > 2 ? control.flowchartData['route_names']["2"].includes("8") ? 2:1 : 0) + 2)
        //console.log(JSON.stringify(allData))
    }

    ListView {
        id: roundListView

        property int columnWidth: height * 0.3
        property int columnHeight: height

        anchors {
            top: parent.top
            bottom: parent.bottom
            horizontalCenter: parent.horizontalCenter
        }

        width: Math.min((columnWidth + spacing) * model, control.width)

        spacing: app.height * 0.05

        orientation: ListView.LeftToRight
        boundsBehavior: ListView.StopAtBounds

        model: control.roundCount

        delegate: Item {
            id: roundItem

            property int thisIndex: index
            property int thisRound: thisRoundIsValid ? control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-2]:-1
            property bool thisRoundIsValid: control.allFlowchartData !== undefined
                                            && control.allFlowchartData[roundItem.thisIndex] !== undefined
                                            && control.allFlowchartData[roundItem.thisIndex].length > 2

            property bool thisIsLastRound: thisIndex === control.roundCount - 1
            property bool thisIsSemiFinal: thisIndex === control.roundCount - 2 && rectRep.model === 2

            property int tileSize: (roundItem.height / 8 - roundNameLa.height) * 1.45

            width: roundListView.columnWidth
            height: roundListView.columnHeight

            Column {
                id: roundCol

                anchors.fill: parent

                Label {
                    id: roundNameLa
                    width: parent.width
                    height: control.height * 0.05
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    fontSizeMode: Text.Fit
                    font.pixelSize: height * 0.6
                    minimumPixelSize: 1
                    font.bold: true
                    text: roundItem.thisRoundIsValid
                          && control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-1] !== undefined ?
                              control.allFlowchartData[roundItem.thisIndex][control.allFlowchartData[roundItem.thisIndex].length-1] :
                              "-"
                }

                Repeater {
                    id: rectRep
                    model: Math.max( Math.pow(2, control.roundCount-1) * Math.pow(0.5, (roundItem.thisIndex)), 2)
                    delegate: Item {
                        id: matchItm

                        property bool lowerPart: (index%2 > 0)

                        property var matchData: roundItem.thisRoundIsValid ?
                                                    control.allFlowchartData[
                                                        thisIsSmallFinal ?
                                                            roundItem.thisIndex+1 :
                                                            roundItem.thisIndex
                                                    ][ thisIsSmallFinal ? 0:matchItm.thisIndex]:
                                                    undefined

                        property int thisIndex: index
                        property int thisRound: parseInt(roundItem.thisRound) - (thisIsSmallFinal ? 1:0)
                        property var thisMatchData: thisMatchDataIsValid ? matchData:[]

                        property bool thisMatchDataIsValid: (matchData !== undefined && matchData !== null && typeof matchData === "object" && matchData.length > 0)
                        property bool thisMatchIsOver: thisMatchDataIsValid && thisMatchData[0]['result_rank'+thisRound] !== undefined && thisMatchData[1]['result_rank'+thisRound] !== undefined

                        property bool thisIsFinal: roundItem.thisIsLastRound && thisIndex === rectRep.model - 2
                        property bool thisIsSmallFinal: roundItem.thisIsLastRound && thisIndex === rectRep.model - 1

                        property int winnerIndex: thisMatchIsOver ? (parseInt(thisMatchData[0]['result_rank'+thisRound]) < parseInt(thisMatchData[1]['result_rank'+thisRound]) ? 0:1) : -1

                        height: !roundItem.thisIsLastRound ?
                                    (roundItem.height - roundNameLa.height) / rectRep.model - roundCol.spacing :
                                    (thisIsFinal ?
                                         (roundItem.height - roundNameLa.height) * 0.5 + roundItem.tileSize * 0.5 :
                                         (roundItem.height - roundNameLa.height) - (roundItem.height - roundNameLa.height) * 0.5 + roundItem.tileSize * 0.5
                                    )

                        width: roundItem.width

                        onMatchDataChanged: {
                            fadeInPa.start()
                        }

                        ParallelAnimation {
                            id: fadeInPa
                            NumberAnimation { target: matchItm; property: "opacity"; from: 0; to: 1.0; duration: 400 }
                            NumberAnimation { target: matchItm; property: "scale"; from: 0.8; to: 1.0; duration: 400 }
                        }

                        Canvas {
                            id: lineCanvas
                            width: app.width; height: app.height
                            contextType: "2d"

                            visible: !roundItem.thisIsLastRound

                            property int targetYFactor: matchItm.lowerPart ? -1:1

                            Path {
                                id: firstPartPath
                                startX: matchItm.width
                                startY: matchItm.height * 0.5

                                PathQuad {
                                    id: firstPartPathQuad
                                    relativeX: roundListView.spacing * 0.5
                                    relativeY: matchItm.height * 0.25 * lineCanvas.targetYFactor
                                    relativeControlX: relativeX
                                    relativeControlY: 0
                                }

                                PathQuad {
                                    relativeX: roundListView.spacing * 0.5
                                    relativeY: matchItm.height * 0.25 * lineCanvas.targetYFactor
                                    relativeControlX: 0
                                    relativeControlY: relativeY
                                }
                            }

                            onPaint: {
                                context.strokeStyle = "lightgrey"
                                context.lineWidth = matchRect.height * 0.05
                                context.path = firstPartPath;
                                context.stroke();
                            }
                        }

                        RectangularGlow {
                            id: effect
                            anchors.fill: matchRect
                            glowRadius: 0
                            spread: 0
                            opacity: 0.3
                            color: "black"
                            cornerRadius: matchRect.radius
                        }

                        Rectangle {
                            id: matchRect

                            anchors {
                                centerIn: !matchItm.thisIsFinal ? parent:undefined
                                bottom: matchItm.thisIsFinal ? parent.bottom:undefined
                            }

                            //anchors.verticalCenterOffset: matchItm.lowerPart ? 10:10
                            width: parent.width
                            height: roundItem.tileSize
                            //scale: 0.9
                            color: Material.dialogColor
                            border.color: "lightgrey"
                            border.width: 0
                            radius: height * 0.2

                            Column {
                                spacing: 0

                                anchors.fill: parent
                                anchors.margins: matchRect.radius * 0.5

                                Repeater {
                                    // for the two athletes
                                    model: 2

                                    delegate: RowLayout {

                                        height: parent.height / 2 - parent.spacing
                                        width: parent.width

                                        spacing: height * 0.1

                                        Label {
                                            Layout.preferredHeight: parent.height
                                            Layout.preferredWidth: parent.width * 0.15

                                            verticalAlignment: Text.AlignVCenter
                                            horizontalAlignment: Text.AlignLeft
                                            font.pixelSize: height * 0.7
                                            fontSizeMode: Text.Fit
                                            minimumPixelSize: 1

                                            text: matchItm.thisMatchData[index] !== undefined ?
                                                      (
                                                          parseInt(matchItm.thisMatchData[index]['result_rank0'])  < 10 ?
                                                              matchItm.thisMatchData[index]['result_rank0'] + " ":
                                                              matchItm.thisMatchData[index]['result_rank0']
                                                          ):
                                                      ""
                                        }

                                        Label {
                                            Layout.preferredHeight: parent.height
                                            Layout.fillWidth: true

                                            height: parent.height

                                            verticalAlignment: Text.AlignVCenter
                                            horizontalAlignment: Text.AlignLeft
                                            font.pixelSize: height * 0.5
                                            font.bold: matchItm.winnerIndex === index
                                            elide: "ElideRight"

                                            color: matchItm.winnerIndex === index ? Material.color(Material.Green):Material.primaryTextColor

                                            text: matchItm.thisMatchData[index] !== undefined ? matchItm.thisMatchData[index]['firstname'] + " " + matchItm.thisMatchData[index]['lastname'] :"-"
                                        }

                                        Label {
                                            Layout.preferredHeight: parent.height

                                            height: parent.height

                                            verticalAlignment: Text.AlignVCenter
                                            font.pixelSize: height * 0.5

                                            text: matchItm.thisMatchData[index] !== undefined && matchItm.thisMatchData[index]['result'+matchItm.thisRound] !== undefined ?
                                                      ( parseFloat(matchItm.thisMatchData[index]['result'+matchItm.thisRound]) ?
                                                           (parseFloat(matchItm.thisMatchData[index]['result'+matchItm.thisRound]).toFixed(2))
                                                         : matchItm.thisMatchData[index]['result'+matchItm.thisRound] )
                                                    : "-"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

            }

            Loader {
                id: blueRockBadgeLoader

                x: (parent.width - width) / 2
                y: (parent.height - roundNameLa.height - height) / 2 + roundNameLa.height

                sourceComponent: roundItem.thisIsSemiFinal ? blueRockBadgeComponent:undefined

                Component {
                    id: blueRockBadgeComponent

                    BlueRockBadge {
                        width: roundItem.width
                        height: width * 0.25
                    }
                }
            }
        }
    }
}

