// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <fcntl.h>
#include <fuchsia/hardware/power/statecontrol/llcpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/unsafe.h>
#include <lib/service/llcpp/service.h>
#include <lib/zx/channel.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/param.h>

#include <hid/usages.h>

#include "keyboard-vt100.h"
#include "keyboard.h"
#include "vc.h"

static struct list_node g_vc_list = LIST_INITIAL_VALUE(g_vc_list);
static unsigned g_vc_count = 0;
static unsigned g_active_vc_index = 0;

vc_t* g_active_vc = nullptr;
int g_status_width = 0;

// Process key sequences that affect the console (scrolling, switching
// console, etc.) without sending input to the current console.  This
// returns whether this key press was handled.
static bool vc_handle_control_keys(uint8_t keycode, int modifiers) {
  switch (keycode) {
    case HID_USAGE_KEY_F1 ... HID_USAGE_KEY_F10:
      if (modifiers & MOD_ALT) {
        vc_set_active(keycode - HID_USAGE_KEY_F1, NULL);
        return true;
      }
      break;

    case HID_USAGE_KEY_TAB:
      if (modifiers & MOD_ALT) {
        if (modifiers & MOD_SHIFT) {
          vc_set_active(g_active_vc_index == 0 ? g_vc_count - 1 : g_active_vc_index - 1, NULL);
        } else {
          vc_set_active(g_active_vc_index == g_vc_count - 1 ? 0 : g_active_vc_index + 1, NULL);
        }
        return true;
      }
      break;

    case HID_USAGE_KEY_VOL_UP:
      vc_set_active(g_active_vc_index == 0 ? g_vc_count - 1 : g_active_vc_index - 1, NULL);
      break;

    case HID_USAGE_KEY_VOL_DOWN:
      vc_set_active(g_active_vc_index == g_vc_count - 1 ? 0 : g_active_vc_index + 1, NULL);
      break;

    case HID_USAGE_KEY_UP:
      if (modifiers & MOD_ALT) {
        vc_scroll_viewport(g_active_vc, -1);
        return true;
      }
      break;
    case HID_USAGE_KEY_DOWN:
      if (modifiers & MOD_ALT) {
        vc_scroll_viewport(g_active_vc, 1);
        return true;
      }
      break;
    case HID_USAGE_KEY_PAGEUP:
      if (modifiers & MOD_SHIFT) {
        vc_scroll_viewport(g_active_vc, -(vc_rows(g_active_vc) / 2));
        return true;
      }
      break;
    case HID_USAGE_KEY_PAGEDOWN:
      if (modifiers & MOD_SHIFT) {
        vc_scroll_viewport(g_active_vc, vc_rows(g_active_vc) / 2);
        return true;
      }
      break;
    case HID_USAGE_KEY_HOME:
      if (modifiers & MOD_SHIFT) {
        vc_scroll_viewport_top(g_active_vc);
        return true;
      }
      break;
    case HID_USAGE_KEY_END:
      if (modifiers & MOD_SHIFT) {
        vc_scroll_viewport_bottom(g_active_vc);
        return true;
      }
      break;
  }
  return false;
}

// Process key sequences that affect the low-level control of the system
// (switching display ownership, rebooting).  This returns whether this key press
// was handled.
static bool vc_handle_device_control_keys(uint8_t keycode, int modifiers) {
  switch (keycode) {
    case HID_USAGE_KEY_DELETE:
      // Provide a CTRL-ALT-DEL reboot sequence
      if ((modifiers & MOD_CTRL) && (modifiers & MOD_ALT)) {
        auto local = service::Connect<fuchsia_hardware_power_statecontrol::Admin>();
        if (local.is_error()) {
          return true;
        }
        auto response =
            fidl::BindSyncClient(std::move(*local))
                .Reboot(fuchsia_hardware_power_statecontrol::wire::RebootReason::kUserRequest);
        if (response.status() != ZX_OK) {
          fprintf(stderr, "Failed to reboot, status:%d\n", response.status());
          return true;
        }
        if (response->result.is_err()) {
          fprintf(stderr, "Failed to reboot, status:%d\n", response->result.err());
          return true;
        }
        // Wait for the world to end.
        zx_nanosleep(ZX_TIME_INFINITE);
        return true;
      }
      break;

    case HID_USAGE_KEY_ESC:
      if (modifiers & MOD_ALT) {
        vc_toggle_framebuffer();
        return true;
      }
      break;
  }

  return false;
}

