from common import Rtos, rtos_class, arm_32_commmon_registers, safe_gdb_lookup_type
from zephyr.Thread import get_zephyr_tasks, get_curr_task
from zephyr.cortex_m import get_arm_cm_zephyr_stacking, switch_zephyr_thread
import json
import gdb


@rtos_class
class Zephyr(Rtos):
    types = None

    def __init__(self):
        self.config = ZephyrConfig()
        for field in Zephyr.types.kernel_t.fields():
            if field.name == "threads":
                self.config.threadMonitor = True
                break

        for field in Zephyr.types.thread_t.fields():
            if field.name == "name":
                self.config.threadName = True
                break

        super(Zephyr, self).__init__(Zephyr.types.uint32_type)

    @staticmethod
    def detect():
        Zephyr.types = TypesCache()
        if Zephyr.types.kernel_t is None or Zephyr.types.thread_t is None:
            return False
        if Zephyr.types.uint32_type is None or Zephyr.types.long_type is None:
            return False
        if gdb.lookup_global_symbol("_kernel") is None:
            return False
        if gdb.lookup_global_symbol("z_main_thread") is None:
            return False
        return True

    @staticmethod
    def name():
        return "ZEPHYR"

    def get_config(self):
        return json.dumps({
          'configThreadMonitor': self.config.threadMonitor,
          'configThreadName': self.config.threadName,
        })

    def get_threads(self):
        return get_zephyr_tasks(self.config, Zephyr.types)

    def get_queues(self):
        return json.dumps([])

    def get_timers(self):
        return json.dumps([])

    def get_heap_info(self):
        return json.dumps([])

    def get_current_thread(self):
        return get_curr_task(self.config, Zephyr.types)

    def get_thread_registers(self):
        return arm_32_commmon_registers

    def get_thread_stacking(self, stack_ptr):
        return get_arm_cm_zephyr_stacking(stack_ptr, Zephyr.types.uint32_type)

    def switch_thread(self, stack_ptr):
        switch_zephyr_thread(self, stack_ptr)


class TypesCache:
    def __init__(self):
        self.uint32_type = safe_gdb_lookup_type("uint32_t")
        self.long_type = safe_gdb_lookup_type("long")
        self.kernel_t = safe_gdb_lookup_type("struct z_kernel")
        self.thread_t = safe_gdb_lookup_type("struct k_thread")


class ZephyrConfig:
    def __init__(self):
        self.threadMonitor = False
        self.threadName = False
        self.tasks_map = {}
        self.next_task_index = 0

    def get_task_id(self, name):
        try:
            return self.tasks_map[name]
        except KeyError:
            new_id = self.next_task_index
            self.tasks_map[name] = new_id
            self.next_task_index += 1
            return new_id


print("Zephyr initialized")
