/*
 *	Universal Terminal Interface -- Initialization
 *
 *	(c) 1996--1999 Martin Mares, <mj@ericsson.cz>
 */

#include <stdio.h>

#include "termint.h"

/* Basic terminal characteristics */

ulg rows, columns;
ulg baud, nsec_per_char, padding_char, term_inited;

/* Tabbing mode */

int use_tabs;

/* Overstriking mode */

int overstriking;

/* Auto-margining mode */

int auto_margins;

/* Control sequence consts */

struct cost cost_multi_down, cost_multi_up, cost_multi_left, cost_multi_right, cost_set_column,
					      cost_set_row, cost_move_row, cost_move_col;

int cost_home, cost_lower_left, cost_cr, cost_left, cost_right, cost_up, cost_down, cost_nl,
  cost_tab, cost_back_tab, cost_attr_set_all, cost_attr_reset_all, cost_attr_set[8],
  cost_set_back, cost_set_fore, cost_attr_reset[8], cost_clear_n, cost_repeat_char;

/* Checking and inititialization */

void
check_caps(void)
{
  if (BOOL(GENERIC))
    fatal_error("Terminal type not set");
  if (BOOL(HARDCOPY))
    fatal_error("Hardcopy terminals are not supported");
  if (!STR(MOVE))
    fatal_error("Terminal doesn't support cursor position setting");
}

void
term_setup(void)
{
  if (BOOL(AUTO_MARGINS))
    {
      if (BOOL(STRANGE_AUTO_MARGINS))
	auto_margins = AM_GOTO;
      else
	{
	  auto_margins = AM_DUMB;
	  if (!STR(INSERT_CHAR))
	    {
	      DBG(("Weird auto-margins and no insert mode => will ignore BR corner\n"));
	      auto_margins = AM_NO_CORNER;
	    }
	}
    }

  if (!HAVE(DEFAULT_TABS) || INT(DEFAULT_TABS) == 8)
    {
      if (BOOL(DESTRUCTIVE_TABS))
	use_tabs = TABS_DESTRUCT;
      else
	use_tabs = TABS_NORMAL;
    }

  send(STR(INIT));

  if (STR(PAD))
    padding_char = STR(PAD)[0];
  if (HAVE(PADDING_MIN_BAUD) && baud < INT(PADDING_MIN_BAUD) || BOOL(XON_XOFF))
    padding_char = -1;
  if (baud)
    nsec_per_char = 1000000000 / baud;
  else
    nsec_per_char = 1000000;

  send(STR(ENABLE_META));
  send(STR(ENABLE_FUNC_KEYS));
  send(STR(ENABLE_ALT_CHAR_SET));

  if (BOOL(OVERSTRIKE))
    {
      if (BOOL(SPACE_ERASES))
	overstriking = OS_SPACE;
      else
	overstriking = OS_CLEAR;
    }

  DBG(("auto_margins=%d, use_tabs=%d, pad_char=%d, overstrike=%d, chartime=%dns\n",
       auto_margins, use_tabs, padding_char, overstriking, nsec_per_char));
}

void
term_clean(void)
{
  send_attrs(0, default_color);
  send(STR(DISABLE_FUNC_KEYS));
  send(STR(DISABLE_META));
  send(STR(CLEANUP));
  FLUSH;
}

static int char_counter;

static int
cs_dummy_put(int c)
{
  char_counter++;
  return 0;
}

static int
cs_size(char *k, int *p, int pad)
{
  if (!k)
    return 10000;
  char_counter = 0;
  send_char = cs_dummy_put;
  senda(k, p);
  if (pad > 0)
    do_padding(pad);
  send_char = putchar;
  return char_counter;
}

static int
cost_simple(char *k, int pad)
{
  int params[10];

  params[0] = params[1] = 1;
  return cs_size(k, params, pad);
}

static void
cost_cplx(struct cost *c, char *k)
{
  int params[10];

  params[1] = 1;
  params[0] = 4;
  c->c0 = cs_size(k, params, 0);
  params[0] = 44;
  c->c1 = cs_size(k, params, 0);
  params[0] = 132;
  c->c2 = cs_size(k, params, 0);
}

static int
cost_set_all(void)
{
  char *c = STR(SET_ALL_ATTRS);
  int m;
  int z[9];

  if (!c)
    return 10000;
  z[0] = z[2] = z[4] = z[6] = z[8] = 1;
  z[1] = z[3] = z[5] = z[7] = 0;
  m = cs_size(c, z, 0);
  z[0] = z[2] = z[4] = z[6] = z[8] = 0;
  z[1] = z[3] = z[5] = z[7] = 1;
  m += cs_size(c, z, 0);
  return m / 2;
}

