import gdb
import json
from freertos.List import ListManager

QUEUE = 0
MUTEX = 1
COUNTING = 2
BINARY = 3
RECURSIVE = 4

QueueTypeMap = {
  MUTEX: "mutex",
  QUEUE: "queue",
  BINARY: "binary semaphore",
  COUNTING: "counting semaphore",
  RECURSIVE: "recursive mutex"
}


def get_queue_registry_as_map():
    symbol, _ = gdb.lookup_symbol("xQueueRegistry")
    registry = symbol.value()
    min_index, max_index = registry.type.range()
    queue_map = {}
    for i in range(min_index, max_index):
        elem = registry[i]
        handle = elem['xHandle']
        if handle != 0:
            name = elem['pcQueueName'].string()
            queue_map[name] = handle
    return queue_map


def get_freertos_queues(config, types):
    result = []
    for name, handle in get_queue_registry_as_map().items():
        result.append(__prepare_queue_info(config, name, handle, types))
    return json.dumps(result)


def __prepare_queue_info(config, name, handle, types):
    q = handle.cast(types.queue_type.pointer()).dereference()

    try:
        tail = int(q['u']['xQueue']['pcTail'])
        read_from = int(q['u']['xQueue']['pcReadFrom'])
    except gdb.error:
        # FreeRTOS V10.0.0-
        tail = int(q['pcTail'])
        read_from = int(q['u']['pcReadFrom'])

    queue = {
      'name': name,
      'address': int(q.address),
      'currentLength': int(q['uxMessagesWaiting']),
      'maxLength': int(q['uxLength']),
      'dataItemSize': int(q['uxItemSize']),
      'head': int(q['pcHead']),
      'tail': tail,
      'readFrom': read_from,
      'writeTo': int(q['pcWriteTo']),
      'txWaitingTasks': {'first': int(q['xTasksWaitingToSend'].address), 'second': get_waiting_tasks(q['xTasksWaitingToSend'], types)},
      'rxWaitingTasks': {'first': int(q['xTasksWaitingToReceive'].address), 'second': get_waiting_tasks(q['xTasksWaitingToReceive'], types)},
    }

    if config.use_trace_facility:
        queue['type'] = QueueTypeMap[int(q['ucQueueType'])]

    return queue


def get_waiting_tasks(list_addr, types):
    res = []
    for task, _ in ListManager(list_addr, types).get_elements(types.tcb_type):
        res.append(int(task.address))
    return res
