import gdb
from common import Rtos, rtos_class, arm_32_commmon_registers, safe_gdb_lookup_type
from freertos.Task import get_freertos_tasks, get_curr_task
from freertos.Queue import get_freertos_queues
from freertos.Timer import get_freertos_timers
from freertos.Heap import get_freertos_heap_info, determine_memory_scheme, HEAP_2, HEAP_4, HEAP_5
from freertos.cortex_m import get_arm_cm_freertos_stacking
import json


@rtos_class
class FreeRtos(Rtos):
    types = None

    def __init__(self):
        self.config = FreeRtosConfig()
        for field in FreeRtos.types.tcb_type.fields():
            if field.name == "uxTaskNumber":
                self.config.use_trace_facility = True
            if field.name == "ulRunTimeCounter":
                self.config.generate_runtime_stats = True
            if field.name == "uxBasePriority":
                self.config.use_mutexes = True
            if field.name == "pxEndOfStack":
                self.config.record_stack_high_address = True

        if FreeRtos.types.timer_type is not None:
            self.config.use_timers = True

        if FreeRtos.types.queue_registry_item_type is not None:
            self.config.queue_registry_enabled = True

        if FreeRtos.types.heap_block_link_type is not None:
            self.config.heap_info_available = True

        if FreeRtos.types.thread_type is not None:  # todo also check for target system
            self.config.is_posix = True

        if gdb.lookup_global_symbol("pxCurrentTCBs"):
            self.config.is_smp = True

        super(FreeRtos, self).__init__(FreeRtos.types.long_type)

    @staticmethod
    def detect():
        FreeRtos.types = TypesCache()
        if FreeRtos.types.tcb_type is None or FreeRtos.types.list_type is None:
            return False
        if FreeRtos.types.uint32_type is None or FreeRtos.types.long_type is None:
            return False
        if gdb.lookup_global_symbol("pxCurrentTCB") is None and gdb.lookup_global_symbol("pxCurrentTCBs") is None:
            return False
        return True

    @staticmethod
    def name():
        return "FREERTOS"

    def get_config(self):
        return json.dumps({
          'useTraceFacility': self.config.use_trace_facility,
          'generateRuntimeStats': self.config.generate_runtime_stats,
          'queueRegistryEnabled': self.config.queue_registry_enabled,
          'heapInfoAvailable': self.config.heap_info_available,
          'useMutexes': self.config.use_mutexes,
          'recordStackHighAddress': self.config.record_stack_high_address,
          'useTimers': self.config.use_timers,
          'isPosix': self.config.is_posix,
          'isSmp': self.config.is_smp,
        })

    def get_threads(self):
        return get_freertos_tasks(self.config, FreeRtos.types)

    def get_queues(self):
        return get_freertos_queues(self.config, self.types)

    def get_timers(self):
        return get_freertos_timers(self.config, self.types)

    def get_heap_info(self):
        return get_freertos_heap_info(self.config, self.types.heap_block_link_type)

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

    def get_thread_registers(self):
        return arm_32_commmon_registers

    def get_thread_stacking(self, stack_ptr):
        return get_arm_cm_freertos_stacking(stack_ptr, FreeRtos.types.uint32_type)


class TypesCache:
    def __init__(self):
        self.tcb_type = safe_gdb_lookup_type("TCB_t")
        self.list_type = safe_gdb_lookup_type("List_t")
        self.uint32_type = safe_gdb_lookup_type("uint32_t")
        self.long_type = safe_gdb_lookup_type("long")
        self.queue_type = safe_gdb_lookup_type("Queue_t")
        self.queue_registry_item_type = safe_gdb_lookup_type("QueueRegistryItem_t")
        self.timer_type = safe_gdb_lookup_type("Timer_t")
        self.heap_block_link_type = safe_gdb_lookup_type("BlockLink_t")
        self.heap_region_type = safe_gdb_lookup_type("HeapRegion_t")
        self.thread_type = safe_gdb_lookup_type("Thread_t")


class FreeRtosConfig:
    def __init__(self):
        self.use_trace_facility = False
        self.generate_runtime_stats = False
        self.use_mutexes = False
        self.record_stack_high_address = False
        self.use_timers = False
        self.queue_registry_enabled = False
        self.heap_info_available = False
        self.heap_type = None
        self.is_posix = False
        self.is_smp = 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("FreeRTOS initialized")
