import gdb
import json

READY = 0
DUMMY = 1 << 0
PENDING = 1 << 1
PRESTART = 1 << 2
DEAD = 1 << 3
SUSPENDED = 1 << 4
ABORTING = 1 << 5
QUEUED = 1 << 7

STATE_NAMES = {
  READY: "Ready",
  DUMMY: "Dummy",
  PENDING: "Pending",
  PRESTART: "Prestart",
  DEAD: "Dead",
  SUSPENDED: "Suspended",
  ABORTING: "Polling",
  QUEUED: "Queued",
}


def get_curr_task(config, types):
    kernel_ptr, _ = gdb.lookup_symbol("_kernel")
    kernel = kernel_ptr.value().cast(types.kernel_t)
    curr_thread = kernel['cpus'][0]['current'].cast(types.thread_t.pointer()).dereference()
    return json.dumps(prepare_task_data(curr_thread, config))


def get_zephyr_tasks(config, types):
    kernel_ptr, _ = gdb.lookup_symbol("_kernel")
    kernel = kernel_ptr.value().cast(types.kernel_t)

    curr_thread = kernel['threads'].cast(types.thread_t.pointer()).dereference()
    result = [prepare_task_data(curr_thread, config)]
    while curr_thread['next_thread'] != 0:
        curr_thread = curr_thread['next_thread'].cast(types.thread_t.pointer()).dereference()
        result.append(prepare_task_data(curr_thread, config))

    return json.dumps(result)


def prepare_task_data(task, config):
    task_addr = int(task.address)

    try:
        pc_buff = gdb.selected_inferior().read_memory(int(task['callee_saved']['psp']) + 24, 4)
        pc = ''.join('%.2x' % ord(pc_buff[i]) for i in reversed(range(len(pc_buff))))
    except gdb.error:
        pc = 0

    result = {
      'name': task['name'].string(),
      'currentPriority': int(task['base']['prio']),
      'basePriority': 0,
      'handle': task_addr,
      'id': config.get_task_id(task['name'].string()),
      'stackTop': int(task['callee_saved']['psp'].address),
      'stackBase': int(task['callee_saved']['psp']),
      'eventObjectPtr': 0,
      'programCounter': int('0x%s' % pc, 0)
    }

    try:
        result['state'] = STATE_NAMES[int(task['base']['thread_state'])]
    except KeyError:
        result['state'] = "Unknown (" + str(int(task['base']['thread_state'])) + ")"

    return result