void
optimizer_setup(void)
{
  int p[2];
  int i;

  cost_home = cost_simple(STR(HOME), 0);
  cost_lower_left = cost_simple(STR(LOWER_LEFT), 0);
  cost_cr = cost_simple(STR(CR), INT(PAD_CR));
  cost_left = cost_simple(STR(LEFT), 0);
  cost_right = cost_simple(STR(RIGHT), 0);
  cost_up = cost_simple(STR(UP), 0);
  cost_down = cost_simple(STR(DOWN), 0);
  cost_nl = cost_simple(STR(NL), INT(PAD_LF));
  cost_tab = cost_simple(STR(TAB), INT(PAD_TAB));
  cost_back_tab = cost_simple(STR(BACK_TAB), 0);
  cost_cplx(&cost_multi_left, STR(MULTI_LEFT));
  cost_cplx(&cost_multi_right, STR(MULTI_RIGHT));
  cost_cplx(&cost_multi_up, STR(MULTI_UP));
  cost_cplx(&cost_multi_down, STR(MULTI_DOWN));
  cost_cplx(&cost_set_column, STR(SET_COLUMN));
  cost_cplx(&cost_set_row, STR(SET_ROW));
  p[1] = 4;
  p[0] = 4; cost_move_row.c0 = cs_size(STR(MOVE), p, 0);
  p[0] = 44; cost_move_row.c1 = cs_size(STR(MOVE), p, 0);
  p[0] = 132; cost_move_row.c2 = cs_size(STR(MOVE), p, 0);
  p[0] = 4;
  p[1] = 4; cost_move_col.c0 = cs_size(STR(MOVE), p, 0);
  p[1] = 44; cost_move_col.c1 = cs_size(STR(MOVE), p, 0) - cost_move_col.c0;
  p[1] = 132; cost_move_col.c2 = cs_size(STR(MOVE), p, 0) - cost_move_col.c0;
  cost_move_col.c0 = 0;
  cost_attr_reset_all = cost_simple(STR(NORMAL), 0);
  cost_attr_set_all = cost_set_all();
  for(i=0; i<8; i++)
    {
      cost_attr_set[i] = cost_simple(set_attr[i], 0);
      cost_attr_reset[i] = cost_simple(reset_attr[i], 0);
    }
  cost_set_back = cost_simple(STR(SET_ANSI_BACKGROUND) ? : STR(SET_BACKGROUND), 0);
  cost_set_fore = cost_simple(STR(SET_ANSI_FOREGROUND) ? : STR(SET_FOREGROUND), 0);
  cost_clear_n = cost_simple(STR(CLEAR_N_CHARS), 0);
  p[0] = '*'; p[1] = 1;
  cost_repeat_char = cs_size(STR(REPEAT), p, 0);
  TR("Costs: ho=%d, ll=%d, cr=%d, le=%d, ri=%d, up=%d, do=%d, nl=%d, ta=%d, bt=%d, cn=%d, rc=%d, ",
      cost_home, cost_lower_left, cost_cr, cost_left, cost_right, cost_up,
      cost_down, cost_nl, cost_tab, cost_back_tab, cost_clear_n, cost_repeat_char);
#define CC(x) cost_##x.c0, cost_##x.c1, cost_##x.c2
  TR("ml=%d/%d/%d, mr=%d/%d/%d, mu=%d/%d/%d, md=%d/%d/%d, sc=%d/%d/%d, sr=%d/%d/%d, cm=%d/%d/%d+%d/%d/%d, ",
      CC(multi_left), CC(multi_right), CC(multi_up), CC(multi_down), CC(set_column),
      CC(set_row), CC(move_row), CC(move_col));
#undef CC
  TR("rac=%d, sac=%d, sc=(%d,%d,%d,%d,%d,%d,%d,%d), rc=(%d,%d,%d,%d,%d,%d,%d,%d), sb=%d, sf=%d.\n",
      cost_attr_reset_all, cost_attr_set_all, cost_attr_set[0], cost_attr_set[1], cost_attr_set[2],
      cost_attr_set[3], cost_attr_set[4], cost_attr_set[5], cost_attr_set[6], cost_attr_set[7],
      cost_attr_reset[0], cost_attr_reset[1], cost_attr_reset[2], cost_attr_reset[3],
      cost_attr_reset[4], cost_attr_reset[5], cost_attr_reset[6], cost_attr_reset[7],
      cost_set_back, cost_set_fore);
}
