// Copyright (c) 2014-2024, The Monero Project
// 
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
// 
// 2. 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.
// 
// 3. Neither the name of the copyright holder 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 HOLDER 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.

import QtQml.Models 2.2
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import moneroComponents.Clipboard 1.0
import moneroComponents.PendingTransaction 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.NetworkType 1.0
import FontAwesome 1.0
import "../components"
import "../components" as MoneroComponents
import "." 1.0
import "../js/TxUtils.js" as TxUtils
import "../js/Utils.js" as Utils


Rectangle {
    id: root
    signal paymentClicked(var recipients, string paymentId, int mixinCount, int priority, string description)
    signal sweepUnmixableClicked()

    color: "transparent"
    property alias transferHeight1: pageRoot.height
    property alias transferHeight2: advancedLayout.height
    property int mixin: 15  // (ring size 16)
    property string warningContent: ""
    property string sendButtonWarning: {
        // Currently opened wallet is not view-only
        if (appWindow.viewOnly) {
            return qsTr("Wallet is view-only and sends are only possible by using offline transaction signing. " +
                        "Unless key images are imported, the balance reflects only incoming but not outgoing transactions.") + translationManager.emptyString;
        }

        // There are sufficient unlocked funds available
        if (recipientModel.getAmountTotal() > appWindow.getUnlockedBalance()) {
            return qsTr("Amount is more than unlocked balance.") + translationManager.emptyString;
        }

        if (!recipientModel.hasEmptyAddress()) {
            // Address is valid
            if (recipientModel.hasInvalidAddress()) {
                return qsTr("Address is invalid.") + translationManager.emptyString;
            }

            // Amount is nonzero
            if (recipientModel.hasEmptyAmount()) {
                return qsTr("Enter an amount.") + translationManager.emptyString;
            }
        }

        return "";
    }
    property string startLinkText: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style><a href='#'>(%1)</a>".arg(qsTr("Start daemon")) + translationManager.emptyString
    property bool warningLongPidDescription: descriptionLine.text.match(/^[0-9a-f]{64}$/i)

    Clipboard { id: clipboard }

    function oa_message(text) {
      oaPopup.title = qsTr("OpenAlias error") + translationManager.emptyString
      oaPopup.text = text
      oaPopup.icon = StandardIcon.Information
      oaPopup.onCloseCallback = null
      oaPopup.open()
    }

    function fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name) {
        if (recipientModel.count > 0) {
            const last = recipientModel.count - 1;
            if (recipientModel.get(recipientModel.count - 1).address == "") {
                recipientModel.remove(last);
            }
        }

        recipientModel.newRecipient(address, Utils.removeTrailingZeros(amount || ""));
        setPaymentId(payment_id || "");
        setDescription((recipient_name ? recipient_name + (tx_description ? " (" + tx_description + ")" : "") : (tx_description || "")));
    }

    function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
        console.log("updateFromQrCode")
        fillPaymentDetails(address, payment_id, amount, tx_description, recipient_name);
        cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
    }

    function setDescription(value) {
        descriptionLine.text = value;
        descriptionCheckbox.checked = descriptionLine.text != "";
    }

    function setPaymentId(value) {
        paymentIdLine.text = value;
        paymentIdCheckbox.checked = paymentIdLine.text != "";
    }

    function clearFields() {
        recipientModel.clear();
        fillPaymentDetails("", "", "", "", "");
        priorityDropdown.currentIndex = 0
    }

    // Information dialog
    StandardDialog {
        // dynamically change onclose handler
        property var onCloseCallback
        id: oaPopup
        cancelVisible: false
        onAccepted:  {
            if (onCloseCallback) {
                onCloseCallback()
            }
        }
    }

    ColumnLayout {
      id: pageRoot
      anchors.margins: 20
      anchors.topMargin: 40

      anchors.left: parent.left
      anchors.top: parent.top
      anchors.right: parent.right

      spacing: 30

      RowLayout {
          visible: root.warningContent !== ""

          MoneroComponents.WarningBox {
              text: warningContent
              onLinkActivated: {
                  appWindow.startDaemon(appWindow.persistentSettings.daemonFlags);
              }
          }
      }

      RowLayout {
          visible: leftPanel.minutesToUnlock !== ""

          MoneroComponents.WarningBox {
              text: qsTr("Spendable funds: %1 XMR. Please wait ~%2 minutes for your whole balance to become spendable.").arg(leftPanel.balanceUnlockedString).arg(leftPanel.minutesToUnlock)
          }
      }

        ListModel {
            id: recipientModel

            readonly property int maxRecipients: 16

            ListElement {
                address: ""
                amount: ""
            }

            function newRecipient(address, amount) {
                if (recipientModel.count < maxRecipients) {
                    recipientModel.append({address: address, amount: amount});
                    return true;
                }
                return false;
            }

            function getRecipients() {
                var recipients = [];
                for (var index = 0; index < recipientModel.count; ++index) {
                    const recipient = recipientModel.get(index);
                    recipients.push({
                        address: recipient.address,
                        amount: recipient.amount,
                    });
                }
                return recipients;
            }

            function getAmountTotal() {
                var sum = [];
                for (var index = 0; index < recipientModel.count; ++index) {
                    const amount = recipientModel.get(index).amount;
                    if (amount == "(all)") {
                        return appWindow.getUnlockedBalance();
                    }
                    sum.push(amount || "0");
                }
                return walletManager.amountsSumFromStrings(sum);
            }

            function hasEmptyAmount() {
                for (var index = 0; index < recipientModel.count; ++index) {
                    if (recipientModel.get(index).amount === "") {
                        return true;
                    }
                }
                return false;
            }

            function hasEmptyAddress() {
                for (var index = 0; index < recipientModel.count; ++index) {
                    if (recipientModel.get(index).address === "") {
                        return true;
                    }
                }
                return false;
            }

            function hasInvalidAddress() {
                for (var index = 0; index < recipientModel.count; ++index) {
                    if (!TxUtils.checkAddress(recipientModel.get(index).address, appWindow.persistentSettings.nettype)) {
                        return true;
                    }
                }
                return false;
            }
        }

        Item {
            Layout.fillWidth: true
            implicitHeight: recipientLayout.height

            ColumnLayout {
                id: recipientLayout
                anchors.left: parent.left
                anchors.right: parent.right
                spacing: 0

                readonly property int colSpacing: 10
                readonly property int rowSpacing: 10
                readonly property int secondRowWidth: 125
                readonly property int thirdRowWidth: 50

                RowLayout {
                    Layout.bottomMargin: recipientLayout.rowSpacing / 2
                    spacing: recipientLayout.colSpacing

                    RowLayout {
                        id: addressLabel
                        spacing: 6
                        Layout.fillWidth: true

                        MoneroComponents.TextPlain {
                            font.family: MoneroComponents.Style.fontRegular.name
                            font.pixelSize: 16
                            color: MoneroComponents.Style.defaultFontColor
                            text: qsTr("Address") + translationManager.emptyString
                        }

                        MoneroComponents.InlineButton {
                            fontFamily: FontAwesome.fontFamilySolid
                            fontStyleName: "Solid"
                            fontPixelSize: 18
                            text: FontAwesome.desktop
                            tooltip: qsTr("Grab QR code from screen") + translationManager.emptyString
                            onClicked: {
                                clearFields();
                                const codes = oshelper.grabQrCodesFromScreen();
                                for (var index = 0; index < codes.length; ++index) {
                                    const parsed = walletManager.parse_uri_to_object(codes[index]);
                                    if (!parsed.error) {
                                        fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description, parsed.recipient_name);
                                        break;
                                    } else if (walletManager.addressValid(codes[index], appWindow.persistentSettings.nettype)) {
                                        fillPaymentDetails(codes[index]);
                                        break;
                                    }
                                }
                            }
                        }

                        MoneroComponents.InlineButton {
                            fontFamily: FontAwesome.fontFamilySolid
                            fontStyleName: "Solid"
                            text: FontAwesome.qrcode
                            visible: appWindow.qrScannerEnabled
                            tooltip: qsTr("Scan QR code") + translationManager.emptyString
                            onClicked: {
                                cameraUi.state = "Capture"
                                cameraUi.qrcode_decoded.connect(updateFromQrCode)
                            }
                        }

                        MoneroComponents.InlineButton {
                            fontFamily: FontAwesome.fontFamily
                            text: FontAwesome.addressBook
                            tooltip: qsTr("Import from address book") + translationManager.emptyString
                            onClicked: {
                                middlePanel.addressBookView.selectAndSend = true;
                                appWindow.showPageRequest("AddressBook");
                            }
                        }

                        Item {
                            Layout.fillWidth: true
                        }
                    }

                    RowLayout {
                        id: amountLabel
                        spacing: 6
                        Layout.preferredWidth: 125
                        Layout.maximumWidth: recipientLayout.secondRowWidth

                        MoneroComponents.TextPlain {
                            font.family: MoneroComponents.Style.fontRegular.name
                            font.pixelSize: 16
                            color: MoneroComponents.Style.defaultFontColor
                            text: qsTr("Amount") + translationManager.emptyString
                        }

                        MoneroComponents.InlineButton {
                            fontFamily: FontAwesome.fontFamilySolid
                            fontStyleName: "Solid"
                            fontPixelSize: 16
                            text: FontAwesome.infinity
                            visible: recipientModel.count == 1
                            tooltip: qsTr("Send all unlocked balance of this account") + translationManager.emptyString
                            onClicked: recipientRepeater.itemAt(0).children[1].children[2].text = "(all)";
                        }

                        Item {
                            Layout.fillWidth: true
                        }
                    }

                    Item {
                        Layout.preferredWidth: recipientLayout.thirdRowWidth
                    }
                }

                Repeater {
                    id: recipientRepeater
                    model: recipientModel

                    ColumnLayout {
                        spacing: 0

                        Rectangle {
                            Layout.fillWidth: true
                            Layout.topMargin: -1
                            Layout.leftMargin: 1
                            Layout.rightMargin: recipientLayout.thirdRowWidth + 1
                            color: MoneroComponents.Style.inputBorderColorInActive
                            height: 1
                            visible: index > 0
                        }

                        RowLayout {
                            spacing: 0

                            MoneroComponents.LineEditMulti {
                                KeyNavigation.backtab: index > 0 ? recipientRepeater.itemAt(index - 1).children[1].children[2] : sendButton
                                KeyNavigation.tab: parent.children[2]
                                Layout.alignment: Qt.AlignVCenter
                                Layout.topMargin: index > 0 ? 0 : 1
                                Layout.bottomMargin: 2
                                Layout.fillWidth: true
                                addressValidation: true
                                borderDisabled: true
                                fontColor: error && text != "" ? MoneroComponents.Style.errorColor : MoneroComponents.Style.defaultFontColor
                                fontFamily: MoneroComponents.Style.fontMonoRegular.name
                                fontSize: 14
                                inputPaddingBottom: 0
                                inputPaddingTop: 0
                                inputPaddingRight: 0
                                placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
                                placeholderFontSize: 14
                                spacing: 0
                                wrapMode: Text.WrapAnywhere
                                placeholderText: {
                                    if(persistentSettings.nettype == NetworkType.MAINNET){
                                        return "4.. / 8.. / monero:.. / OpenAlias";
                                    } else if (persistentSettings.nettype == NetworkType.STAGENET){
                                        return "5.. / 7.. / monero:..";
                                    } else if(persistentSettings.nettype == NetworkType.TESTNET){
                                        return "9.. / B.. / monero:..";
                                    }
                                }
                                onTextChanged: {
                                    const parsed = walletManager.parse_uri_to_object(text);
                                    if (!parsed.error) {
                                        fillPaymentDetails(parsed.address, parsed.payment_id, parsed.amount, parsed.tx_description, parsed.recipient_name);
                                    }
                                    address = text;
                                }
                                text: address

                                MoneroComponents.InlineButton {
                                    small: true
                                    text: qsTr("Resolve") + translationManager.emptyString
                                    visible: TxUtils.isValidOpenAliasAddress(address)
                                    onClicked: {
                                        const response = TxUtils.handleOpenAliasResolution(address, descriptionLine.text);
                                        if (response) {
                                            if (response.message) {
                                                oa_message(response.message);
                                            }
                                            if (response.address) {
                                                recipientRepeater.itemAt(index).children[1].children[0].text = response.address;
                                            }
                                            if (response.description) {
                                                descriptionLine.text = response.description;
                                                descriptionCheckbox.checked = true;
                                            }
                                        }
                                    }
                                }
                            }

                            Rectangle {
                                Layout.fillHeight: true
                                Layout.topMargin: index > 0 ? 0 : 1
                                Layout.bottomMargin: 1
                                Layout.leftMargin: recipientLayout.colSpacing / 2 - width
                                Layout.rightMargin: recipientLayout.colSpacing / 2
                                color: MoneroComponents.Style.inputBorderColorInActive
                                width: 1
                            }

                            MoneroComponents.LineEdit {
                                KeyNavigation.backtab: parent.children[0]
                                KeyNavigation.tab: index + 1 < recipientRepeater.count ? recipientRepeater.itemAt(index + 1).children[1].children[0] : sendButton
                                Layout.alignment: Qt.AlignVCenter
                                Layout.topMargin: index > 0 ? 0 : 1
                                Layout.bottomMargin: 2
                                Layout.rightMargin: recipientLayout.colSpacing / 2
                                Layout.preferredWidth: 125
                                Layout.maximumWidth: 125
                                borderDisabled: true
                                fontFamily: MoneroComponents.Style.fontMonoRegular.name
                                fontSize: 14
                                inputPaddingLeft: 0
                                inputPaddingRight: 0
                                inputPaddingTop: 0
                                inputPaddingBottom: 0
                                placeholderFontFamily: MoneroComponents.Style.fontMonoRegular.name
                                placeholderFontSize: 14
                                placeholderLeftMargin: 0
                                placeholderText: "0.00"
                                text: amount
                                onTextChanged: {
                                    text = text.trim().replace(",", ".");
                                    const match = text.match(/^0+(\d.*)/);
                                    if (match) {
                                        const cursorPosition = cursorPosition;
                                        text = match[1];
                                        cursorPosition = Math.max(cursorPosition, 1) - 1;
                                    } else if(text.indexOf('.') === 0){
                                        text = '0' + text;
                                        if (text.length > 2) {
                                            cursorPosition = 1;
                                        }
                                    }
                                    error = walletManager.amountFromString(text) > appWindow.getUnlockedBalance();

                                    amount = text;
                                }
                                validator: RegExpValidator {
                                    regExp: /^\s*(\d{1,8})?([\.,]\d{1,12})?\s*$/
                                }
                            }

                            MoneroComponents.TextPlain {
                                Layout.leftMargin: recipientLayout.colSpacing / 2
                                Layout.preferredWidth: recipientLayout.thirdRowWidth
                                font.family: FontAwesome.fontFamilySolid
                                font.styleName: "Solid"
                                horizontalAlignment: Text.AlignHCenter
                                opacity: mouseArea.containsMouse ? 1 : 0.85
                                text: FontAwesome.times
                                tooltip: qsTr("Remove recipient")  + translationManager.emptyString
                                tooltipLeft: true
                                visible: recipientModel.count > 1

                                MouseArea {
                                    id: mouseArea
                                    anchors.fill: parent
                                    cursorShape: Qt.PointingHandCursor
                                    hoverEnabled: true
                                    onEntered: parent.tooltipPopup.open()
                                    onExited: parent.tooltipPopup.close()
                                    onClicked: recipientModel.remove(index);
                                }
                            }

                            MoneroComponents.TextPlain {
                                Layout.leftMargin: recipientLayout.colSpacing / 2
                                Layout.preferredWidth: recipientLayout.thirdRowWidth
                                horizontalAlignment: Text.AlignHCenter
                                font.family: MoneroComponents.Style.fontRegular.name
                                text: "XMR"
                                visible: recipientModel.count == 1
                            }
                        }
                    }
                }

                GridLayout {
                    id: totalLayout
                    Layout.topMargin: recipientLayout.rowSpacing / 2
                    Layout.fillWidth: true
                    columns: 3
                    columnSpacing: recipientLayout.colSpacing
                    rowSpacing: 0

                    RowLayout {
                        Layout.column: 0
                        Layout.row: 0
                        Layout.fillWidth: true
                        Layout.topMargin: recipientModel.count > 1 ? 0 : -1
                        spacing: 0

                        CheckBox {
                            border: false
                            checked: false
                            enabled: {
                                if (recipientModel.count > 0 && recipientModel.get(0).amount == "(all)") {
                                    return false;
                                }
                                if (recipientModel.count >= recipientModel.maxRecipients) {
                                    return false;
                                }
                                return true;
                            }
                            fontAwesomeIcons: true
                            fontSize: descriptionLine.labelFontSize
                            iconOnTheLeft: true
                            text: qsTr("Add recipient") + translationManager.emptyString
                            toggleOnClick: false
                            uncheckedIcon: FontAwesome.plusCircle
                            onClicked: {
                                recipientModel.newRecipient("", "");
                            }
                        }

                        MoneroComponents.TextPlain {
                            Layout.fillWidth: true
                            horizontalAlignment: Text.AlignRight
                            font.family: MoneroComponents.Style.fontRegular.name
                            font.pixelSize: 16
                            text: recipientModel.count > 1 ? qsTr("Total") + translationManager.emptyString : ""
                        }
                    }

                    MoneroComponents.LineEdit {
                        id: totalValue
                        Layout.column: 1
                        Layout.row: 0
                        Layout.preferredWidth: recipientLayout.secondRowWidth
                        Layout.topMargin: recipientModel.count > 1 ? 0 : -1
                        Layout.maximumWidth: recipientLayout.secondRowWidth
                        borderDisabled: true
                        fontFamily: MoneroComponents.Style.fontMonoRegular.name
                        fontSize: 14
                        inputHeight: 30
                        inputPaddingLeft: 0
                        inputPaddingRight: 0
                        inputPaddingTop: 0
                        inputPaddingBottom: 0
                        readOnly: true
                        text: Utils.removeTrailingZeros(walletManager.displayAmount(recipientModel.getAmountTotal()))
                        visible: recipientModel.count > 1
                    }

                    MoneroComponents.TextPlain {
                        Layout.column: 2
                        Layout.row: 0
                        Layout.preferredWidth: recipientLayout.thirdRowWidth
                        Layout.maximumWidth: recipientLayout.thirdRowWidth
                        horizontalAlignment: Text.AlignHCenter
                        font.family: MoneroComponents.Style.fontRegular.name
                        text: "XMR"
                        visible: recipientModel.count > 1
                    }

                    MoneroComponents.LineEdit {
                        Layout.column: 1
                        Layout.row: recipientModel.count > 1 ? 1 : 0
                        Layout.preferredWidth: recipientLayout.secondRowWidth
                        Layout.topMargin: recipientModel.count > 1 ? 0 : -1
                        Layout.maximumWidth: recipientLayout.secondRowWidth
                        borderDisabled: true
                        fontFamily: MoneroComponents.Style.fontMonoRegular.name
                        fontSize: 14
                        inputHeight: 30
                        inputPaddingLeft: 0
                        inputPaddingRight: 0
                        inputPaddingTop: 0
                        inputPaddingBottom: 0
                        opacity: 0.7
                        readOnly: true
                        text: fiatApiConvertToFiat(walletManager.displayAmount(recipientModel.getAmountTotal()))
                        visible: persistentSettings.fiatPriceEnabled
                    }

                    MoneroComponents.TextPlain {
                        Layout.column: 2
                        Layout.row: recipientModel.count > 1 ? 1 : 0
                        Layout.preferredWidth: recipientLayout.thirdRowWidth
                        Layout.topMargin: recipientModel.count > 1 ? 0 : -1
                        Layout.maximumWidth: recipientLayout.thirdRowWidth
                        font.family: MoneroComponents.Style.fontRegular.name
                        horizontalAlignment: Text.AlignHCenter
                        opacity: 0.7
                        text: fiatApiCurrencySymbol()
                        visible: persistentSettings.fiatPriceEnabled
                    }
                }
            }

            Rectangle {
                anchors.top: recipientLayout.top
                anchors.topMargin: addressLabel.height + recipientLayout.rowSpacing / 2
                anchors.bottom: recipientLayout.bottom
                anchors.bottomMargin: totalLayout.height + recipientLayout.rowSpacing / 2
                anchors.left: recipientLayout.left
                anchors.right: recipientLayout.right
                anchors.rightMargin: recipientLayout.thirdRowWidth
                color: "transparent"
                border.color: MoneroComponents.Style.inputBorderColorInActive
                border.width: 1
                radius: 4
            }
        }

        ColumnLayout {
            spacing: 0
            visible: appWindow.walletMode >= 2

            // Note: workaround for translations in listElements
            // ListElement: cannot use script for property value, so
            // code like this wont work:
            // ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
            // For translations to work, the strings need to be listed in
            // the file components/StandardDropdown.qml too.

            // Priorites after v5
            ListModel {
                id: priorityModelV5

                ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
                ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
                ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
                ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
                ListElement { column1: qsTr("Fastest (x200 fee)")  ; column2: "";  priority: 4 }
            }

            RowLayout {
                Layout.topMargin: 5
                spacing: 10

                StandardDropdown {
                    Layout.maximumWidth: 200
                    id: priorityDropdown
                    currentIndex: 0
                    dataModel: priorityModelV5
                    labelText: qsTr("Transaction priority") + translationManager.emptyString
                    labelFontSize: 16
                }

                MoneroComponents.TextPlain {
                    id: feeLabel
                    Layout.alignment: Qt.AlignBottom
                    Layout.bottomMargin: 11
                    font.family: MoneroComponents.Style.fontRegular.name
                    font.pixelSize: 14
                    color: MoneroComponents.Style.defaultFontColor
                    opacity: 0.7
                    property bool estimating: false
                    property var estimatedFee: null
                    property string estimatedFeeFiat: {
                        if (!persistentSettings.fiatPriceEnabled || estimatedFee == null) {
                            return "";
                        }
                        const fiatFee = fiatApiConvertToFiat(estimatedFee);
                        return " (%1 %3)".arg(fiatFee < 0.01 ? "<0.01" : "~" + fiatFee).arg(fiatApiCurrencySymbol());
                    }
                    property var fee: {
                        estimatedFee = null;
                        estimating = sendButton.enabled;
                        if (!sendButton.enabled || !currentWallet) {
                            return;
                        }
                        var addresses = [];
                        var amounts = [];
                        for (var index = 0; index < recipientModel.count; ++index) {
                            const recipient = recipientModel.get(index);
                            addresses.push(recipient.address);
                            amounts.push(walletManager.amountFromString(recipient.amount));
                        }
                        currentWallet.estimateTransactionFeeAsync(
                            addresses,
                            amounts,
                            priorityModelV5.get(priorityDropdown.currentIndex).priority,
                            function (amount) {
                                if (amount) {
                                    estimatedFee = Utils.removeTrailingZeros(amount);
                                }
                                estimating = false;
                            });
                    }
                    text: {
                        if (!sendButton.enabled || estimatedFee == null) {
                            return ""
                        }
                        return "~%1 XMR%2 %3".arg(estimatedFee)
                            .arg(estimatedFeeFiat)
                            .arg(qsTr("fee") + translationManager.emptyString);
                    }

                    BusyIndicator {
                        anchors.left: parent.left
                        running: feeLabel.estimating
                        height: parent.height
                        width: height
                    }
                }
            }
        }

      MoneroComponents.WarningBox {
          text: qsTr("Description field contents match long payment ID format. \
          Please don't paste long payment ID into description field, your funds might be lost.") + translationManager.emptyString;
          visible: warningLongPidDescription
      }

      ColumnLayout {
          spacing: 15

          ColumnLayout {
              CheckBox {
                  id: descriptionCheckbox
                  border: false
                  checkedIcon: FontAwesome.minusCircle
                  uncheckedIcon: FontAwesome.plusCircle
                  fontAwesomeIcons: true
                  fontSize: descriptionLine.labelFontSize
                  iconOnTheLeft: true
                  Layout.fillWidth: true
                  text: qsTr("Add description") + translationManager.emptyString
                  onClicked: {
                      if (!descriptionCheckbox.checked) {
                        descriptionLine.text = "";
                      }
                  }
              }

              LineEdit {
                  id: descriptionLine
                  placeholderFontSize: 16
                  fontSize: 16
                  placeholderText: qsTr("Saved to local wallet history") + " (" + qsTr("only visible to you") + ")" + translationManager.emptyString
                  Layout.fillWidth: true
                  visible: descriptionCheckbox.checked
              }
          }

          ColumnLayout {
              visible: paymentIdCheckbox.checked
              CheckBox {
                  id: paymentIdCheckbox
                  border: false
                    checkedIcon: FontAwesome.minusCircle
                    uncheckedIcon: FontAwesome.plusCircle
                    fontAwesomeIcons: true
                  fontSize: paymentIdLine.labelFontSize
                  iconOnTheLeft: true
                  Layout.fillWidth: true
                  text: qsTr("Add payment ID") + translationManager.emptyString
                  onClicked: {
                      if (!paymentIdCheckbox.checked) {
                        paymentIdLine.text = "";
                      }
                  }
              }

              // payment id input
              LineEditMulti {
                  id: paymentIdLine
                  fontBold: true
                  placeholderText: qsTr("64 hexadecimal characters") + translationManager.emptyString
                  readOnly: true
                  Layout.fillWidth: true
                  wrapMode: Text.WrapAnywhere
                  addressValidation: false
                  visible: paymentIdCheckbox.checked
                  error: paymentIdCheckbox.checked
              }
          }
      }

      MoneroComponents.WarningBox {
          id: paymentIdWarningBox
          text: qsTr("Long payment IDs are obsolete. \
          Long payment IDs were not encrypted on the blockchain and would harm your privacy. \
          If the party you're sending to still requires a long payment ID, please notify them.") + translationManager.emptyString;
          visible: paymentIdCheckbox.checked || warningLongPidDescription
      }

      MoneroComponents.WarningBox {
          id: sendButtonWarningBox
          text: root.sendButtonWarning
          visible: root.sendButtonWarning !== ""
      }

      RowLayout {
          StandardButton {
              id: sendButton
              rightIcon: "qrc:///images/rightArrow.png"
              Layout.topMargin: 4
              text: qsTr("Send") + translationManager.emptyString
              enabled: !sendButtonWarningBox.visible && !warningContent && !recipientModel.hasEmptyAddress() && !paymentIdWarningBox.visible
              onClicked: {
                  console.log("Transfer: paymentClicked")
                  var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
                  console.log("priority: " + priority)
                  setPaymentId(paymentIdLine.text.trim());
                  root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
              }
          }
      }

      function checkInformation() {
        return !recipientModel.hasEmptyAmount() &&
            recipientModel.getAmountTotal() <= appWindow.getUnlockedBalance() &&
            !recipientModel.hasInvalidAddress();
      }

    } // pageRoot

    ColumnLayout {
        id: advancedLayout
        anchors.top: pageRoot.bottom
        anchors.left: parent.left
        anchors.margins: 20
        anchors.topMargin: 32
        spacing: 10
        enabled: !viewOnly || pageRoot.enabled

        RowLayout {
            visible: appWindow.walletMode >= 2
            CheckBox2 {
                id: showAdvancedCheckbox
                checked: persistentSettings.transferShowAdvanced
                onClicked: {
                    persistentSettings.transferShowAdvanced = !persistentSettings.transferShowAdvanced
                }
                text: qsTr("Advanced options") + translationManager.emptyString
            }
        }

        AdvancedOptionsItem {
            visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
            title: qsTr("Outputs") + translationManager.emptyString
            button1.text: qsTr("Export") + translationManager.emptyString
            button1.enabled: appWindow.viewOnly
            button1.onClicked: {
                console.log("Transfer: export outputs clicked")
                exportOutputsDialog.open();
            }
            button2.text: qsTr("Import") + translationManager.emptyString
            button2.enabled: !appWindow.viewOnly
            button2.onClicked: {
                console.log("Transfer: import outputs clicked")
                importOutputsDialog.open();
            }
            tooltip: {
                var header = qsTr("Required for cold wallets to sign their corresponding key images") + translationManager.emptyString;
                return "<style type='text/css'>.header{ font-size: 13px; } p{line-height:20px; margin-top:0px; margin-bottom:0px; " +
                       ";} p.orange{color:#ff9323;}</style>" +
                       "<div class='header'>" + header + "</div>" +
                       "<p>" + qsTr("1. Using view-only wallet, export the outputs into a file") + "</p>" +
                       "<p>" + qsTr("2. Using cold wallet, import the outputs file") + "</p>" +
                       translationManager.emptyString
            }
        }

        AdvancedOptionsItem {
            visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
            title: qsTr("Key images") + translationManager.emptyString
            button1.text: qsTr("Export") + translationManager.emptyString
            button1.enabled: !appWindow.viewOnly
            button1.onClicked: {
                console.log("Transfer: export key images clicked")
                exportKeyImagesDialog.open();
            }
            button2.text: qsTr("Import") + translationManager.emptyString
            button2.enabled: appWindow.viewOnly && appWindow.isTrustedDaemon()
            button2.onClicked: {
                console.log("Transfer: import key images clicked")
                importKeyImagesDialog.open(); 
            }
            tooltip: {
                var errorMessage = "";
                if (appWindow.viewOnly && !appWindow.isTrustedDaemon()){
                    errorMessage = "<p class='orange'>" + qsTr("* To import, you must connect to a local node or a trusted remote node") + "</p>";
                }
                var header = qsTr("Required for view-only wallets to display the real balance") + translationManager.emptyString;
                return "<style type='text/css'>.header{ font-size: 13px; } p{line-height:20px; margin-top:0px; margin-bottom:0px; " +
                       ";} p.orange{color:#ff9323;}</style>" +
                       "<div class='header'>" + header + "</div>" +
                       "<p>" + qsTr("1. Using cold wallet, export the key images into a file") + "</p>" +
                       "<p>" + qsTr("2. Using view-only wallet, import the key images file") + "</p>" +
                       errorMessage + translationManager.emptyString
            }
        }

        AdvancedOptionsItem {
            visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
            title: qsTr("Offline transaction signing") + translationManager.emptyString
            button1.text: qsTr("Create") + translationManager.emptyString
            button1.enabled: appWindow.viewOnly && pageRoot.checkInformation() && appWindow.daemonSynced
            button1.onClicked: {
                console.log("Transfer: saveTx Clicked")
                var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
                console.log("priority: " + priority)
                setPaymentId(paymentIdLine.text.trim());
                root.paymentClicked(recipientModel.getRecipients(), paymentIdLine.text, root.mixin, priority, descriptionLine.text)
            }
            button2.text: qsTr("Sign (offline)") + translationManager.emptyString
            button2.enabled: !appWindow.viewOnly
            button2.onClicked: {
                console.log("Transfer: sign tx clicked")
                signTxDialog.open();
            }
            button3.text: qsTr("Submit") + translationManager.emptyString
            button3.enabled: appWindow.viewOnly
            button3.onClicked: {
                console.log("Transfer: submit tx clicked")
                submitTxDialog.open();
            }
            tooltip: {
                var errorMessage = "";
                if (appWindow.viewOnly && !pageRoot.checkInformation()) {
                    errorMessage = "<p class='orange'>" + qsTr("* To create a transaction file, please enter address and amount above") + "</p>";
                }
                var header = qsTr("Spend XMR from a cold (offline) wallet") + translationManager.emptyString;
                return "<style type='text/css'>.header{ font-size: 13px; } p{line-height:20px; margin-top:0px; margin-bottom:0px; " +
                       ";} p.orange{color:#ff9323;}</style>" +
                       "<div class='header'>" + header + "</div>" +
                       "<p>" + qsTr("1. Using view-only wallet, export the outputs into a file") + "</p>" +
                       "<p>" + qsTr("2. Using cold wallet, import the outputs file and export the key images") + "</p>" +
                       "<p>" + qsTr("3. Using view-only wallet, import the key images file and create a transaction file") + "</p>" +
                       errorMessage +
                       "<p>" + qsTr("4. Using cold wallet, sign your transaction file") + "</p>" +
                       "<p>" + qsTr("5. Using view-only wallet, submit your signed transaction") + "</p>" + translationManager.emptyString
            }
        }

        AdvancedOptionsItem {
            visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
            title: qsTr("Unmixable outputs") + translationManager.emptyString
            button1.text: qsTr("Sweep") + translationManager.emptyString
            button1.enabled : pageRoot.enabled
            button1.onClicked: {
                console.log("Transfer: sweepUnmixableClicked")
                root.sweepUnmixableClicked()
            }
            tooltip: qsTr("Create a transaction that spends old unmovable outputs") + translationManager.emptyString
        }
    }

    //SignTxDialog
    FileDialog {
        id: signTxDialog
        title: qsTr("Please choose a file") + translationManager.emptyString
        folder: "file://" + appWindow.accountsDir
        nameFilters: [ "Unsigned transfers (*)"]

        onAccepted: {
            var path = walletManager.urlToLocalPath(fileUrl);
            // Load the unsigned tx from file
            var transaction = currentWallet.loadTxFile(path);

            if (transaction.status !== PendingTransaction.Status_Ok) {
                console.error("Can't load unsigned transaction: ", transaction.errorString);
                informationPopup.title = qsTr("Error") + translationManager.emptyString;
                informationPopup.text  = qsTr("Can't load unsigned transaction: ") + transaction.errorString
                informationPopup.icon  = StandardIcon.Critical
                informationPopup.onCloseCallback = null
                informationPopup.open();
                // deleting transaction object, we don't want memleaks
                transaction.destroy();
            } else {
                confirmationDialog.text =  qsTr("\nConfirmation message:\n ") + transaction.confirmationMessage
                console.log(transaction.confirmationMessage);

                // Show confirmation dialog
                confirmationDialog.title = qsTr("Confirmation") + translationManager.emptyString
                confirmationDialog.icon = StandardIcon.Question
                confirmationDialog.onAcceptedCallback = function() {
                    transaction.sign(path+"_signed");
                    transaction.destroy();
                };
                confirmationDialog.onRejectedCallback = transaction.destroy;

                confirmationDialog.open()
            }

        }
        onRejected: {
            // File dialog closed
            console.log("Canceled")
        }
    }

    //SignTxDialog
    FileDialog {
        id: submitTxDialog
        title: qsTr("Please choose a file") + translationManager.emptyString
        folder: "file://" + appWindow.accountsDir
        nameFilters: [ "signed transfers (*)"]

        onAccepted: {
            if(!currentWallet.submitTxFile(walletManager.urlToLocalPath(fileUrl))){
                informationPopup.title = qsTr("Error") + translationManager.emptyString;
                informationPopup.text  = qsTr("Can't submit transaction: ") + currentWallet.errorString
                informationPopup.icon  = StandardIcon.Critical
                informationPopup.onCloseCallback = null
                informationPopup.open();
            } else {
                informationPopup.title = qsTr("Information") + translationManager.emptyString
                informationPopup.text  = qsTr("Monero sent successfully") + translationManager.emptyString
                informationPopup.icon  = StandardIcon.Information
                informationPopup.onCloseCallback = null
                informationPopup.open();
            }
        }
        onRejected: {
            console.log("Canceled")
        }

    }
    
    FileDialog {
        id: exportOutputsDialog
        selectMultiple: false
        selectExisting: false
        onAccepted: {
            console.log(walletManager.urlToLocalPath(exportOutputsDialog.fileUrl))
            if (currentWallet.exportOutputs(walletManager.urlToLocalPath(exportOutputsDialog.fileUrl), true)) {
                appWindow.showStatusMessage(qsTr("Outputs successfully exported to file") + translationManager.emptyString, 3);
            } else {
                appWindow.showStatusMessage(currentWallet.errorString, 5);
            }
        }
        onRejected: {
            console.log("Canceled");
        }
    }

    FileDialog {
        id: importOutputsDialog
        selectMultiple: false
        selectExisting: true
        title: qsTr("Please choose a file") + translationManager.emptyString
        onAccepted: {
            console.log(walletManager.urlToLocalPath(importOutputsDialog.fileUrl))
            if (currentWallet.importOutputs(walletManager.urlToLocalPath(importOutputsDialog.fileUrl))) {
                appWindow.showStatusMessage(qsTr("Outputs successfully imported to wallet") + translationManager.emptyString, 3);
            } else {
                appWindow.showStatusMessage(currentWallet.errorString, 5);
            }
        }
        onRejected: {
            console.log("Canceled");
        }
    }

    //ExportKeyImagesDialog
    FileDialog {
        id: exportKeyImagesDialog
        selectMultiple: false
        selectExisting: false
        onAccepted: {
            console.log(walletManager.urlToLocalPath(exportKeyImagesDialog.fileUrl))
            if (currentWallet.exportKeyImages(walletManager.urlToLocalPath(exportKeyImagesDialog.fileUrl), true)) {
                appWindow.showStatusMessage(qsTr("Key images successfully exported to file") + translationManager.emptyString, 3);
            } else {
                appWindow.showStatusMessage(currentWallet.errorString, 5);
            }
        }
        onRejected: {
            console.log("Canceled");
        }
    }

    //ImportKeyImagesDialog
    FileDialog {
        id: importKeyImagesDialog
        selectMultiple: false
        selectExisting: true
        title: qsTr("Please choose a file") + translationManager.emptyString
        onAccepted: {
            console.log(walletManager.urlToLocalPath(importKeyImagesDialog.fileUrl))
            if (currentWallet.importKeyImages(walletManager.urlToLocalPath(importKeyImagesDialog.fileUrl))) {
                appWindow.showStatusMessage(qsTr("Key images successfully imported to wallet") + translationManager.emptyString, 3);
            } else {
                appWindow.showStatusMessage(currentWallet.errorString, 5);
            }
        }
        onRejected: {
            console.log("Canceled");
        }
    }



    Component.onCompleted: {
        //Disable password page until enabled by updateStatus
        pageRoot.enabled = false
    }

    // fires on every page load
    function onPageCompleted() {
        console.log("transfer page loaded")
        updateStatus();
    }

    //TODO: Add daemon sync status
    //TODO: enable send page when we're connected and daemon is synced

    function updateStatus() {
        var messageNotConnected = qsTr("Wallet is not connected to daemon.");
        if(appWindow.walletMode >= 2 && !persistentSettings.useRemoteNode) messageNotConnected += root.startLinkText;
        pageRoot.enabled = true;
        if(typeof currentWallet === "undefined") {
            root.warningContent = messageNotConnected;
            return;
        }

        if (currentWallet.viewOnly) {
           // warningText.text = qsTr("Wallet is view only.")
           //return;
        }
        //pageRoot.enabled = false;

        switch (currentWallet.connected()) {
        case Wallet.ConnectionStatus_Connecting:
            root.warningContent = qsTr("Wallet is connecting to daemon.")
            break
        case Wallet.ConnectionStatus_Disconnected:
            root.warningContent = messageNotConnected;
            break
        case Wallet.ConnectionStatus_WrongVersion:
            root.warningContent = qsTr("Connected daemon is not compatible with GUI. \n" +
                                   "Please upgrade or connect to another daemon")
            break
        default:
            if(!appWindow.daemonSynced){
                root.warningContent = qsTr("Waiting on daemon synchronization to finish.")
            } else {
                // everything OK, enable transfer page
                // Light wallet is always ready
                pageRoot.enabled = true;
                root.warningContent = "";
            }
        }
    }

    // Popuplate fields from addressbook.
    function sendTo(address, paymentId, description, amount) {
        middlePanel.state = 'Transfer';

        fillPaymentDetails(address, paymentId, amount, description);
    }
}