/*
  Shared
*/

#include "shared.h"

#include "config.h"
#include "console.h"
#include "file.h"
#include "head.h"
#include "os.h"
#include "page.h"
#include "wio.h"

#define CMD_LIMIT 256

void display(byte *s)
{
  start_update();
  while(*s)
    out_char(*s++);
  finish_update();
}

void save_cursor(void)
{
  save_attributes(0);
}

void restore_cursor(void)
{
  restore_attributes(0);
}

#define bytes(s) (1+os_strlen(s))

static void draw_editable(int x, byte *s, int off, int log)
{
  int dummy, y;
  get_xy(&dummy, &y);
  start_update();
  set_xy(x, y);
  erase_to_eoln();
  if(log)
    display(s);
  else
    raw_display(s);
  set_xy(x + off, y);
  finish_update();
}

int getline(const byte *prompt, char *buff, int maxlen)
{
  static int cmd_held = 0;
  static char cmd_buff[CMD_LIMIT];
  int cmd_count = cmd_held;
  int font = 1;
  int c, off = 0;
  int x, y;
  force_update();
  show_cursor();
  raw_display(prompt);
  swap_font_status(&font);
  get_xy(&x, &y);
  buff[off] = '\0';
  draw_editable(x, (byte *) buff, off, 0);
  while((c = get_ch()) != '\r')
  {
    switch(c)
    {
      case '\b':
        if(off > 0)
        {
          os_strcpy(&buff[off - 1], &buff[off]);
          --off;
        }
        break;
      case 'A' - '@':
        off = 0;
        break;
      case 'E' - '@':
        off = os_strlen(buff);
        break;
      case 'D' - '@':
        if(off < os_strlen(buff))
          os_strcpy(&buff[off], &buff[off + 1]);
        break;
      case 'F' - '@':
        if(off < os_strlen(buff))
          ++off;
        break;
      case 'B' - '@':
        if(off)
          --off;
        break;
      case 'P' - '@':
      case 'N' - '@':
        if(cmd_held)
        {
          if(c == 'P' - '@')
          {
            if(cmd_count == 0)
              cmd_count = cmd_held;
            cmd_count -= 2;
            while(cmd_count >= 0 && cmd_buff[cmd_count])
              --cmd_count;
            ++cmd_count;
          }
          else
          {
            cmd_count += bytes(&cmd_buff[cmd_count]);
            if(cmd_count == cmd_held)
              cmd_count = 0;
          }
          off = bytes(&cmd_buff[cmd_count]);
          os_mcpy(buff, &cmd_buff[cmd_count], min(off, maxlen));
          buff[maxlen - 1] = '\0';
          off = os_strlen(buff);
        }
        break;
      case 'U' - '@':
        off = 0;
      /* Fall through */
      case 'K' - '@':
        buff[off] = '\0';
        break;
      default:
        if(bytes(buff) < maxlen && c >= 32)
        {
          os_mcpy(&buff[off + 1], &buff[off], os_strlen(&buff[off]) + 1);
          buff[off++] = c;
        }
        break;
    }
    draw_editable(x, (byte *) buff, off, 0);
  }
  off = os_strlen(buff);
  draw_editable(x, (byte *) buff, off, 1);
  hide_cursor();
  out_char('\n');

  swap_font_status(&font);

  game_saved = 0;

  /* Store in history */

  if(off && off + 1 < CMD_LIMIT)
  {
    int i = 0;
    while(cmd_held + off - i >= CMD_LIMIT)
      i += bytes(&cmd_buff[i]);
    cmd_held -= i;
    os_mcpy(cmd_buff, &cmd_buff[i], cmd_held);
    os_strcpy(&cmd_buff[cmd_held], buff);
    cmd_held += off + 1;
  }
  return off;
}

void out_char(word c)
{
  extern bool newlines_are_significant;
  extern bool windowing_enabled;
  extern word current_window;
  extern word status_height;
  extern bool enable_screen;
  extern int linecount;
  script_char(c);
  put_char(c);
  if(enable_screen)
  {
    if(c == '\n')
    {
      int page = !windowing_enabled || current_window == 0;
      if(page && newlines_are_significant)
      {
        int lose = windowing_enabled ? 0 : status_height;
        int high = hd_height() - lose - 3;
        if(linecount++ >= high)
        {
          force_update();
          more();
          newlines_are_significant = 0;
          linecount = 0;
        }
      }
    }
    else
    {
      newlines_are_significant = 1;
    }
  }
}

void raw_display(const byte *s)
{
  start_update();
  while(*s)
    put_char(*s++);
  finish_update();
}

#if 0 /* Used for real-time support */
int kbd_hit(void)
{
  return 1;
}
#endif

