from Core.categories import DefaultCategories
from Core.fields import Int32Field
from Core.io import Input, Output
from Mafi import Fix32
from Core.module import DefaultControllers, Module

# File written by Nightinggale
# Optimized: per-class `_scan(n)` recurses from highest input down, replacing
# the early-return chains.  Input and field name tables are pre-built once
# as class-level lists (slot 0 unused so the natural index maps directly) —
# zero string allocations per tick.

class Runtime_Memory_Selector_1(Module):
    name = "Control: Memory Selector (1 input)"
    description = "When <b>in_1</b> is positive, outputs the value of field <b>field_1</b>; otherwise outputs the <b>default</b> field. Single-input lookup table."
    symbol = "MS"
    inputs = [
        Input("in_1", "Signal input")
    ]
    outputs = [
        Output("output", "Signal output")
    ]

    fields = [
        Int32Field("default", "Default", "Output this when none of the inputs are positive", 0),
        Int32Field("field_1", "1 value", "Output this when input 1 is positive", 1)
    ]

    width = 1

    categories = [ DefaultCategories.Control ]
    controllers = [ DefaultControllers.Controller ]

    INPUT_NAMES = ["", "in_1"]
    FIELD_NAMES = ["", "field_1"]

    def action(self):
        self._scan(1)

    def _scan(self, n):
        if n <= 0:
            self.Output.set("output", self.Field.get("default", Fix32.Zero))
            return
        if self.Input.get_bool(self.INPUT_NAMES[n], False):
            self.Output.set("output", self.Field.get(self.FIELD_NAMES[n], Fix32.Zero))
            return
        self._scan(n - 1)


class Runtime_Memory_Selector_2(Module):
    name = "Control: Memory Selector (2 inputs)"
    description = "Priority lookup: outputs the value of <b>field_2</b> if <b>in_2</b> is positive, else <b>field_1</b> if <b>in_1</b> is positive, else the <b>default</b> field. Higher-numbered inputs win ties."
    symbol = "MS"
    inputs = [
        Input("in_1", "Input 1"),
        Input("in_2", "Input 2")
    ]
    outputs = [
        Output("output", "Signal output")
    ]

    fields = [
        Int32Field("default", "Default", "Output this when none of the inputs are positive", 0),
        Int32Field("field_1", "1 value", "Output this when input 1 is positive", 1),
        Int32Field("field_2", "2 value", "Output this when input 2 is positive", 2)
    ]

    width = 2

    categories = [ DefaultCategories.Control ]
    controllers = [ DefaultControllers.Controller ]

    INPUT_NAMES = ["", "in_1", "in_2"]
    FIELD_NAMES = ["", "field_1", "field_2"]

    def action(self):
        self._scan(2)

    def _scan(self, n):
        if n <= 0:
            self.Output.set("output", self.Field.get("default", Fix32.Zero))
            return
        if self.Input.get_bool(self.INPUT_NAMES[n], False):
            self.Output.set("output", self.Field.get(self.FIELD_NAMES[n], Fix32.Zero))
            return
        self._scan(n - 1)


class Runtime_Memory_Selector_4(Module):
    name = "Control: Memory Selector (4 inputs)"
    description = "Priority lookup: scans inputs <b>in_4</b> down to <b>in_1</b> and outputs the value of the matching <b>field_n</b> for the first positive input; falls back to the <b>default</b> field. Higher-numbered inputs win ties."
    symbol = "MEM SELECT"
    inputs = [
        Input("in_1", "Input 1"),
        Input("in_2", "Input 2"),
        Input("in_3", "Input 3"),
        Input("in_4", "Input 4")
    ]
    outputs = [
        Output("output", "Signal output")
    ]

    fields = [
        Int32Field("default", "Default", "Output this when none of the inputs are positive", 0),
        Int32Field("field_1", "1 value", "Output this when input 1 is positive", 1),
        Int32Field("field_2", "2 value", "Output this when input 2 is positive", 2),
        Int32Field("field_3", "3 value", "Output this when input 3 is positive", 3),
        Int32Field("field_4", "4 value", "Output this when input 4 is positive", 4)
    ]

    width = 4

    categories = [ DefaultCategories.Control ]
    controllers = [ DefaultControllers.Controller ]

    INPUT_NAMES = ["", "in_1", "in_2", "in_3", "in_4"]
    FIELD_NAMES = ["", "field_1", "field_2", "field_3", "field_4"]

    def action(self):
        self._scan(4)

    def _scan(self, n):
        if n <= 0:
            self.Output.set("output", self.Field.get("default", Fix32.Zero))
            return
        if self.Input.get_bool(self.INPUT_NAMES[n], False):
            self.Output.set("output", self.Field.get(self.FIELD_NAMES[n], Fix32.Zero))
            return
        self._scan(n - 1)


