// Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V.
// The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Controls.Styles 1.1
import QtQml.Models 2.15 as Models
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Window 2.2

import UM 1.2 as UM
import Cura 1.0 as Cura

UM.Dialog
{
    id: dialog

    title: catalog.i18nc("@title:window", "Post Processing Plugin")
    width: 700 * screenScaleFactor;
    height: 500 * screenScaleFactor;
    minimumWidth: 400 * screenScaleFactor;
    minimumHeight: 250 * screenScaleFactor;

    onVisibleChanged:
    {
        if(!visible) //Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack.
        {
            manager.writeScriptsToStack()
        }
    }

    Item
    {
        UM.I18nCatalog{id: catalog; name: "cura"}
        id: base
        property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width)
        property int textMargin: Math.round(UM.Theme.getSize("default_margin").width / 2)
        property string activeScriptName
        SystemPalette{ id: palette }
        SystemPalette{ id: disabledPalette; colorGroup: SystemPalette.Disabled }
        anchors.fill: parent

        ExclusiveGroup
        {
            id: selectedScriptGroup
        }
        Item
        {
            id: activeScripts
            anchors.left: parent.left
            width: base.columnWidth
            height: parent.height

            Label
            {
                id: activeScriptsHeader
                text: catalog.i18nc("@label", "Post Processing Scripts")
                anchors.top: parent.top
                anchors.topMargin: base.textMargin
                anchors.left: parent.left
                anchors.leftMargin: base.textMargin
                anchors.right: parent.right
                anchors.rightMargin: base.textMargin
                font: UM.Theme.getFont("large_bold")
                elide: Text.ElideRight
            }
            ListView
            {
                id: activeScriptsList

                anchors
                {
                    top: activeScriptsHeader.bottom
                    left: parent.left
                    right: parent.right
                    rightMargin: base.textMargin
                    topMargin: base.textMargin
                    leftMargin: UM.Theme.getSize("default_margin").width
                }

                height: childrenRect.height
                model: manager.scriptList
                delegate: Item
                {
                    width: parent.width
                    height: activeScriptButton.height
                    Button
                    {
                        id: activeScriptButton
                        text: manager.getScriptLabelByKey(modelData.toString())
                        exclusiveGroup: selectedScriptGroup
                        width: parent.width
                        height: UM.Theme.getSize("setting").height
                        checkable: true

                        checked:
                        {
                            if (manager.selectedScriptIndex == index)
                            {
                                base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
                                return true
                            }
                            else
                            {
                                return false
                            }
                        }
                        onClicked:
                        {
                            forceActiveFocus()
                            manager.setSelectedScriptIndex(index)
                            base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
                        }

                        style: ButtonStyle
                        {
                            background: Rectangle
                            {
                                color: activeScriptButton.checked ? palette.highlight : "transparent"
                                width: parent.width
                                height: parent.height
                            }
                            label: Label
                            {
                                wrapMode: Text.Wrap
                                text: control.text
                                elide: Text.ElideRight
                                color: activeScriptButton.checked ? palette.highlightedText : palette.text
                            }
                        }
                    }

                    Button
                    {
                        id: removeButton
                        text: "x"
                        width: 20 * screenScaleFactor
                        height: 20 * screenScaleFactor
                        anchors.right:parent.right
                        anchors.rightMargin: base.textMargin
                        anchors.verticalCenter: parent.verticalCenter
                        onClicked: manager.removeScriptByIndex(index)
                        style: ButtonStyle
                        {
                            label: Item
                            {
                                UM.RecolorImage
                                {
                                    anchors.verticalCenter: parent.verticalCenter
                                    anchors.horizontalCenter: parent.horizontalCenter
                                    width: Math.round(control.width / 2.7)
                                    height: Math.round(control.height / 2.7)
                                    sourceSize.height: width
                                    color: palette.text
                                    source: UM.Theme.getIcon("Cancel")
                                }
                            }
                        }
                    }
                    Button
                    {
                        id: downButton
                        text: ""
                        anchors.right: removeButton.left
                        anchors.verticalCenter: parent.verticalCenter
                        enabled: index != manager.scriptList.length - 1
                        width: 20 * screenScaleFactor
                        height: 20 * screenScaleFactor
                        onClicked:
                        {
                            if (manager.selectedScriptIndex == index)
                            {
                                manager.setSelectedScriptIndex(index + 1)
                            }
                            return manager.moveScript(index, index + 1)
                        }
                        style: ButtonStyle
                        {
                            label: Item
                            {
                                UM.RecolorImage
                                {
                                    anchors.verticalCenter: parent.verticalCenter
                                    anchors.horizontalCenter: parent.horizontalCenter
                                    width: Math.round(control.width / 2.5)
                                    height: Math.round(control.height / 2.5)
                                    sourceSize.height: width
                                    color: control.enabled ? palette.text : disabledPalette.text
                                    source: UM.Theme.getIcon("ChevronSingleDown")
                                }
                            }
                        }
                    }
                    Button
                    {
                        id: upButton
                        text: ""
                        enabled: index != 0
                        width: 20 * screenScaleFactor
                        height: 20 * screenScaleFactor
                        anchors.right: downButton.left
                        anchors.verticalCenter: parent.verticalCenter
                        onClicked:
                        {
                            if (manager.selectedScriptIndex == index)
                            {
                                manager.setSelectedScriptIndex(index - 1)
                            }
                            return manager.moveScript(index, index - 1)
                        }
                        style: ButtonStyle
                        {
                            label: Item
                             {
                                UM.RecolorImage
                                {
                                    anchors.verticalCenter: parent.verticalCenter
                                    anchors.horizontalCenter: parent.horizontalCenter
                                    width: Math.round(control.width / 2.5)
                                    height: Math.round(control.height / 2.5)
                                    sourceSize.height: width
                                    color: control.enabled ? palette.text : disabledPalette.text
                                    source: UM.Theme.getIcon("ChevronSingleUp")
                                }
                            }
                        }
                    }
                }
            }
            Button
            {
                id: addButton
                text: catalog.i18nc("@action", "Add a script")
                anchors.left: parent.left
                anchors.leftMargin: base.textMargin
                anchors.top: activeScriptsList.bottom
                anchors.topMargin: base.textMargin
                onClicked: scriptsMenu.open()
                style: ButtonStyle
                {
                    label: Label
                    {
                        text: control.text
                    }
                }
            }
            QQC2.Menu
            {
                id: scriptsMenu
                width: parent.width

                Models.Instantiator
                {
                    model: manager.loadedScriptList

                    QQC2.MenuItem
                    {
                        text: manager.getScriptLabelByKey(modelData.toString())
                        onTriggered: manager.addScriptToList(modelData.toString())
                    }

                    onObjectAdded: scriptsMenu.insertItem(index, object)
                    onObjectRemoved: scriptsMenu.removeItem(object)
                }
            }
        }

        Rectangle
        {
            color: UM.Theme.getColor("main_background")
            anchors.left: activeScripts.right
            anchors.leftMargin: UM.Theme.getSize("default_margin").width
            anchors.right: parent.right
            height: parent.height
            id: settingsPanel

            Label
            {
                id: scriptSpecsHeader
                text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName
                anchors
                {
                    top: parent.top
                    topMargin: base.textMargin
                    left: parent.left
                    leftMargin: base.textMargin
                    right: parent.right
                    rightMargin: base.textMargin
                }

                elide: Text.ElideRight
                height: 20 * screenScaleFactor
                font: UM.Theme.getFont("large_bold")
                color: UM.Theme.getColor("text")
            }

            ScrollView
            {
                id: scrollView
                anchors
                {
                    top: scriptSpecsHeader.bottom
                    topMargin: settingsPanel.textMargin
                    left: parent.left
                    leftMargin: UM.Theme.getSize("default_margin").width
                    right: parent.right
                    bottom: parent.bottom
                }

                visible: manager.selectedScriptDefinitionId != ""
                style: UM.Theme.styles.scrollview;

                ListView
                {
                    id: listview
                    spacing: UM.Theme.getSize("default_lining").height
                    model: UM.SettingDefinitionsModel
                    {
                        id: definitionsModel
                        containerId: manager.selectedScriptDefinitionId
                        showAll: true
                    }

                    delegate: Loader
                    {
                        id: settingLoader

                        width: parent.width
                        height:
                        {
                            if(provider.properties.enabled == "True")
                            {
                                if(model.type != undefined)
                                {
                                    return UM.Theme.getSize("section").height
                                }
                                else
                                {
                                    return 0
                                }
                            }
                            else
                            {
                                return 0
                            }
                        }
                        Behavior on height { NumberAnimation { duration: 100 } }
                        opacity: provider.properties.enabled == "True" ? 1 : 0

                        Behavior on opacity { NumberAnimation { duration: 100 } }
                        enabled: opacity > 0

                        property var definition: model
                        property var settingDefinitionsModel: definitionsModel
                        property var propertyProvider: provider
                        property var globalPropertyProvider: inheritStackProvider

                        //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
                        //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
                        //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
                        asynchronous: model.type != "enum" && model.type != "extruder"

                        onLoaded:
                        {
                            settingLoader.item.showRevertButton = false
                            settingLoader.item.showInheritButton = false
                            settingLoader.item.showLinkedSettingIcon = false
                            settingLoader.item.doDepthIndentation = false
                            settingLoader.item.doQualityUserSettingEmphasis = false
                        }

                        sourceComponent:
                        {
                            switch(model.type)
                            {
                                case "int":
                                    return settingTextField
                                case "float":
                                    return settingTextField
                                case "enum":
                                    return settingComboBox
                                case "extruder":
                                    return settingExtruder
                                case "bool":
                                    return settingCheckBox
                                case "str":
                                    return settingTextField
                                case "category":
                                    return settingCategory
                                default:
                                    return settingUnknown
                            }
                        }

                        UM.SettingPropertyProvider
                        {
                            id: provider
                            containerStackId: manager.selectedScriptStackId
                            key: model.key ? model.key : "None"
                            watchedProperties: [ "value", "enabled", "state", "validationState" ]
                            storeIndex: 0
                        }

                        // Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
                        // so we bypass that to make a dedicated provider).
                        UM.SettingPropertyProvider
                        {
                            id: inheritStackProvider
                            containerStack: Cura.MachineManager.activeMachine
                            key: model.key ? model.key : "None"
                            watchedProperties: [ "limit_to_extruder" ]
                        }

                        Connections
                        {
                            target: item

                            function onShowTooltip(text)
                            {
                                tooltip.text = text
                                var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0)
                                tooltip.show(position)
                                tooltip.target.x = position.x + 1
                            }

                            function onHideTooltip() { tooltip.hide() }
                        }
                    }
                }
            }
        }

        Cura.PrintSetupTooltip
        {
            id: tooltip
        }

        Component
        {
            id: settingTextField;

            Cura.SettingTextField { }
        }

        Component
        {
            id: settingComboBox;

            Cura.SettingComboBox { }
        }

        Component
        {
            id: settingExtruder;

            Cura.SettingExtruder { }
        }

        Component
        {
            id: settingCheckBox;

            Cura.SettingCheckBox { }
        }

        Component
        {
            id: settingCategory;

            Cura.SettingCategory { }
        }

        Component
        {
            id: settingUnknown;

            Cura.SettingUnknown { }
        }
    }

    rightButtons: Button
    {
        text: catalog.i18nc("@action:button", "Close")
        iconName: "dialog-close"
        onClicked: dialog.accept()
    }

    Item
    {
        objectName: "postProcessingSaveAreaButton"
        visible: activeScriptsList.count > 0
        height: UM.Theme.getSize("action_button").height
        width: height

        Cura.SecondaryButton
        {
            height: UM.Theme.getSize("action_button").height
            tooltip:
            {
                var tipText = catalog.i18nc("@info:tooltip", "Change active post-processing scripts.");
                if (activeScriptsList.count > 0)
                {
                    tipText += "<br><br>" + catalog.i18ncp("@info:tooltip",
                        "The following script is active:",
                        "The following scripts are active:",
                        activeScriptsList.count
                    ) + "<ul>";
                    for(var i = 0; i < activeScriptsList.count; i++)
                    {
                        tipText += "<li>" + manager.getScriptLabelByKey(manager.scriptList[i]) + "</li>";
                    }
                    tipText += "</ul>";
                }
                return tipText
            }
            toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft
            onClicked: dialog.show()
            iconSource: "Script.svg"
            fixedWidthMode: false
        }

        Cura.NotificationIcon
        {
            id: activeScriptCountIcon
            visible: activeScriptsList.count > 0
            anchors
            {
                top: parent.top
                right: parent.right
                rightMargin: (-0.5 * width) | 0
                topMargin: (-0.5 * height) | 0
            }

            labelText: activeScriptsList.count
        }
    }
}
