# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty

import cura.ExtruderManager
import UM.Qt.ListModel

##  Model that holds extruders.
#
#   This model is designed for use by any list of extruders, but specifically
#   intended for drop-down lists of the current machine's extruders in place of
#   settings.
class ExtrudersModel(UM.Qt.ListModel.ListModel):
    # The ID of the container stack for the extruder.
    IdRole = Qt.UserRole + 1

    ##  Human-readable name of the extruder.
    NameRole = Qt.UserRole + 2

    ##  Colour of the material loaded in the extruder.
    ColourRole = Qt.UserRole + 3

    ##  Index of the extruder, which is also the value of the setting itself.
    #
    #   An index of 0 indicates the first extruder, an index of 1 the second
    #   one, and so on. This is the value that will be saved in instance
    #   containers.
    IndexRole = Qt.UserRole + 4

    ##  List of colours to display if there is no material or the material has no known
    #   colour.
    defaultColours = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"]

    ##  Initialises the extruders model, defining the roles and listening for
    #   changes in the data.
    #
    #   \param parent Parent QtObject of this list.
    def __init__(self, parent = None):
        super().__init__(parent)

        self.addRoleName(self.IdRole, "id")
        self.addRoleName(self.NameRole, "name")
        self.addRoleName(self.ColourRole, "colour")
        self.addRoleName(self.IndexRole, "index")

        self._add_global = False

        #Listen to changes.
        manager = cura.ExtruderManager.ExtruderManager.getInstance()
        manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general.
        UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes.
        self._updateExtruders()

    def setAddGlobal(self, add):
        if add != self._add_global:
            self._add_global = add
            self._updateExtruders()
            self.addGlobalChanged.emit()

    addGlobalChanged = pyqtSignal()
    @pyqtProperty(bool, fset = setAddGlobal, notify = addGlobalChanged)
    def addGlobal(self):
        return self._add_global

    ##  Update the list of extruders.
    #
    #   This should be called whenever the list of extruders changes.
    def _updateExtruders(self):
        self.clear()
        manager = cura.ExtruderManager.ExtruderManager.getInstance()
        global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
        if not global_container_stack:
            return #There is no machine to get the extruders of.

        if self._add_global:
            material = global_container_stack.findContainer({ "type": "material" })
            colour = material.getMetaDataEntry("color_code", default = self.defaultColours[0]) if material else self.defaultColours[0]
            item = {
                "id": global_container_stack.getId(),
                "name": "Global",
                "colour": colour,
                "index": -1
            }
            self.appendItem(item)

        for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()):
            material = extruder.findContainer({ "type": "material" })
            position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition.
            try:
                position = int(position)
            except ValueError: #Not a proper int.
                position = -1
            default_colour = self.defaultColours[position] if position >= 0 and position < len(self.defaultColours) else defaultColours[0]
            colour = material.getMetaDataEntry("color_code", default = default_colour) if material else default_colour
            item = { #Construct an item with only the relevant information.
                "id": extruder.getId(),
                "name": extruder.getName(),
                "colour": colour,
                "index": position
            }
            self.appendItem(item)

        self.sort(lambda item: item["index"])

@@ -1649,16 +1649,60 @@
  False%0A%0A
+        self._active_extruder_stack = None%0A%0A
         
@@ -1925,16 +1925,30 @@
 ication.
+getInstance().
 globalCo
@@ -2062,24 +2062,142 @@
 xtruders()%0A%0A
+        manager.activeExtruderChanged.connect(self._onActiveExtruderChanged)%0A        self._onActiveExtruderChanged()%0A%0A
     def setA
@@ -2532,16 +2532,853 @@
 global%0A%0A
+    def _onActiveExtruderChanged(self):%0A        manager = cura.ExtruderManager.ExtruderManager.getInstance()%0A        active_extruder_stack = manager.getActiveExtruderStack()%0A        if self._active_extruder_stack != active_extruder_stack:%0A            if self._active_extruder_stack:%0A                self._active_extruder_stack.containersChanged.disconnect(self._onExtruderStackContainersChanged)%0A%0A            if active_extruder_stack:%0A                # Update the model when the material container is changed%0A                active_extruder_stack.containersChanged.connect(self._onExtruderStackContainersChanged)%0A            self._active_extruder_stack = active_extruder_stack%0A%0A%0A    def _onExtruderStackContainersChanged(self, container):%0A        if container.getMetaDataEntry(%22type%22) == %22material%22:%0A            self._updateExtruders()%0A%0A
     ##  

Update extrudermodel when material is changed