#include "global.h"
#include "ctype.h"
#include "color.h"
#include "socket.h"
#include "session.h"
#ifdef MSDOS
#include "conio.h"
#else
#define COLOR_BLACK	0
#define COLOR_RED	1
#define COLOR_GREEN	2
#define COLOR_YELLOW	3
#define COLOR_BLUE	4
#define COLOR_MAGENTA	5
#define COLOR_CYAN	6
#define COLOR_WHITE	7
#endif

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: color.c,v 1.19 2001/05/06 16:32:55 brian Exp $";
#endif

#ifdef DEMO
#define tprintf printf
#define tputc putchar

static unsigned char last[2];

void
tflush ()
{
	fflush (stdout);
}
#else
#include "usock.h"

static void myusflush (int s);

static void
myusflush (s)
int s;
{
register struct usock *up;

	if((up = itop(s)) == NULLUSOCK)
		return;

	if(up->obuf == NULLBUF)
		return;
	if (len_p (up->obuf) < 220)
		return;
	usflush (s);
}
#endif

static int getmycolor (unsigned char color);
static int getone (FILE *fp);
static void getkeyword (unsigned char *input,FILE *fp);
static int cmdmatch (unsigned char *input);
static int blinking (unsigned char c);
static int bold (unsigned char c);
#ifdef MSDOS
extern int chksession (struct session *sp);
#endif
int getcolor (char *str);
int docolor (int argc, char *argv[], void *p);
void setscreens (int back, int fore, int clr);
extern void displayStatLine (int offset, int phase, int onlymarquee);


#ifdef MSDOS
int SYSback = 40, SYSfore = 37;
static int backs[8] = {0, 4, 2, 0, 1, 5, 3, 7};
static int fores[8] = {0, 4, 2, 0, 1, 5, 3, 7};
#else

#ifdef PATCURSES
int SYSback = COLOR_BLACK, SYSfore = COLOR_WHITE;
extern int init_pairs(void);
#else
int SYSback = COLOR_BLUE, SYSfore = COLOR_WHITE;
#endif

#endif
extern int STATLINE;

static char nope[] = "Color '%s' unknown!\nAvailable colors: black, red, green, cyan, blue, magenta, and white\n";



int
colorprintf (char *escapeflag, char usecolor, const unsigned char *str)
{
unsigned char c;
int foundone = 0;


	while ((c = *str++) != 0)	{
		if (c == 0x1b)	{	/* escape sequence */
			if (usecolor)	{
				foundone = 1;
#ifdef DEMO
				tflush ();
#else
				myusflush(Curproc->output);
#endif
			}
			if (escapeflag)
				*escapeflag = 1;
		}
		else if (escapeflag && *escapeflag)	{
			if (!isdigit(c) && c != ';' && c != '[')
				*escapeflag = 0;
		}
		if (!escapeflag || (escapeflag && !*escapeflag) || usecolor)	{
			tputc (c);
		}
	}
	return (foundone);
}


static int
getmycolor (unsigned char color)
{
int retval = 30;

	switch (color)	{
		case '1': case '9':	retval += 4;	break;
		case '2': case 'A':	retval += 2;	break;
		case '3': case 'B':	retval += 6;	break;
		case '4': case 'C':	retval += 1;	break;
		case '5': case 'D':	retval += 5;	break;
		case '6': case 'E':	retval += 3;	break;
		case '7': case 'F':	retval += 7;	break;
		default:		break;
	}
	return (retval);
}


static int
getone (fp)
FILE *fp;
{
int c;

	c = getc (fp);
	if (feof (fp))
		c = 0;
	return (c);
}


static void
getkeyword (input, fp)
unsigned char *input;
FILE *fp;
{
unsigned char c = 0;
int k;

	do	{
		for (k = 0; k < 15; k++)	{
			input[k] = c = uchar(getone (fp));
			if (!c || (c == '@'))
				break;
		}
		input[k] = 0;
		if (!c)
			k++;
	} while (!k);
}


void
colorcls ()
{
#ifdef DEMO
	tflush ();
#else
	myusflush(Curproc->output);
#endif
	tprintf ("\033[2J");
}


static int
cmdmatch (input)
unsigned char *input;
{
int retval = 0;

	if (!strcmp ("CLS", (char *) input))	{
		colorcls();
		retval = 1;
	}
	return (retval);
}


static int
blinking (unsigned char c)
{
	return ((c > '7') ? 1 : 0);
}


static int
bold (unsigned char c)
{
	return ((c > '7') ? 1 : 0);
}