class Runtime_Memory_Selector_6(Module):
    name = "Control: Memory Selector (6 inputs)"
    description = "Priority lookup: scans inputs <b>in_6</b> down to <b>in_1</b> and outputs the value of the matching <b>field_n</b> for the first positive input; falls back to the <b>default</b> field. Higher-numbered inputs win ties."
    symbol = "Memory Selector"
    inputs = [
        Input("in_1", "Input 1"),
        Input("in_2", "Input 2"),
        Input("in_3", "Input 3"),
        Input("in_4", "Input 4"),
        Input("in_5", "Input 5"),
        Input("in_6", "Input 6")
    ]
    outputs = [
        Output("output", "Signal output")
    ]

    fields = [
        Int32Field("default", "Default", "Output this when none of the inputs are positive", 0),
        Int32Field("field_1", "1 value", "Output this when input 1 is positive", 1),
        Int32Field("field_2", "2 value", "Output this when input 2 is positive", 2),
        Int32Field("field_3", "3 value", "Output this when input 3 is positive", 3),
        Int32Field("field_4", "4 value", "Output this when input 4 is positive", 4),
        Int32Field("field_5", "5 value", "Output this when input 5 is positive", 5),
        Int32Field("field_6", "6 value", "Output this when input 6 is positive", 6)
    ]

    width = 6

    categories = [ DefaultCategories.Control ]
    controllers = [ DefaultControllers.Controller ]

    INPUT_NAMES = ["", "in_1", "in_2", "in_3", "in_4", "in_5", "in_6"]
    FIELD_NAMES = ["", "field_1", "field_2", "field_3", "field_4", "field_5", "field_6"]

    def action(self):
        self._scan(6)

    def _scan(self, n):
        if n <= 0:
            self.Output.set("output", self.Field.get("default", Fix32.Zero))
            return
        if self.Input.get_bool(self.INPUT_NAMES[n], False):
            self.Output.set("output", self.Field.get(self.FIELD_NAMES[n], Fix32.Zero))
            return
        self._scan(n - 1)


class Runtime_Memory_Selector_8(Module):
    name = "Control: Memory Selector (8 inputs)"
    description = "Priority lookup: scans inputs <b>in_8</b> down to <b>in_1</b> and outputs the value of the matching <b>field_n</b> for the first positive input; falls back to the <b>default</b> field. Higher-numbered inputs win ties."
    symbol = "Memory Selector"
    inputs = [
        Input("in_1", "Input 1"),
        Input("in_2", "Input 2"),
        Input("in_3", "Input 3"),
        Input("in_4", "Input 4"),
        Input("in_5", "Input 5"),
        Input("in_6", "Input 6"),
        Input("in_7", "Input 7"),
        Input("in_8", "Input 8")
    ]
    outputs = [
        Output("output", "Signal output")
    ]

    fields = [
        Int32Field("default", "Default", "Output this when none of the inputs are positive", 0),
        Int32Field("field_1", "1 value", "Output this when input 1 is positive", 1),
        Int32Field("field_2", "2 value", "Output this when input 2 is positive", 2),
        Int32Field("field_3", "3 value", "Output this when input 3 is positive", 3),
        Int32Field("field_4", "4 value", "Output this when input 4 is positive", 4),
        Int32Field("field_5", "5 value", "Output this when input 5 is positive", 5),
        Int32Field("field_6", "6 value", "Output this when input 6 is positive", 6),
        Int32Field("field_7", "7 value", "Output this when input 7 is positive", 7),
        Int32Field("field_8", "8 value", "Output this when input 8 is positive", 8)
    ]

    width = 8

    categories = [ DefaultCategories.Control ]
    controllers = [ DefaultControllers.Controller ]

    INPUT_NAMES = ["", "in_1", "in_2", "in_3", "in_4", "in_5", "in_6", "in_7", "in_8"]
    FIELD_NAMES = ["", "field_1", "field_2", "field_3", "field_4", "field_5", "field_6", "field_7", "field_8"]

    def action(self):
        self._scan(8)

    def _scan(self, n):
        if n <= 0:
            self.Output.set("output", self.Field.get("default", Fix32.Zero))
            return
        if self.Input.get_bool(self.INPUT_NAMES[n], False):
            self.Output.set("output", self.Field.get(self.FIELD_NAMES[n], Fix32.Zero))
            return
        self._scan(n - 1)
