<commit_before># Copyright (c) 2017 <NAME>.
# Cura is released under the terms of the AGPLv3 or higher.

from UM.Logger import Logger

from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry

from .GlobalStack import GlobalStack
from .ExtruderStack import ExtruderStack
from typing import Optional


##  Contains helper functions to create new machines.
class CuraStackBuilder:
    ##  Create a new instance of a machine.
    #
    #   \param name The name of the new machine.
    #   \param definition_id The ID of the machine definition to use.
    #
    #   \return The new global stack or None if an error occurred.
    @classmethod
    def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]:
        registry = ContainerRegistry.getInstance()
        definitions = registry.findDefinitionContainers(id = definition_id)
        if not definitions:
            Logger.log("w", "Definition {definition} was not found!", definition = definition_id)
            return None

        machine_definition = definitions[0]
        name = registry.createUniqueName("machine", "", name, machine_definition.name)
        # Make sure the new name does not collide with any definition or (quality) profile
        # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
        # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
        if registry.findContainers(id = name):
            name = registry.uniqueName(name)

        new_global_stack = cls.createGlobalStack(
            new_stack_id = name,
            definition = machine_definition,
            quality = "default",
            material = "default",
            variant = "default",
        )

        for extruder_definition in registry.findDefinitionContainers(machine = machine_definition.id):
            position = extruder_definition.getMetaDataEntry("position", None)
            if not position:
                Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.id)

            new_extruder_id = registry.uniqueName(extruder_definition.id)
            new_extruder = cls.createExtruderStack(
                new_extruder_id,
                definition = extruder_definition,
                machine_definition = machine_definition,
                quality = "default",
                material = "default",
                variant = "default",
                next_stack = new_global_stack
            )

        return new_global_stack

    ##  Create a new Extruder stack
    #
    #   \param new_stack_id The ID of the new stack.
    #   \param definition The definition to base the new stack on.
    #   \param machine_definition The machine definition to use for the user container.
    #   \param kwargs You can add keyword arguments to specify IDs of containers to use for a specific type, for example "variant": "0.4mm"
    #
    #   \return A new Global stack instance with the specified parameters.
    @classmethod
    def createExtruderStack(cls, new_stack_id: str, definition: DefinitionContainer, machine_definition: DefinitionContainer, **kwargs) -> ExtruderStack:
        stack = ExtruderStack(new_stack_id)
        stack.setName(definition.getName())
        stack.setDefinition(definition)
        stack.addMetaDataEntry("position", definition.getMetaDataEntry("position"))

        user_container = InstanceContainer(new_stack_id + "_user")
        user_container.addMetaDataEntry("type", "user")
        user_container.addMetaDataEntry("extruder", new_stack_id)
        from cura.CuraApplication import CuraApplication
        user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
        user_container.setDefinition(machine_definition)

        stack.setUserChanges(user_container)

        if "next_stack" in kwargs:
            stack.setNextStack(kwargs["next_stack"])

        # Important! The order here matters, because that allows the stack to
        # assume the material and variant have already been set.
        if "definition_changes" in kwargs:
            stack.setDefinitionChangesById(kwargs["definition_changes"])
        else:
            stack.setDefinitionChanges(cls._createDefinitionChangesContainer(stack, new_stack_id + "_settings"))

        if "variant" in kwargs:<commit_msg>Set the next stack before adding the user container<commit_after># Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from UM.Logger import Logger

from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry

from .GlobalStack import GlobalStack
from .ExtruderStack import ExtruderStack
from typing import Optional


##  Contains helper functions to create new machines.
class CuraStackBuilder:
    ##  Create a new instance of a machine.
    #
    #   \param name The name of the new machine.
    #   \param definition_id The ID of the machine definition to use.
    #
    #   \return The new global stack or None if an error occurred.
    @classmethod
    def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]:
        registry = ContainerRegistry.getInstance()
        definitions = registry.findDefinitionContainers(id = definition_id)
        if not definitions:
            Logger.log("w", "Definition {definition} was not found!", definition = definition_id)
            return None

        machine_definition = definitions[0]
        name = registry.createUniqueName("machine", "", name, machine_definition.name)
        # Make sure the new name does not collide with any definition or (quality) profile
        # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
        # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
        if registry.findContainers(id = name):
            name = registry.uniqueName(name)

        new_global_stack = cls.createGlobalStack(
            new_stack_id = name,
            definition = machine_definition,
            quality = "default",
            material = "default",
            variant = "default",
        )

        for extruder_definition in registry.findDefinitionContainers(machine = machine_definition.id):
            position = extruder_definition.getMetaDataEntry("position", None)
            if not position:
                Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.id)

            new_extruder_id = registry.uniqueName(extruder_definition.id)
            new_extruder = cls.createExtruderStack(
                new_extruder_id,
                definition = extruder_definition,
                machine_definition = machine_definition,
                quality = "default",
                material = "default",
                variant = "default",
                next_stack = new_global_stack
            )

        return new_global_stack

    ##  Create a new Extruder stack
    #
    #   \param new_stack_id The ID of the new stack.
    #   \param definition The definition to base the new stack on.
    #   \param machine_definition The machine definition to use for the user container.
    #   \param kwargs You can add keyword arguments to specify IDs of containers to use for a specific type, for example "variant": "0.4mm"
    #
    #   \return A new Global stack instance with the specified parameters.
    @classmethod
    def createExtruderStack(cls, new_stack_id: str, definition: DefinitionContainer, machine_definition: DefinitionContainer, **kwargs) -> ExtruderStack:
        stack = ExtruderStack(new_stack_id)
        stack.setName(definition.getName())
        stack.setDefinition(definition)
        stack.addMetaDataEntry("position", definition.getMetaDataEntry("position"))
        if "next_stack" in kwargs: #Add stacks before containers are added, since they may trigger a setting update.
            stack.setNextStack(kwargs["next_stack"])

        user_container = InstanceContainer(new_stack_id + "_user")
        user_container.addMetaDataEntry("type", "user")
        user_container.addMetaDataEntry("extruder", new_stack_id)
        from cura.CuraApplication import CuraApplication
        user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
        user_container.setDefinition(machine_definition)

        stack.setUserChanges(user_container)

        # Important! The order here matters, because that allows the stack to
        # assume the material and variant have already been set.
        if "definition_changes" in kwargs:
            stack.setDefinitionChangesById(kwargs["definition_changes"])
        else:
            stack.setDefinitionChanges(cls._createDefinitionChangesContainer(stack, new_stack_id + "_settings"))

        if "variant" in kwargs:
{'fraction_non_alphanumeric': 0.06940200785683108, 'fraction_numerical': 0.001745962461807071, 'mean_word_length': 2.9675324675324677, 'pattern_counts': {'":': 2, '<': 4, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2210509', 'n_tokens_mistral': 2299, 'n_tokens_neox': 2236, 'n_words': 737}