/*
    SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

import QtQuick
import QtQuick.Controls
import QtQuick.Templates as T
import org.kde.ksvg as KSvg
//NOTE: importing PlasmaCore is necessary in order to make KSvg load the current Plasma Theme
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import "mobiletextselection" as MobileTextSelection
import "private" as Private

T.TextField {
    id: control

    /*!
     * Whether the button to clear the text from TextField is visible.
     * @since 5.73
     * @deprecated since 5.93 Use SearchField instead
     */
    property bool clearButtonShown: false

    // Can't guarantee that background will always be present or have the margins property
    readonly property bool __hasBackgroundAndMargins: background && background.hasOwnProperty("margins")

    // store information that echoMode was set to Password, regardless of its current value
    property bool __isPassword: false
    onEchoModeChanged: echoMode => {
        __isPassword |= (echoMode === TextInput.Password);
    }

    // TextField doesn't have this property by default for whatever reason
    property bool visualFocus: activeFocus && [
        Qt.TabFocusReason,
        Qt.BacktabFocusReason,
        Qt.ShortcutFocusReason,
    ].includes(focusReason)

    /* It might be preferable to do background width OR content width if we
     * want content to stay within the background rather than expanding the
     * control, but this is maintaining compatibility with the pre-existing
     * behavior. Use the following 2 lines if you want text to stay within the
     * background:
    implicitBackgroundWidth + leftInset + rightInset
    || Math.ceil(Math.max(contentWidth + leftPadding + rightPadding, placeholder.implicitWidth))
     */
    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
                            Math.ceil(Math.max(contentWidth + leftPadding + rightPadding, placeholder.implicitWidth)))
    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
                             Math.max(contentHeight + topPadding + bottomPadding, placeholder.implicitHeight, __isPassword ? passwordsizeholder.implicitHeight : 0))

    topPadding: __hasBackgroundAndMargins ? background.margins.top : 0
    leftPadding: (__hasBackgroundAndMargins ? background.margins.left : 0) + (control.effectiveHorizontalAlignment === TextInput.AlignRight ? inlineButtonRow.width : 0)
    rightPadding: (__hasBackgroundAndMargins ? background.margins.right : 0) + (control.effectiveHorizontalAlignment === TextInput.AlignRight ? 0 : inlineButtonRow.width)
    bottomPadding: __hasBackgroundAndMargins ? background.margins.bottom : 0

    Kirigami.Theme.inherit: !background || !background.visible
    Kirigami.Theme.colorSet: Kirigami.Theme.View

    color: Kirigami.Theme.textColor
    selectionColor: Kirigami.Theme.highlightColor
    selectedTextColor: Kirigami.Theme.highlightedTextColor
    placeholderTextColor: Kirigami.Theme.disabledTextColor

    verticalAlignment: TextInput.AlignVCenter
    // Manually setting this fixes alignment in RTL layouts
    horizontalAlignment: TextInput.AlignLeft
    opacity: control.enabled ? 1 : 0.6
    hoverEnabled: !Kirigami.Settings.tabletMode

    selectByMouse: !Kirigami.Settings.tabletMode

    cursorDelegate: Kirigami.Settings.tabletMode ? mobileCursor : null
    Component {
        id: mobileCursor
        MobileTextSelection.MobileCursor {
            target: control
        }
    }
    onFocusChanged: {
        if (focus) {
            MobileTextSelection.MobileTextActionsToolBar.controlRoot = control;
        }
    }

    onTextChanged: MobileTextSelection.MobileTextActionsToolBar.shouldBeVisible = false;
    onPressed: event => MobileTextSelection.MobileTextActionsToolBar.shouldBeVisible = true;

    onPressAndHold: event => {
        if (!Kirigami.Settings.tabletMode) {
            return;
        }
        forceActiveFocus();
        cursorPosition = positionAt(event.x, event.y);
        selectWord();
    }
    MobileTextSelection.MobileCursor {
        target: control
        selectionStartHandle: true
        property var rect: target.positionToRectangle(target.selectionStart)
        //FIXME: this magic values seem to be always valid, for every font,every dpi, every scaling
        x: rect.x + 5
        y: rect.y + 6
    }

    Label {
        id: placeholder
        enabled: false
        x: 0
        y: 0
        topPadding: control.topPadding
        bottomPadding: control.bottomPadding
        leftPadding: control.leftPadding
        rightPadding: control.rightPadding
        height: control.height
        width: control.width
        font: control.font
        LayoutMirroring.enabled: false
        horizontalAlignment: control.effectiveHorizontalAlignment
        verticalAlignment: control.verticalAlignment
        elide: Text.ElideRight
        renderType: control.renderType
        text: control.placeholderText
        visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
        color: control.placeholderTextColor
    }

    // Object holding the size (implicitHeight) of the password dot character,
    // so that a password TextField never gets shorter than required to display it
    Label {
        id: passwordsizeholder
        enabled: false
        visible: false
        topPadding: control.topPadding
        bottomPadding: control.bottomPadding
        leftPadding: control.leftPadding
        rightPadding: control.rightPadding
        font: control.font
        horizontalAlignment: control.horizontalAlignment
        verticalAlignment: control.verticalAlignment
        elide: Text.ElideRight
        renderType: control.renderType
        text: control.passwordCharacter
    }

    Row {
        id: inlineButtonRow
        anchors.right: control.right
        anchors.rightMargin: control.__hasBackgroundAndMargins ? background.margins.right : 0
        anchors.verticalCenter: control.verticalCenter
        LayoutMirroring.enabled: control.effectiveHorizontalAlignment === TextInput.AlignRight

        Kirigami.Icon {
            id: clearButton
            //ltr confusingly refers to the direction of the arrow in the icon, not the text direction which it should be used in
            source: clearButtonShown ? (control.effectiveHorizontalAlignment === TextInput.AlignRight ? "edit-clear-locationbar-ltr" : "edit-clear-locationbar-rtl") : ""
            height: Kirigami.Units.iconSizes.small
            width: height
            opacity: (control.length > 0 && clearButtonShown && control.enabled) ? 1 : 0
            visible: opacity > 0
            Behavior on opacity {
                enabled: Kirigami.Units.longDuration > 0
                NumberAnimation {
                    duration: Kirigami.Units.longDuration
                    easing.type: Easing.InOutQuad
                }
            }
            MouseArea {
                anchors.fill: parent
                onClicked: mouse => {
                    control.clear()
                    control.forceActiveFocus()
                }
            }
        }
    }

    background: KSvg.FrameSvgItem {
        implicitWidth: Kirigami.Units.gridUnit * 8 + margins.left + margins.right
        implicitHeight: Kirigami.Units.gridUnit + margins.top + margins.bottom
        imagePath: "widgets/lineedit"
        prefix: "base"

        KSvg.FrameSvgItem {
            anchors {
                fill: parent
                leftMargin: -margins.left
                topMargin: -margins.top
                rightMargin: -margins.right
                bottomMargin: -margins.bottom
            }
            imagePath: "widgets/lineedit"
            prefix: "hover"
            visible: opacity > 0
            opacity: control.enabled && control.hovered
            Behavior on opacity {
                enabled: control.enabled && control.hovered && Kirigami.Units.longDuration > 0
                NumberAnimation {
                    duration: Kirigami.Units.longDuration
                    easing.type: Easing.OutCubic
                }
            }
        }
        KSvg.FrameSvgItem {
            z: hasElement("hint-focus-over-base") ? 0 : -1
            anchors {
                fill: parent
                leftMargin: -margins.left
                topMargin: -margins.top
                rightMargin: -margins.right
                bottomMargin: -margins.bottom
            }
            imagePath: "widgets/lineedit"
            prefix: control.visualFocus && hasElement("focusframe-center") ? "focusframe" : "focus"
            visible: opacity > 0
            opacity: control.visualFocus || control.activeFocus
            Behavior on opacity {
                enabled: Kirigami.Units.longDuration > 0
                NumberAnimation {
                    duration: Kirigami.Units.longDuration
                    easing.type: Easing.OutCubic
                }
            }
        }
    }
}
