/*
 *  SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 */

import QtQuick 2.6
import QtQuick.Controls 2.3 as QtControls
import QtQuick.Layouts 1.0
import QtQuick.Window 2.2

import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.configuration 2.0
import org.kde.kitemmodels as KItemModels

//TODO: all of this will be done with desktop components
Rectangle {
    id: root
   // Layout.minimumWidth:  plasmoid.availableScreenRect.width
   // Layout.minimumHeight: plasmoid.availableScreenRect.height


    LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
    LayoutMirroring.childrenInherit: true

    color: "transparent"

//BEGIN properties
    property bool isContainment: false
    property alias internalDialog: dialogContents
//END properties

//BEGIN model
    property ConfigModel globalConfigModel:  globalAppletConfigModel

    ConfigModel {
        id: globalAppletConfigModel
    }

    Connections {
        target: root.Window.window
        function onVisibleChanged() {
            if (root.Window.window.visible) {
                root.Window.window.showMaximized();
            }
        }
    }

    KItemModels.KSortFilterProxyModel {
        id: configDialogFilterModel
        sourceModel: configDialog.configModel
        filterRoleName: "visible"
        filterRowCallback: (sourceRow, sourceParent) => {
            let value = sourceModel.data(sourceModel.index(sourceRow, 0, sourceParent), filterRole);
            return value === true;
        }
    }
//END model

//BEGIN functions
    function saveConfig() {
        if (pageStack.currentItem.saveConfig) {
            pageStack.currentItem.saveConfig()
        }
        for (var key in plasmoid.configuration) {
            if (pageStack.currentItem["cfg_"+key] !== undefined) {
                plasmoid.configuration[key] = pageStack.currentItem["cfg_"+key]
            }
        }
    }

    function configurationHasChanged() {
        for (var key in plasmoid.configuration) {
            if (pageStack.currentItem["cfg_"+key] !== undefined) {
                //for objects == doesn't work
                if (typeof plasmoid.configuration[key] == 'object') {
                    for (var i in plasmoid.configuration[key]) {
                        if (plasmoid.configuration[key][i] != pageStack.currentItem["cfg_"+key][i]) {
                            return true;
                        }
                    }
                    return false;
                } else if (pageStack.currentItem["cfg_"+key] != plasmoid.configuration[key]) {
                    return true;
                }
            }
        }
        return false;
    }


    function settingValueChanged() {
        if (pageStack.currentItem.saveConfig !== undefined) {
            pageStack.currentItem.saveConfig();
        } else {
            root.saveConfig();
        }
    }
//END functions


//BEGIN connections
    Component.onCompleted: {
        if (!isContainment && configDialog.configModel && configDialog.configModel.count > 0) {
            if (configDialog.configModel.get(0).source) {
                pageStack.sourceFile = configDialog.configModel.get(0).source
            } else if (configDialog.configModel.get(0).kcm) {
                pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml");
                pageStack.currentItem.kcm = configDialog.configModel.get(0).kcm;
            } else {
                pageStack.sourceFile = "";
            }
            pageStack.title = configDialog.configModel.get(0).name
        } else {
            pageStack.sourceFile = globalConfigModel.get(0).source
            pageStack.title = globalConfigModel.get(0).name
        }
//         root.width = dialogRootItem.implicitWidth
//         root.height = dialogRootItem.implicitHeight
    }
    onVisibleChanged: {
        if (visible) {
            dialogContents.visible = true;
        }
    }
//END connections

//BEGIN UI components

    Rectangle {
        id: dialogContents
        visible: true
        anchors.fill: parent
        color: Kirigami.Theme.backgroundColor

        ColumnLayout {
            id: dialogRootItem
            anchors.fill: parent

            spacing: 0
            implicitWidth: scroll.implicitWidth

            QtControls.ScrollView {
                id: scroll

                activeFocusOnTab: false

                Layout.fillWidth: true
                Layout.fillHeight: true

                implicitWidth: pageColumn.implicitWidth
                implicitHeight: pageColumn.implicitHeight

                property Item flickableItem: pageFlickable
                // this horrible code below ensures the control with active focus stays visible in the window
                // by scrolling the view up or down as needed when tabbing through the window
                Window.onActiveFocusItemChanged: {
                    var flickable = scroll.flickableItem;

                    var item = Window.activeFocusItem;
                    if (!item) {
                        return;
                    }

                    // when an item within ScrollView has active focus the ScrollView,
                    // as FocusScope, also has it, so we only scroll in this case
                    if (!scroll.activeFocus) {
                        return;
                    }

                    var padding = Kirigami.Units.gridUnit * 2 // some padding to the top/bottom when we scroll

                    var yPos = item.mapToItem(scroll.contentItem, 0, 0).y;
                    if (yPos < flickable.contentY) {
                        flickable.contentY = Math.max(0, yPos - padding);

                    // The "Math.min(padding, item.height)" ensures that we only scroll the item into view
                    // when it's barely visible. The logic was mostly meant for keyboard navigating through
                    // a list of CheckBoxes, so this check keeps us from trying to scroll an inner ScrollView
                    // into view when it implicitly gains focus (like plasma-pa config dialog has).
                    } else if (yPos + Math.min(padding, item.height) > flickable.contentY + flickable.height) {
                        flickable.contentY = Math.min(flickable.contentHeight - flickable.height,
                                                    yPos - flickable.height + item.height + padding);
                    }
                }
                Flickable {
                    id: pageFlickable
                    anchors {
                        fill: parent
                        margins: Kirigami.Units.smallSpacing
                    }
                    contentHeight: pageColumn.height
                    contentWidth: width
                    ColumnLayout {
                        id: pageColumn
                        spacing: Kirigami.Units.gridUnit / 2
                        width: pageFlickable.width
                        height: Math.max(implicitHeight, pageFlickable.height)

                        Kirigami.Heading {
                            id: pageTitle
                            Layout.fillWidth: true
                            level: 1
                            text: pageStack.title
                        }

                        QtControls.StackView {
                            id: pageStack
                            property string title: ""
                            property bool invertAnimations: false

                            Layout.fillWidth: true
                            Layout.fillHeight: true
                            implicitWidth: Math.max(currentItem ? Math.max(currentItem.Layout.minimumWidth, currentItem.Layout.preferredWidth, currentItem.implicitWidth) : 0, Kirigami.Units.gridUnit * 15)
                            implicitHeight: Math.max(currentItem ? Math.max(currentItem.Layout.minimumHeight, currentItem.Layout.preferredHeight, currentItem.implicitHeight) : 0, Kirigami.Units.gridUnit * 15)

                            property string sourceFile

                            onSourceFileChanged: {
                                if (!sourceFile) {
                                    return;
                                }

                                //in a StackView pages need to be initialized with stackviews size, or have none
                                var props = {"width": width, "height": height}

                                var plasmoidConfig = plasmoid.configuration
                                for (var key of plasmoidConfig.keys()) {
                                    props["cfg_" + key] = plasmoid.configuration[key]
                                }

                                var newItem = depth == 0 ? push(Qt.resolvedUrl(sourceFile), props) : replace(Qt.resolvedUrl(sourceFile), props)

                                for (var key of plasmoidConfig.keys()) {
                                    var changedSignal = newItem["cfg_" + key + "Changed"]
                                    if (changedSignal) {
                                        changedSignal.connect(root.settingValueChanged)
                                    }
                                }

                                var configurationChangedSignal = newItem.configurationChanged
                                if (configurationChangedSignal) {
                                    configurationChangedSignal.connect(root.settingValueChanged)
                                }

                                var unsavedChangesChangedSignal = newItem.unsavedChangesChanged
                                if (unsavedChangesChangedSignal) {
                                    unsavedChangesChangedSignal.connect( () => {
                                        if (newItem.unsavedChanges) {
                                            root.settingValueChanged()
                                        }
                                    })
                                }

                                scroll.flickableItem.contentY = 0

                                /*
                                for (var prop in currentItem) {
                                    if (prop.indexOf("cfg_") === 0) {
                                        currentItem[prop+"Changed"].connect(root.pageChanged)
                                    }
                                }*/
                            }

                            replaceEnter: Transition {
                                ParallelAnimation {
                                    //OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)
                                    NumberAnimation {
                                        property: "opacity"
                                        from: 0.5
                                        to: 1
                                        duration: Kirigami.Units.longDuration
                                        easing.type: Easing.InOutQuad
                                    }
                                    XAnimator {
                                        from: pageStack.invertAnimations ? -scroll.width/3: scroll.width/3
                                        to: 0
                                        duration: Kirigami.Units.longDuration
                                        easing.type: Easing.InOutQuad
                                    }
                                }
                            }
                            replaceExit: Transition {
                                ParallelAnimation {
                                    OpacityAnimator {
                                        from: 1
                                        to: 0
                                        duration: Kirigami.Units.longDuration
                                        easing.type: Easing.InOutQuad
                                    }
                                    XAnimator {
                                        from: 0
                                        to: pageStack.invertAnimations ? scroll.width/3 : -scroll.width/3
                                        duration: Kirigami.Units.longDuration
                                        easing.type: Easing.InOutQuad
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Rectangle {
                id: separator
                Layout.fillWidth: true
                Layout.preferredHeight: 1
                color: Kirigami.Theme.highlightColor
                visible: categoriesScroll.visible
                Behavior on color {
                    ColorAnimation {
                        duration: Kirigami.Units.longDuration
                        easing.type: Easing.InOutQuad
                    }
                }
            }

            QtControls.ScrollView {
                id: categoriesScroll

                Layout.fillWidth: true
                Layout.preferredHeight: categories.implicitHeight

                visible: (configDialog.configModel ? configDialog.configModel.count : 0) + globalConfigModel.count > 1

                Keys.onLeftPressed: {
                    var buttons = categories.children

                    var foundPrevious = false
                    for (var i = buttons.length - 1; i >= 0; --i) {
                        var button = buttons[i];
                        if (!button.hasOwnProperty("current")) {
                            // not a ConfigCategoryDelegate
                            continue;
                        }

                        if (foundPrevious) {
                            button.openCategory()
                            return
                        } else if (button.current) {
                            foundPrevious = true
                        }
                    }
                }

                Keys.onRightPressed: {
                    var buttons = categories.children

                    var foundNext = false
                    for (var i = 0, length = buttons.length; i < length; ++i) {
                        var button = buttons[i];
                        console.log(button)
                        if (!button.hasOwnProperty("current")) {
                            continue;
                        }

                        if (foundNext) {
                            button.openCategory()
                            return
                        } else if (button.current) {
                            foundNext = true
                        }
                    }
                }

                RowLayout {
                    id: categories
                    spacing: 0
                    width: categoriesScroll.width
                    height: implicitHeight

                    property Item currentItem: children[1]

                    Repeater {
                        model: root.isContainment ? globalConfigModel : undefined
                        delegate: ConfigCategoryDelegate {}
                    }
                    Repeater {
                        model: configDialogFilterModel
                        delegate: ConfigCategoryDelegate {}
                    }
                    Repeater {
                        model: !root.isContainment ? globalConfigModel : undefined
                        delegate: ConfigCategoryDelegate {}
                    }
                }
            }

        }
    }
//END UI components
}
