from adfotg.amitools.fs.block.Block import *
import adfotg.amitools.fs.DosType as DosType


class FSHeaderDeviceNode:
    valid_flags = (
        "type",
        "task",
        "lock",
        "handler",
        "stack_size",
        "priority",
        "startup",
        "seg_list_blk",
        "global_vec",
    )

    def __init__(
        self,
        type=0,
        task=0,
        lock=0,
        handler=0,
        stack_size=0,
        priority=0,
        startup=0,
        seg_list_blk=0,
        global_vec=0,
    ):
        self.type = type
        self.task = task
        self.lock = lock
        self.handler = handler
        self.stack_size = stack_size
        self.priority = priority
        self.startup = startup
        self.seg_list_blk = seg_list_blk
        self.global_vec = global_vec

    def dump(self):
        print("DeviceNode")
        print(" type:           0x%08x" % self.type)
        print(" task:           0x%08x" % self.task)
        print(" lock:           0x%08x" % self.lock)
        print(" handler:        0x%08x" % self.handler)
        print(" stack_size:     0x%08x" % self.stack_size)
        print(" seg_list_blk:   0x%08x" % self.seg_list_blk)
        print(" global_vec:     0x%08x" % self.global_vec)

    def get_flags(self, patch_flags=0x1FF):
        res = []
        if patch_flags & 0x01 == 0x01:
            res.append(("type", self.type))
        if patch_flags & 0x02 == 0x02:
            res.append(("task", self.task))
        if patch_flags & 0x04 == 0x04:
            res.append(("lock", self.lock))
        if patch_flags & 0x08 == 0x08:
            res.append(("handler", self.handler))
        if patch_flags & 0x10 == 0x10:
            res.append(("stack_size", self.stack_size))
        if patch_flags & 0x20 == 0x20:
            res.append(("priority", self.priority))
        if patch_flags & 0x40 == 0x40:
            res.append(("startup", self.startup))
        if patch_flags & 0x80 == 0x80:
            res.append(("seg_list_blk", self.seg_list_blk))
        if patch_flags & 0x100 == 0x100:
            res.append(("global_vec", self.global_vec))
        return res

    def set_flags(self, flags):
        mask = 0
        for f in flags:
            key = f[0]
            val = int(f[1])
            if key == "type":
                self.type = val
                mask |= 0x01
            elif key == "task":
                self.task = val
                mask |= 0x02
            elif key == "lock":
                self.lock = val
                mask |= 0x04
            elif key == "handler":
                self.handler = val
                mask |= 0x08
            elif key == "stack_size":
                self.stack_size = val
                mask |= 0x10
            elif key == "priority":
                self.priority = val
                mask |= 0x20
            elif key == "startup":
                self.startup = val
                mask |= 0x40
            elif key == "seg_list_blk":
                self.seg_list_blk = val
                mask |= 0x80
            elif key == "global_vec":
                self.global_vec = val
                mask |= 0x100
            else:
                raise ValueError("Invalid flag: " + key)
        return mask

    def get_valid_flag_names(self):
        return (
            "type",
            "task",
            "lock",
            "handler",
            "stack_size",
            "priority",
            "startup",
            "seg_list_blk",
            "global_vec",
        )

    def read(self, blk):
        self.type = blk._get_long(11)
        self.task = blk._get_long(12)
        self.lock = blk._get_long(13)
        self.handler = blk._get_long(14)
        self.stack_size = blk._get_long(15)
        self.priority = blk._get_long(16)
        self.startup = blk._get_long(17)
        self.seg_list_blk = blk._get_long(18)
        self.global_vec = blk._get_long(19)

    def write(self, blk):
        blk._put_long(11, self.type)
        blk._put_long(12, self.task)
        blk._put_long(13, self.lock)
        blk._put_long(14, self.handler)
        blk._put_long(15, self.stack_size)
        blk._put_long(16, self.priority)
        blk._put_long(17, self.startup)
        blk._put_long(18, self.seg_list_blk)
        blk._put_long(19, self.global_vec)

    def clear_flags(self):
        self.ftype = 0
        self.task = 0
        self.lock = 0
        self.handler = 0
        self.stack_size = 0
        self.priority = 0
        self.startup = 0


class FSHeaderBlock(Block):
    def __init__(self, blkdev, blk_num):
        Block.__init__(self, blkdev, blk_num, chk_loc=2, is_type=Block.FSHD)

    def create(
        self,
        host_id=0,
        next=Block.no_blk,
        flags=0,
        dos_type=0,
        version=0,
        patch_flags=0,
        size=64,
        dev_node=None,
    ):
        Block.create(self)
        self.size = size
        self.host_id = host_id
        self.next = next
        self.flags = flags

        self.dos_type = dos_type
        self.version = version
        self.patch_flags = patch_flags

        if dev_node == None:
            dev_node = FSHeaderDeviceNode()
        self.dev_node = dev_node

    def write(self):
        self._create_data()

        self._put_long(1, self.size)
        self._put_long(3, self.host_id)
        self._put_long(4, self.next)
        self._put_long(5, self.flags)

        self._put_long(8, self.dos_type)
        self._put_long(9, self.version)
        self._put_long(10, self.patch_flags)

        self.dev_node.write(self)

        Block.write(self)

    def read(self):
        Block.read(self)
        if not self.valid:
            return False

        self.size = self._get_long(1)
        self.host_id = self._get_long(3)
        self.next = self._get_long(4)
        self.flags = self._get_long(5)

        self.dos_type = self._get_long(8)
        self.version = self._get_long(9)
        self.patch_flags = self._get_long(10)

        self.dev_node = FSHeaderDeviceNode()
        self.dev_node.read(self)

        return self.valid

    def get_version_tuple(self):
        return ((self.version >> 16), (self.version & 0xFFFF))

    def get_version_string(self):
        return "%d.%d" % self.get_version_tuple()

    def get_flags(self):
        return self.dev_node.get_flags(self.patch_flags)

    def get_valid_flag_names(self):
        return self.dev_node.get_valid_flag_names()

    def get_dev_node(self):
        return self.dev_node

    def dump(self):
        Block.dump(self, "FSHeader")

        print(" size:           %d" % self.size)
        print(" host_id:        %d" % self.host_id)
        print(" next:           %s" % self._dump_ptr(self.next))
        print(" flags:          0x%08x" % self.flags)
        print(
            " dos_type:       0x%08x = %s"
            % (self.dos_type, DosType.num_to_tag_str(self.dos_type))
        )
        print(
            " version:        0x%08x = %s" % (self.version, self.get_version_string())
        )
        print(" patch_flags:    0x%08x" % self.patch_flags)

        self.dev_node.dump()

    def set_flags(self, flags):
        mask = self.dev_node.set_flags(flags)
        self.patch_flags |= mask

    def set_flag(self, key, value):
        mask = self.dev_node.set_flags([(key, value)])
        self.patch_flags |= mask

    def clear_flags(self):
        self.patch_flags = 0x180
        self.dev_node.clear_flags()
