// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Window

Item {
    id: display
    property int fontSize: 22
    readonly property int maxDigits: Math.min((width / fontSize) + 1, 9)
    readonly property color backgroundColor: "#262626"
    readonly property color qtGreenColor: "#2CDE85"
    property string displayedOperand: ""
    readonly property string errorString: qsTr("ERROR")
    readonly property bool isError: displayedOperand === errorString
    property bool enteringDigits: false

    function displayOperator(operator) {
        calculationsListView.model.append({ "operator": operator, "operand": "" })
        enteringDigits = true
        calculationsListView.positionViewAtEnd()
    }

    function newLine(operator, operand) {
        displayedOperand = displayNumber(operand)
        calculationsListView.model.append({ "operator": operator, "operand": displayedOperand })
        enteringDigits = false
        calculationsListView.positionViewAtEnd()
    }

    function appendDigit(digit) {
        if (!enteringDigits)
            calculationsListView.model.append({ "operator": "", "operand": "" })
        const i = calculationsListView.model.count - 1
        calculationsListView.model.get(i).operand = calculationsListView.model.get(i).operand + digit
        enteringDigits = true
        calculationsListView.positionViewAtEnd()
    }

    function setDigit(digit) {
        const i = calculationsListView.model.count - 1
        calculationsListView.model.get(i).operand = digit
        calculationsListView.positionViewAtEnd()
    }

    function backspace() {
        const i = calculationsListView.model.count - 1
        if (i >= 0) {
            let operand = calculationsListView.model.get(i).operand.toString().slice(0, -1)
            if (operand === "-")
                operand = ""
            calculationsListView.model.get(i).operand = operand
            return
        }
        return
    }

    function isOperandEmpty() {
        const i = calculationsListView.model.count - 1
        return i >= 0 ? calculationsListView.model.get(i).operand === "" : true
    }

    function isDisplayEmpty() {
        const i = calculationsListView.model.count - 1
        return i == -1 ? true : (i == 0 ? calculationsListView.model.get(0).operand === ""  : false)
    }

    function clear() {
        displayedOperand = ""
        if (enteringDigits) {
            const i = calculationsListView.model.count - 1
            if (i >= 0)
                calculationsListView.model.remove(i)
            enteringDigits = false
        }
    }

    function allClear()
    {
        display.clear()
        calculationsListView.model.clear()
        enteringDigits = false
    }

    // Returns a string representation of a number that fits in
    // display.maxDigits characters, trying to keep as much precision
    // as possible. If the number cannot be displayed, returns an
    // error string.
    function displayNumber(num) {
        if (typeof(num) !== "number")
            return errorString

        // deal with the absolute
        const abs = Math.abs(num)

        if (abs.toString().length <= maxDigits) {
            return isFinite(num) ? num.toString() : errorString
        }

        if (abs < 1) {
            // check if abs < 0.00001, if true, use exponential form
            // if it isn't true, we can round the number without losing
            // too much precision
            if (Math.floor(abs * 100000) === 0) {
                const expVal = num.toExponential(maxDigits - 6).toString()
                if (expVal.length <= maxDigits + 1)
                    return expVal

            } else {
                // the first two digits are zero and .
                return num.toFixed(maxDigits - 2)
            }
        } else {
            // if the integer part of num is greater than maxDigits characters, use exp form
            const intAbs = Math.floor(abs)
            if (intAbs.toString().length <= maxDigits)
                return parseFloat(num.toPrecision(maxDigits - 1)).toString()

            const expVal = num.toExponential(maxDigits - 6).toString()
            if (expVal.length <= maxDigits + 1)
                return expVal
        }
        return errorString
    }

    Item {
        anchors.fill: parent

        Rectangle {
            anchors.fill: parent
            radius: 8
            color: display.backgroundColor

            ListView {
                id: calculationsListView
                x: 5
                y: 10
                width: parent.width
                height: parent.height - 2 * y
                clip: true
                delegate: Item {
                    height: display.fontSize * 1.1
                    width: calculationsListView.width

                    required property string operator
                    required property string operand

                    Text {
                        x: 6
                        font.pixelSize: display.fontSize
                        color: display.qtGreenColor
                        text: parent.operator
                    }
                    Text {
                        font.pixelSize: display.fontSize
                        anchors.right: parent.right
                        anchors.rightMargin: 16
                        text: parent.operand
                        color: "white"
                    }
                }
                model: ListModel { }
                onHeightChanged: positionViewAtEnd()
            }
        }
    }
}