int
colorchange (input, last)
register const char *input;
register char *last;
{
int retval = 0, putone = 0, temp, putall = 0;


	if (!input || !last)
		return (retval);
	if (!strncmp (input, last, 2))
		return (retval);
	if ((strlen(input) == 2) && (isxdigit (input[0])) && (isxdigit (input[1])))	{
#ifdef DEMO
		tflush ();
#else
		myusflush(Curproc->output);
#endif
		tprintf ("\033[");
		retval = 2;
		if (!*last)
			putall++;
		if (putall || (blinking(uchar(*last)) && !blinking(uchar(*input))) || (bold (uchar(last[1])) && !bold(uchar(input[1])))) {
			tputc ('0');
			retval++;
			putone++;
			putall++;
		}
		if (blinking(uchar(*input)))	{
			tprintf ("%s5", putone ? ";" : "");
			putone++;
			retval++;
		}
		temp = getmycolor(uchar(*input));
		if (putall || temp != getmycolor (uchar(*last)))		{
			tprintf ("%s%d", putone ? ";" : "", temp + 10);
			retval += (2 + putone);
			putone++;
		}
		if (putall || (input[1] != last[1]))	{
			tprintf ("%s%s%d", putone ? ";" : "", (input[1] > '7') ? "1;" : "",
				getmycolor (uchar(input[1])));
			retval += (putone + 2 + ((input[1] > 7) ? 2 : 0));
		}
		tputc ('m');
		retval += 1;
		memcpy (last, input, 2);
	}
	return (retval);
}


void
colorfile (filenm, last)
const char *filenm;
char *last;
{
FILE *fp;
unsigned char c, input[16];
char invalid = 0;

	if ((fp = fopen (filenm, "rb")) == NULLFILE)
		return;
	while (!feof (fp))	{
		if ((c = (unsigned char) getone (fp)) == '\0')
			continue;
		if (c == 0x1b)
			invalid = 1;
		if (c == '@')	{
			invalid = 0;
			getkeyword (input, fp);
			if (!colorchange ((char *) input, last))
				if (!cmdmatch (input))
					tprintf ("@%s@", input);
		} else
#ifndef DEMO
			if ((c != 0x0d) && (c != 0x1a))
#endif
				tputc (c);
	}
	(void) fclose (fp);
	if (invalid)
		last[0] = 0;
}



int
getcolor (char *str)
{
#ifdef MSDOS
char *ptr;

	for (ptr = str; *ptr; ptr++)
		*ptr = (char) tolower (*ptr);
	switch (*str) {
		case 'r':	return 31;
		case 'g':	return 32;
		case 'm':	return 35;
		case 'c':	return 36;
		case 'w':	return 37;
		case 'b':	if (str[1] != 'l')
					return -1;
				switch (str[2]) {
					case 'a':	return 30;
					case 'u':	return 34;
					default:	return 0;
				}
		default:	return -1;
	}
#else
	if (strcasecmp(str, "black") == 0)
		return COLOR_BLACK;
	if (strcasecmp(str, "red") == 0)
		return COLOR_RED;
	if (strcasecmp(str, "yellow") == 0)
		return COLOR_YELLOW;
	if (strcasecmp(str, "green") == 0)
		return COLOR_GREEN;
	if (strcasecmp(str, "blue") == 0)
		return COLOR_BLUE;
	if (strcasecmp(str, "magenta") == 0)
		return COLOR_MAGENTA;
	if (strcasecmp(str, "cyan") == 0)
		return COLOR_CYAN;
	if (strcasecmp(str, "white") == 0)
		return COLOR_WHITE;
	return -1;
#endif
}



/* Set terminal colors */
int
docolor (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
int temp;
int back, fore;
#ifdef MSDOS
struct session *sp = NULLSESSION;
#endif

	temp = getcolor (argv[1]);
	if (temp == -1)
		tprintf (nope, argv[1]);
	else {
#ifdef MSDOS
		back = temp + 10;
#else
		back = temp;
#endif
		temp = getcolor (argv[2]);
		if (temp == -1)
			tprintf (nope, argv[2]);
		else {
			fore = temp;
#ifdef MSDOS
			if (argc > 3) {
				temp = atoi (argv[3]);
				if (temp) {
					sp = &Sessions[temp];
					if (chksession (sp))
						sp->screen->attr = (((backs[back - 40] << 4) + (fores[fore - 30])) | 0x80);	/*lint !e701 !e734 */
				}
			} else
#endif
			{
#ifndef PATCURSES
				SYSback = back;
				SYSfore = fore;
#endif
#ifdef MSDOS
				setscreens (0, 0, 1);
#else
#ifdef PATCURSES
				setscreens (back, fore, 0);
#else
				setscreens (0, 0, 0);
#endif				
				textrefresh ();
#endif
			}
		}
	}
	return 0;
}



void
setscreens (int back OPTIONAL, int fore OPTIONAL, int clr OPTIONAL)
{
int resetstatline = 0;

	if (!back && !fore)	{	/* if both black, use system colors */
		back = SYSback;
		fore = SYSfore;
#ifdef MSDOS
		back = backs[back - 40];
		fore = fores[fore - 30];
#endif
		resetstatline = 1;
	}

#ifdef PATCURSES
	/* reinit colors if back or fore change */
	if (SYSback != back || SYSfore != fore) {
		SYSback = back;
		SYSfore = fore;
		(void) init_pairs();
	}
#endif
	textbackground (back);
	textcolor (fore);
	textattr ((back << 4) | fore);		/*lint !e701 */

	if (clr)	{
		clrscr ();
		if (resetstatline && STATLINE)	{
			displayStatLine (1, 1, 0);
			displayStatLine (-1, 1, 0);
		}
	}
}


#ifdef DEMO
void
main (argc, argv)
int argc;
char *argv[];
{
	last[0] = last[1] = 0;
	if (argc == 1)
		exit (0);
	colorfile (argv[1], last);
}
#endif

