/* ----------------------------------------------------------------------- *
 *
 *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 *   Boston MA 02110-1301, USA; either version 2 of the License, or
 *   (at your option) any later version; incorporated herein by reference.
 *
 * ----------------------------------------------------------------------- */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <colortbl.h>
#include "menu.h"

/*
 * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows
 *
 * 00 - screen		Rest of the screen
 * 01 - border		Border area
 * 02 - title		Title bar
 * 03 - unsel		Unselected menu item
 * 04 - hotkey		Unselected hotkey
 * 05 - sel		Selection bar
 * 06 - hotsel		Selected hotkey
 * 07 - scrollbar	Scroll bar
 * 08 - tabmsg		Press [Tab] message
 * 09 - cmdmark		Command line marker
 * 10 - cmdline		Command line
 * 11 - pwdborder	Password box border
 * 12 - pwdheader	Password box header
 * 13 - pwdentry	Password box contents
 * 14 - timeout_msg	Timeout message
 * 15 - timeout		Timeout counter
 * 16 - help		Current entry help text
 * 17 - disabled        Disabled menu item
 */

static const struct color_table default_colors[] = {
  { "screen",      "37;40",     0x80ffffff, 0x00000000, SHADOW_NORMAL },
  { "border",      "30;44",     0x40000000, 0x00000000, SHADOW_NORMAL },
  { "title",       "1;36;44",   0xc00090f0, 0x00000000, SHADOW_NORMAL },
  { "unsel",       "37;44",     0x90ffffff, 0x00000000, SHADOW_NORMAL },
  { "hotkey",      "1;37;44",   0xffffffff, 0x00000000, SHADOW_NORMAL },
  { "sel",         "7;37;40",   0xe0000000, 0x20ff8000, SHADOW_ALL },
  { "hotsel",      "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL },
  { "scrollbar",   "30;44",     0x40000000, 0x00000000, SHADOW_NORMAL },
  { "tabmsg",      "31;40",     0x90ffff00, 0x00000000, SHADOW_NORMAL },
  { "cmdmark",     "1;36;40",   0xc000ffff, 0x00000000, SHADOW_NORMAL },
  { "cmdline",     "37;40",     0xc0ffffff, 0x00000000, SHADOW_NORMAL },
  { "pwdborder",   "30;47",     0x80ffffff, 0x20ffffff, SHADOW_NORMAL },
  { "pwdheader",   "31;47",     0x80ff8080, 0x20ffffff, SHADOW_NORMAL },
  { "pwdentry",    "30;47",     0x80ffffff, 0x20ffffff, SHADOW_NORMAL },
  { "timeout_msg", "37;40",     0x80ffffff, 0x00000000, SHADOW_NORMAL },
  { "timeout",     "1;37;40",   0xc0ffffff, 0x00000000, SHADOW_NORMAL },
  { "help",        "37;40",     0xc0ffffff, 0x00000000, SHADOW_NORMAL },
  { "disabled",    "1;30;44",   0x60cccccc, 0x00000000, SHADOW_NORMAL },
};

#define NCOLORS (sizeof default_colors/sizeof default_colors[0])
const int message_base_color = NCOLORS;
const int menu_color_table_size = NCOLORS+256;

/* Algorithmically generate the msgXX colors */
void set_msg_colors_global(struct color_table *tbl,
			   unsigned int fg, unsigned int bg,
			   enum color_table_shadow shadow)
{
  struct color_table *cp = tbl+message_base_color;
  unsigned int i;
  unsigned int fga, bga;
  unsigned int fgh, bgh;
  unsigned int fg_idx, bg_idx;
  unsigned int fg_rgb, bg_rgb;

  static const unsigned int pc2rgb[8] =
    { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
      0xffffff };

  /* Converting PC RGBI to sensible RGBA values is an "interesting"
     proposition.  This algorithm may need plenty of tweaking. */

  fga = fg & 0xff000000;
  fgh = ((fg >> 1) & 0xff000000) | 0x80000000;

  bga = bg & 0xff000000;
  bgh = ((bg >> 1) & 0xff000000) | 0x80000000;

  for (i = 0; i < 256; i++) {
    fg_idx = i & 15;
    bg_idx = i >> 4;

    fg_rgb = pc2rgb[fg_idx & 7] & fg;
    bg_rgb = pc2rgb[bg_idx & 7] & bg;

    if (fg_idx & 8) {
      /* High intensity foreground */
      fg_rgb |= fgh;
    } else {
      fg_rgb |= fga;
    }

    if (bg_idx == 0) {
      /* Default black background, assume transparent */
      bg_rgb = 0;
    } else if (bg_idx & 8) {
      bg_rgb |= bgh;
    } else {
      bg_rgb |= bga;
    }

    cp->argb_fg = fg_rgb;
    cp->argb_bg = bg_rgb;
    cp->shadow = shadow;
    cp++;
  }
}

struct color_table *default_color_table(void)
{
  unsigned int i;
  const struct color_table *dp;
  struct color_table *cp;
  struct color_table *color_table;
  static const int pc2ansi[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  static char msg_names[6*256];
  char *mp;

  color_table = calloc(NCOLORS+256, sizeof(struct color_table));

  dp = default_colors;
  cp = color_table;

  for (i = 0; i < NCOLORS; i++) {
    *cp = *dp;
    cp->ansi = refstrdup(dp->ansi);
    cp++;
    dp++;
  }

  mp = msg_names;
  for (i = 0; i < 256; i++) {
    cp->name = mp;
    mp += sprintf(mp, "msg%02x", i)+1;

    rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
	     pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
    cp++;
  }

  /*** XXX: This needs to move to run_menu() ***/
  console_color_table = color_table;
  console_color_table_size = NCOLORS+256;

  set_msg_colors_global(color_table, MSG_COLORS_DEF_FG,
			MSG_COLORS_DEF_BG, MSG_COLORS_DEF_SHADOW);

  return color_table;
}

struct color_table *copy_color_table(const struct color_table *master)
{
  const struct color_table *dp;
  struct color_table *color_table, *cp;
  unsigned int i;

  color_table = calloc(NCOLORS+256, sizeof(struct color_table));

  dp = master;
  cp = color_table;

  for (i = 0; i < NCOLORS+256; i++) {
    *cp = *dp;
    cp->ansi = refstr_get(dp->ansi);
    cp++;
    dp++;
  }

  return color_table;
}