zx_status_t vc_set_active(int num, vc_t* to_vc) {
  vc_t* vc = NULL;
  int i = 0;
  list_for_every_entry (&g_vc_list, vc, vc_t, node) {
    if ((num == i) || (to_vc == vc)) {
      if (vc == g_active_vc) {
        return ZX_OK;
      }
      if (g_active_vc) {
        g_active_vc->active = false;
        g_active_vc->flags &= ~VC_FLAG_HASOUTPUT;
      }
      vc->active = true;
      vc->flags &= ~VC_FLAG_HASOUTPUT;
      g_active_vc = vc;
      g_active_vc_index = i;
      vc_full_repaint(vc);
      vc_render(vc);
      return ZX_OK;
    }
    i++;
  }
  return ZX_ERR_NOT_FOUND;
}

void vc_show_active() {
  vc_t* vc = NULL;
  list_for_every_entry (&g_vc_list, vc, vc_t, node) {
    vc_attach_gfx(vc);
    if ((vc->fd >= 0) && isatty(vc->fd)) {
      struct winsize sz = {};

      ZX_DEBUG_ASSERT(vc->columns <= UINT16_MAX);
      sz.ws_col = static_cast<uint16_t>(vc->columns);

      ZX_DEBUG_ASSERT(vc->rows <= UINT16_MAX);
      sz.ws_row = static_cast<uint16_t>(vc->rows);

      ioctl(vc->fd, TIOCSWINSZ, &sz);
    }
    if (vc == g_active_vc) {
      vc_full_repaint(vc);
      vc_render(vc);
    }
  }
}

void vc_change_graphics(vc_gfx_t* graphics) {
  vc_t* vc = NULL;
  list_for_every_entry (&g_vc_list, vc, vc_t, node) { vc->graphics = graphics; }
  vc_show_active();
}

void vc_status_update() {
  vc_t* vc = NULL;
  unsigned i = 0;
  int x = 0;

  int w = g_status_width / (g_vc_count + 1);
  if (w < MIN_TAB_WIDTH) {
    w = MIN_TAB_WIDTH;
  } else if (w > MAX_TAB_WIDTH) {
    w = MAX_TAB_WIDTH;
  }

  char tmp[w];

  vc_status_clear();
  list_for_every_entry (&g_vc_list, vc, vc_t, node) {
    unsigned fg;
    if (vc->active) {
      fg = STATUS_COLOR_ACTIVE;
    } else if (vc->flags & VC_FLAG_HASOUTPUT) {
      fg = STATUS_COLOR_UPDATED;
    } else {
      fg = STATUS_COLOR_DEFAULT;
    }

    int lines = vc_get_scrollback_lines(vc);
    char L = (lines > 0) && (-vc->viewport_y < lines) ? '<' : '[';
    char R = (vc->viewport_y < 0) ? '>' : ']';

    snprintf(tmp, w, "%c%u%c %s", L, i, R, vc->title);
    vc_status_write(x, fg, tmp);
    x += w;
    i++;
  }
  vc_status_commit();
}

void handle_key_press(uint8_t keycode, int modifiers) {
  // Handle vc-level control keys
  if (vc_handle_device_control_keys(keycode, modifiers))
    return;

  // Handle other keys only if we own the display
  if (!g_vc_owns_display)
    return;

  // Handle other control keys
  if (vc_handle_control_keys(keycode, modifiers))
    return;

  vc_t* vc = g_active_vc;
  char output[4];
  uint32_t length = hid_key_to_vt100_code(keycode, modifiers, vc->keymap, output, sizeof(output));
  if (length > 0) {
    if (vc->fd >= 0) {
      write(vc->fd, output, length);
    }
    vc_scroll_viewport_bottom(vc);
  }
}

ssize_t vc_write(vc_t* vc, const void* buf, size_t count, zx_off_t off) {
  vc->invy0 = vc_rows(vc) + 1;
  vc->invy1 = -1;
  const uint8_t* str = (const uint8_t*)buf;
  for (size_t i = 0; i < count; i++) {
    vc->textcon.putc(&vc->textcon, str[i]);
  }
  vc_flush(vc);
  if (!(vc->flags & VC_FLAG_HASOUTPUT) && !vc->active) {
    vc->flags |= VC_FLAG_HASOUTPUT;
    vc_status_update();
  }
  return count;
}

// Create a new vc_t and add it to the console list.
zx_status_t vc_create(vc_t** vc_out, const color_scheme_t* color_scheme) {
  zx_status_t status;
  vc_t* vc;
  if ((status = vc_alloc(&vc, color_scheme)) < 0) {
    return status;
  }

  // add to the vc list
  list_add_tail(&g_vc_list, &vc->node);
  g_vc_count++;

  // make this the active vc if it's the first one
  if (!g_active_vc) {
    vc_set_active(-1, vc);
  } else {
    vc_render(g_active_vc);
  }

  *vc_out = vc;
  return ZX_OK;
}

void vc_destroy(vc_t* vc) {
  list_delete(&vc->node);
  g_vc_count -= 1;

  vc_free(vc);
}
