from ironflow.node_tools import (
    dtypes,
    Node,
    NodeInputBP,
    NodeOutputBP,
    PlaceholderWidgetsContainer,
)

widgets = PlaceholderWidgetsContainer()


class NodeBase(Node):
    pass


class GetVar_Node(NodeBase):
    """Gets the value of a script variable"""

    version = "v0.1"

    title = "get var"
    init_inputs = [
        NodeInputBP(dtype=dtypes.String()),
    ]
    init_outputs = [NodeOutputBP(label="val")]
    color = "#c69a15"

    def __init__(self, params):
        super().__init__(params)

        self.var_name = ""
        self.temp_var_val = None

    def place_event(self):
        self.update()

    def view_place_event(self):
        self.var_name = self.input(0)

    def update_event(self, input_called=-1):
        if self.input(0) != self.var_name:
            if self.var_name != "":  # disconnect old var val update connection
                self.unregister_var_receiver(self.var_name, self.var_val_changed)

            self.var_name = self.input(0)

            # create new var update connection
            self.register_var_receiver(self.var_name, self.var_val_changed)

        self.set_output_val(0, self.get_var_val(self.var_name))

    def var_val_changed(self, name, val):
        self.set_output_val(0, val)


class Result_Node(NodeBase):
    """Simply shows a value converted to str"""

    version = "v0.1"

    title = "result"
    init_inputs = [
        NodeInputBP(type_="data"),
    ]
    main_widget_class = widgets.Result_Node_MainWidget
    main_widget_pos = "between ports"
    color = "#c69a15"

    def __init__(self, params):
        super().__init__(params)
        self.val = None

    def place_event(self):
        self.update()

    def view_place_event(self):
        self.main_widget().show_val(self.val)

    def update_event(self, input_called=-1):
        self.val = self.input(0)
        if self.session.gui:
            self.main_widget().show_val(self.val)


class Val_Node(NodeBase):
    """Evaluates a string from the input field"""

    version = "v0.1"

    title = "val"
    init_inputs = [
        NodeInputBP(dtype=dtypes.Data(size="s")),
    ]
    init_outputs = [
        NodeOutputBP(type_="data"),
    ]
    style = "small"
    color = "#c69a15"

    def __init__(self, params):
        super().__init__(params)

        self.display_title = ""
        self.actions["edit val via dialog"] = {"method": self.action_edit_via_dialog}
        self.val = None

    def place_event(self):
        self.update()

    def update_event(self, input_called=-1):
        self.val = self.input(0)
        self.set_output_val(0, self.val)

    def action_edit_via_dialog(self):
        return

        # from ..EditVal_Dialog import EditVal_Dialog
        #
        # val_dialog = EditVal_Dialog(parent=None, init_val=self.val)
        # accepted = val_dialog.exec_()
        # if accepted:
        #     self.main_widget().setText(str(val_dialog.get_val()))
        #     self.update()

    def get_current_var_name(self):
        return self.input(0)

    def get_state(self):
        return {"val": self.val}  # self.main_widget().get_val()

    def set_state(self, data, version):
        self.val = data["val"]

        if version is None:
            self.display_title = ""

            self.create_input_dt(dtype=dtypes.Data(size="s"))

            # the old version didn't use a dtype
            self.inputs[0].dtype.val = self.val
            self.inputs[0].update(self.val)


class SetVar_Node(NodeBase):
    """Sets the value of a script variable"""

    version = "v0.1"

    title = "set var"
    init_inputs = [
        NodeInputBP(type_="exec"),
        NodeInputBP(dtype=dtypes.String(), label="var"),
        NodeInputBP(dtype=dtypes.Data(size="s"), label="val"),
    ]
    init_outputs = [
        NodeOutputBP(type_="exec"),
        NodeOutputBP(type_="data", label="val"),
    ]
    style = "normal"
    color = "#c69a15"

    def __init__(self, params):
        super().__init__(params)

        self.actions["make passive"] = {"method": self.action_make_passive}
        self.active = True

        self.var_name = ""
        self.num_vars = 1

    def update_event(self, input_called=-1):
        if self.active and input_called == 0:
            if self.set_var_val(self.input(1), self.input(2)):
                self.set_output_val(1, self.input(2))
            self.exec_output(0)

        elif not self.active:
            self.var_name = self.input(0)
            if self.set_var_val(self.input(0), self.input(1)):
                self.set_output_val(0, self.get_var_val(self.var_name))

    def action_make_passive(self):
        self.active = False
        self.delete_input(0)
        self.delete_output(0)
        del self.actions["make passive"]
        self.actions["make active"] = {"method": self.action_make_active}

    def action_make_active(self):
        self.active = True
        self.create_input(type_="exec", pos=0)
        self.create_output(type_="exec", pos=0)
        del self.actions["make active"]
        self.actions["make passive"] = {"method": self.action_make_passive}

    def get_state(self):
        return {"active": self.active}

    def set_state(self, data, version):
        self.active = data["active"]


class SetVarsPassive_Node(NodeBase):
    """Sets the values of multiple script variables"""

    version = "v0.1"

    title = "set vars passive"
    init_inputs = []
    init_outputs = []
    style = "normal"
    color = "#c69a15"

    def __init__(self, params):
        super().__init__(params)

        self.actions["add var input"] = {"method": self.add_var_input}

        self.num_vars = 0

    def place_event(self):
        if self.num_vars == 0:
            self.add_var_input()

    def add_var_input(self):
        self.create_input_dt(label="var", dtype=dtypes.String(size="l"))
        self.create_input_dt(label="val", dtype=dtypes.Data(size="l"))
        self.num_vars += 1

        self.actions[f"remove var {self.num_vars}"] = {
            "method": self.remove_var_input,
            "data": self.num_vars,
        }

    def remove_var_input(self, number):
        self.delete_input((number - 1) * 2)
        self.delete_input((number - 1) * 2)
        self.num_vars -= 1
        self.rebuild_remove_actions()

    def rebuild_remove_actions(self):
        remove_keys = []
        for k, v in self.actions.items():
            if k.startswith("remove var"):
                remove_keys.append(k)

        for k in remove_keys:
            del self.actions[k]

        for i in range(self.num_vars):
            self.actions[f"remove var {i+1}"] = {
                "method": self.remove_var_input,
                "data": i + 1,
            }

    def update_event(self, input_called=-1):
        var_names = [self.input(i) for i in range(0, len(self.inputs), 2)]
        values = [self.input(i) for i in range(1, len(self.inputs), 2)]

        for i in range(len(var_names)):
            self.set_var_val(var_names[i], values[i])

    def get_state(self):
        return {"num vars": self.num_vars}

    def set_state(self, data, version):
        self.num_vars = data["num vars"]
