import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtCharts 2.3

import Controls 1.0 as Controls
import Cubo 1.0
import Utils 1.0

ColumnLayout {
    spacing: 20

    property int currentTime: 0

    property var voltageData: []
    property var currentData: []
    property var batteryTemperatureData: []
    property var bmsTemperatureData: []
    property var cellVoltageData: []
    property var cellListData: []

    Controls.Frame {
        padding: 20
        leftPadding: 1
        rightPadding: 1

        ColumnLayout {
            anchors.fill: parent

            Controls.TabBar {
                id: bar
                implicitWidth: 300

                Controls.TabButton {
                    text: qsTr("Voltage")
                    width: bar.width / 6 * 0.9
                }

                Controls.TabButton {
                    text: qsTr("Current")
                    width: bar.width / 6 * 0.9
                }

                Controls.TabButton {
                    text: qsTr("Battery temperature")
                    width: bar.width / 6 * 1.2
                }

                Controls.TabButton {
                    text: qsTr("BMS temperature")
                    width: bar.width / 6 * 1.2
                }

                Controls.TabButton {
                    text: qsTr("Cell voltage")
                    width: bar.width / 6 * 0.8
                }

                Controls.TabButton {
                    text: qsTr("Cell list")
                    width: bar.width / 6 * 0.9
                }

                Layout.fillWidth: true
            }

            StackLayout {
                width: parent.width
                currentIndex: bar.currentIndex

                Component {
                    id: legendDelegate

                    RowLayout {
                        width: ListView.view.width
                        height: 60

                        property Controls.ChartView chartItem: undefined
                        property color seriesColor: "black"

                        Controls.CheckBox {
                            id: checkSeries
                            checked: true
                            onCheckedChanged: {
                                if (checked) {
                                    chartItem.series(modelData).color = seriesColor
                                } else {
                                    chartItem.series(modelData).color = "transparent"
                                }
                            }
                            Layout.fillWidth: true
                        }

                        Rectangle {
                            color: seriesColor
                            radius: width / 2
                            Layout.preferredWidth: 18
                            Layout.preferredHeight: 18
                            Layout.rightMargin: 20
                        }

                        Component.onCompleted: {
                            chartItem = ListView.view.chartItem
                            seriesColor = chartItem.series(modelData).color
                            checkSeries.text = chartItem.series(modelData).name
                        }
                    }
                }

                Component {
                    id: chartComponent

                    RowLayout {
                        property string xLabel: ""
                        property string yLabel: ""
                        property Controls.ChartView chart: chartView
                        property int seriesCount: 0

                        ColumnLayout {
                            spacing: -20

                            Controls.ContentLabel {
                                z: 1
                                text: yLabel
                                Layout.topMargin: 20
                                Layout.leftMargin: 30
                                Layout.alignment: Qt.AlignLeft
                            }

                            Controls.ChartView {
                                id: chartView
                                Layout.fillWidth: true
                                Layout.fillHeight: true
                            }

                            Controls.ContentLabel {
                                z: 1
                                text: xLabel
                                Layout.alignment: Qt.AlignRight
                                Layout.rightMargin: 30
                                Layout.bottomMargin: 10
                            }

                            Layout.fillWidth: true
                            Layout.fillHeight: true
                        }

                        ListView {
                            clip: true
                            model: seriesCount
                            delegate: legendDelegate

                            property Controls.ChartView chartItem: chart

                            Layout.preferredWidth: 300
                            Layout.fillHeight: true
                        }
                    }
                }

                Loader {
                    id: voltageLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
                    }
                }

                Loader {
                    id: currentLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Current, A") })
                    }
                }

                Loader {
                    id: batteryTemperatureLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
                    }
                }

                Loader {
                    id: bmsTemperatureLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
                    }
                }

                Loader {
                    id: cellVoltageLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
                    }
                }

                Loader {
                    id: cellListLoader
                    sourceComponent: chartComponent

                    Layout.fillWidth: true
                    Layout.fillHeight: true

                    Component.onCompleted: {
                        item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
                        item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
                    }
                }

                Layout.fillWidth: true
                Layout.fillHeight: true
            }
        }

        Layout.fillWidth: true
        Layout.fillHeight: true
    }

    RowLayout {
        spacing: 20

        Controls.Button {
            text: timer.running ? qsTr("Pause data collection") : qsTr("Resume data collection")
            onClicked: {
                if (timer.running)
                    timer.stop()
                else
                    timer.start()
            }
        }

        Controls.Button {
            text: qsTr("Clear data")
            onClicked: {
                currentTime = 0

                clearData(voltageData, voltageLoader)
                clearData(currentData, currentLoader)
                clearData(batteryTemperatureData, batteryTemperatureLoader)
                clearData(bmsTemperatureData, bmsTemperatureLoader)
                clearData(cellVoltageData, cellVoltageLoader)
                clearData(cellListData, cellListLoader)

                resetZoomButton.clicked()
            }

            function clearData(dataObject, chartObject) {
                for (var i = 0; i < dataObject.length; ++i) {
                    dataObject[i].splice(0, dataObject[i].length)
                    var series = chartObject.item.chart.series(i)
                    series.removePoints(0, series.count)
                }
            }
        }

        Item {
            Layout.fillWidth: true
        }

        Controls.Button {
            id: resetZoomButton
            text: qsTr("Reset zoom")
            onClicked: {
                resetChartZoom(voltageData, voltageLoader)
                resetChartZoom(currentData, currentLoader)
                resetChartZoom(batteryTemperatureData, batteryTemperatureLoader)
                resetChartZoom(bmsTemperatureData, bmsTemperatureLoader)
                resetChartZoom(cellVoltageData, cellVoltageLoader)
                resetChartZoom(cellListData, cellListLoader)
            }

            function resetChartZoom(dataObject, chartObject) {
                chartObject.item.chart.zoomReset()
                chartObject.item.chart.autoScaling = true
                chartObject.item.chart.axes[1].min = closestMinValue(getMinValue(dataObject), 0.05)
                chartObject.item.chart.axes[1].max = closestMaxValue(getMaxValue(dataObject), 0.05)
                chartObject.item.chart.axes[0].min = 0
                chartObject.item.chart.axes[0].max = Math.max(chartObject.item.chart.defaultXMax, chartObject.item.chart.series(0).at(chartObject.item.chart.series(0).count - 1).x)
            }

            function getMaxValue(dataObject, seriesIndex) {
                if (dataObject.length === 0 || dataObject[0].length === 0) {
                    return 0
                }

                var max = dataObject[0][0].y
                for (var i = 0; i < dataObject.length; ++i) {
                    for (var j = 0; j < dataObject[i].length; ++j) {
                        if (dataObject[i][j].y > max) {
                            max = dataObject[i][j].y
                        }
                    }
                }

                return max
            }

            function getMinValue(dataObject) {
                if (dataObject.length === 0 || dataObject[0].length === 0) {
                    return 0
                }

                var min = dataObject[0][0].y
                for (var i = 0; i < dataObject.length; ++i) {
                    for (var j = 0; j < dataObject[i].length; ++j) {
                        if (dataObject[i][j].y < min) {
                            min = dataObject[i][j].y
                        }
                    }
                }

                return min
            }
        }
    }

    Connections {
        target: BmsInterface.commands()

        onValuesReceived: {
            addValueToChart(values.packVoltage, voltageData, voltageLoader, 0, 0.05)
            addValueToChart(values.packCurrent, currentData, currentLoader, 0, 0.05)

            addValueToChart(values.tempBMSHigh, batteryTemperatureData, batteryTemperatureLoader, 0, 0.05)
            addValueToChart(values.tempBMSAverage, batteryTemperatureData, batteryTemperatureLoader, 1, 0.05)
            addValueToChart(values.tempBMSLow, batteryTemperatureData, batteryTemperatureLoader, 2, 0.05)

            addValueToChart(values.tempBattHigh, bmsTemperatureData, bmsTemperatureLoader, 0, 0.05)
            addValueToChart(values.tempBattAverage, bmsTemperatureData, bmsTemperatureLoader, 1, 0.05)
            addValueToChart(values.tempBattLow, bmsTemperatureData, bmsTemperatureLoader, 2, 0.05)

            addValueToChart(values.cVHigh, cellVoltageData, cellVoltageLoader, 0, 0.05)
            addValueToChart(values.cVAverage, cellVoltageData, cellVoltageLoader, 1, 0.05)
            addValueToChart(values.cVLow, cellVoltageData, cellVoltageLoader, 2, 0.05)
        }

        onCellsReceived: {
            for (var i = cellListLoader.item.chart.count; i < cellCount; ++i) {
                cellListLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Cell #") + (i + 1).toString(),
                                                       cellListLoader.item.chart.xAxis, cellListLoader.item.chart.yAxis)
                cellListLoader.item.chart.axes[0].max = 10
                cellListLoader.item.seriesCount = cellListLoader.item.chart.count
            }

            for (var j = 0; j < cellCount; ++j) {
                addValueToChart(cellVoltageArray[j], cellListData, cellListLoader, j, 0.05)
            }

            currentTime += 1
        }
    }

    function addValueToChart(value, dataObject, chartObject, seriesIndex, yScale) {
        if (seriesIndex >= dataObject.length) {
            for (var i = dataObject.length; i <= seriesIndex; ++i) {
                dataObject.push([])
            }
        }

        var seriesData = dataObject[seriesIndex]
        seriesData.push(Qt.point(currentTime, value))
        chartObject.item.chart.series(seriesIndex).append(currentTime, value)

        if (currentTime > chartObject.item.chart.defaultXMax && chartObject.item.chart.autoScaling) {
            chartObject.item.chart.axes[0].max = currentTime
        }

        if (seriesData.length < 2 || (value >= chartObject.item.chart.axes[1].max && chartObject.item.chart.autoScaling)) {
            chartObject.item.chart.axes[1].max = closestMaxValue(value, yScale)
        }

        if (seriesData.length < 2 || (value <= chartObject.item.chart.axes[1].min && chartObject.item.chart.autoScaling)) {
            chartObject.item.chart.axes[1].min = closestMinValue(value, yScale)
        }
    }

    function closestMaxValue(value, scale) {
        return value === 0 ? 1 : Math.ceil(value * (value > 0 ? (1 + scale) : (1 - scale)))
    }

    function closestMinValue(value, scale) {
        return value === 0 ? -1 : Math.floor(value * (value > 0 ? (1 - scale) : (1 + scale)))
    }

    Timer {
        id: timer
        running: true
        interval: 1000
        triggeredOnStart: true

        onTriggered: {
            BmsInterface.commands().getValues()
            BmsInterface.commands().getCells()
            Qt.callLater(start)
        }
    }

    Connections {
        target: BmsInterface
        onPortConnectedChanged: getValues()
    }

    onVisibleChanged: getValues()

    function getValues() {
        if (BmsInterface.isPortConnected() && visible) {
            timer.start()
        } else {
            timer.stop()
        }
    }

    Component.onCompleted: {
        voltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Voltage indicator"),
                                              voltageLoader.item.chart.xAxis, voltageLoader.item.chart.yAxis)
        voltageLoader.item.chart.axes[0].max = 10
        voltageLoader.item.seriesCount = voltageLoader.item.chart.count

        currentLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Current indicator"),
                                              currentLoader.item.chart.xAxis, currentLoader.item.chart.yAxis)
        currentLoader.item.chart.axes[0].max = 10
        currentLoader.item.seriesCount = currentLoader.item.chart.count

        batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
                                                         batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
        batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
                                                         batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
        batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
                                                         batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
        batteryTemperatureLoader.item.chart.axes[0].max = 10
        batteryTemperatureLoader.item.seriesCount = batteryTemperatureLoader.item.chart.count

        bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
                                                     bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
        bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
                                                     bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
        bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
                                                     bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
        bmsTemperatureLoader.item.chart.axes[0].max = 10
        bmsTemperatureLoader.item.seriesCount = bmsTemperatureLoader.item.chart.count

        cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum voltage"),
                                                  cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
        cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average voltage"),
                                                  cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
        cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum voltage"),
                                                  cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
        cellVoltageLoader.item.chart.axes[0].max = 10
        cellVoltageLoader.item.seriesCount = cellVoltageLoader.item.chart.count
    }
}
