/******************************************************************************
 * This file is part of a software distribution, which is furnished under the *
 * terms of a license.  Use of this software  by any means is subject to this *
 * license  and  signifies  the  acceptance of  the  licensing  terms  stated *
 * therein. Please see  the file LICENSE in the  top-level directory  of this *
 * software  distribution  for detailed copyright  disclaimers  and licensing *
 * terms.                                                                     *
 ******************************************************************************
 * Copryight (c) by Andreas S. Wetzel - All rights reserved.                  *
 ******************************************************************************/

/* $Id: screen.c,v 1.2 2001/03/19 14:54:01 mickey Exp $ */

#include <vchat.h>
#include <proto_common.h>

#include <sys/ioctl.h>

/*** Globals ***/

#define	PADTIME	1

int in_chat_window = 0;

/*** Externals ***/

extern char nlstr[];

extern VP vp;
extern ED *ed;
extern VTCAP vtcap;

/*** Code ***/

void screen_init(void)
{
	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	cls();

	update_status(1);

	scroll_reg(1, vtcap.rows - 2);

	mv(1, vtcap.rows);

	in_chat_window = 0;

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));
}

void cprintf(int win, char *fmt, ...)
{
	va_list ap;

	u_int strindex;
	u_int space;
	u_int in_line;
	u_int wrapdist;
	u_int indent;

	int fg;
	int bg;

	unsigned char c; 
	unsigned char x;

	unsigned char tmp[SVMSGBUF];

	/*
	 * Lockout all signals that may annoy us here
	 */

	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	pbc_disable();

	va_start(ap, fmt);

	vsprintf(tmp, fmt, ap);

	tmp[SVMSGBUF - 1] = '\0';

	/*
	 * Compute number of
	 * columns to indent
	 */

	strindex = wrapdist = space = in_line = indent = 0;

	if(vp.indent && tmp[0] == '(')
	{ 
		int i;
		int flg = 0;
		int sz = 1;

		for(i = 1; i < 20; i++)
		{
			if(tmp[i] == ')')	/*** LEFT BRACKET ***/
			{
				++sz;
				flg |= 0x01;
			}
			else if(tmp[i] == CSI)	/*** CSI ***/
			{
				flg |= 0x02;
			}
			else if(flg & 0x02)	/*** TEXT ATTRIBUTE ***/
			{
				flg &= ~0x02;
			}
			else if(tmp[i] == ' ' && flg)	/*** FINAL SPACE ***/
			{
				indent = ++sz;
				break;
			}
			else if(tmp[i] == ' ' || tmp[i] == '\n' || tmp[i] == '\0')
			{
				sz = 0;
				break;
			}
			else				/*** TEXT ***/
			{
				++sz;
				flg &= ~0x01;
			}
		}
	}

	/*
	 * Do word wrapping
	 */

	if(vp.word_wrap && win == chat)
	{
		strindex = in_line = space = wrapdist = 0;

		while(tmp[strindex] != '\0')
		{
			switch(tmp[strindex])
			{
				case CSI:	strindex += 2;
						break;
				case ' ':	space = strindex++;
						wrapdist = 0;
						++in_line;
						break;
				case '\n':	space = wrapdist = 0;
						in_line = indent;
						++strindex;
						break;
				default:	++strindex;
						++in_line;
						++wrapdist;
						break;
			}

			/*
			 * Will we have to wrap the line?
			 */

			if(in_line > (vtcap.cols - 1))
			{
				/*
				 * If we have a space in the current line
				 * and the distance of the space relative
				 * to the current position is less or equal
				 * than one third of the total columns of
				 * a display line, wrap this line at the
				 * space. Otherwise simply break the line
				 * at the current position.
				 */

				if(space > 0 && wrapdist <= (vtcap.cols / 3))
				{
					tmp[space] = '\n';
					in_line = (wrapdist + indent);
				}
				else
				{
					wrapdist = in_line = 0;
				}	

				space = 0;
			}
		}
	}

	strindex = 0;

	/*
	 * Output string in window
	 */

	if(win == chat)
	{
		if(!in_chat_window)
		{
			mv(1, vtcap.rows - 2);
			in_chat_window = 0xff;
		}	

		printf("%s", nlstr);

		if(vp.logswitch)
		{
			fprintf(vp.logfl, "%s", nlstr);
			vp.logcnt += strlen(nlstr);
		}
	}

	while((c = tmp[strindex++]) != '\0')
	{
		switch(c)
		{
			case CSI:	x = tmp[strindex++];

					if((fg = (x >= C_FG_BLK && x <= C_FG_WHT) ? (x - C_FG_BLK) : -1) != -1)
					{
						if(HAS_COLOR)
						{
							if(vtcap.bold && vp.hicolor)
								tputs(vtcap.bold, 1, (void *)outc);

							printf("%s", tparm(vtcap.set_fg_color, fg));
						}
						else
						{
							switch(fg)
							{
								case 2:		if(vtcap.dim)
											tputs(vtcap.dim, 1, (void *)outc);
										else if(vtcap.bold)
											tputs(vtcap.bold, 1, (void *)outc);
										break;
								case 3:		if(vtcap.bold)
											tputs(vtcap.bold, 1, (void *)outc);
										else if(vtcap.underline)
											tputs(vtcap.underline, 1, (void *)outc);
										break;
								default:	break;
							}
						}
					}
					else if((bg = (x >= C_BG_BLK && x <= C_BG_WHT) ? (x - C_BG_BLK) : -1) != -1)
					{
						if(HAS_COLOR)
						{
							if(vtcap.bold && vp.hicolor)
								tputs(vtcap.bold, 1, (void *)outc);

							printf("%s", tparm(vtcap.set_bg_color, bg));
						}
						else
						{
							if(bg == 4)
							{
								if(vtcap.reverse)
									tputs(vtcap.reverse, 1, (void *)outc);
							}
						}

					}
					else if(x == C_OFF && vtcap.off)
						tputs(vtcap.off, 1, (void *)outc);
					else if(x == C_BOLD && vtcap.bold)
						tputs(vtcap.bold, 1, (void *)outc);
					else if(x == C_UL && vtcap.underline)
						tputs(vtcap.underline, 1, (void *)outc);
					else if(x == C_DIM && vtcap.dim)
						tputs(vtcap.dim, 1, (void *)outc);
					else if(x == C_BLINK && vtcap.blink)
						tputs(vtcap.blink, 1, (void *)outc);

					break;
			case '\n':	printf("%s", nlstr);

					if(vp.logswitch && win == chat)
					{
						fprintf(vp.logfl, "%s", nlstr);
						vp.logcnt += strlen(nlstr);
						fflush(vp.logfl);
					}

					vsleep(0, PADTIME);

					if(tmp[strindex] != '\0' && indent)
					{
						printf("%*s", indent, " ");

						if(vp.logswitch && win == chat)
						{
							fprintf(vp.logfl, "%*s", indent, " ");
							vp.logcnt += indent;
						}
					}

					break;
			default:	putchar(c);

					if(vp.logswitch && win == chat)
					{
						fprintf(vp.logfl, "%c", c);
						++vp.logcnt;
					}

					break;
		}
	}

	pbc_enable();
	va_end(ap);

	/*
	 * Release locked out signals
	 */

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));

	if(vp.logswitch)
		fflush(vp.logfl);
}

void cputnchars(u_char *buf, size_t size)
{
	u_int strindex;
	u_int space;
	u_int in_line;
	u_int wrapdist;
	u_int indent = 0;

	int fg;
	int bg;

	unsigned char c; 
	unsigned char x;

	/*
	 * Lockout all signals that may annoy us here
	 */

	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	pbc_disable();

	/*
	 * Compute number of
	 * columns to indent
	 */

	strindex = in_line = indent = 0;

	if(vp.indent && *buf == '(')
	{
		int i;
		u_char sz = 1;
		u_char flg = 0;

		for(i = 1; i < (size <= 20) ? size : 20; i++)
		{
			if(*(buf + i) == ')')		/*** LEFT BRACKET ***/
			{
				++sz;
				flg |= 0x01;
			}
			else if(*(buf + i) == CSI)	/*** CSI ***/
			{
				flg |= 0x02;
			}
			else if(flg & 0x02)		/*** TEXT ATTRIBUTE ***/
			{
				flg &= ~0x02;
			}
			else if(*(buf + i) == ' ' && flg)	/*** FINAL SPACE ***/
			{
				indent = ++sz;
				break;
			}
			else if(*(buf + i) == ' ' || *(buf + i) == '\n' || *(buf + i) == '\0')
			{
				sz = 0;
				break;
			}
			else			/*** TEXT ***/
			{
				++sz;
				flg &= ~0x01;
			}
		}
	}

	/*
	 * Do word wrapping
	 */

	if(vp.word_wrap)
	{
		strindex = in_line = space = wrapdist = 0;

		while(strindex < size)
		{
			switch(*(buf + strindex))
			{
				case CSI:	strindex += 2;
						break;
				case ' ':	space = strindex++;
						wrapdist = 0;
						++in_line;
						break;
				case '\n':	space = wrapdist = 0;
						in_line = indent;
						++strindex;
						break;
				default:	++strindex;
						++in_line;
						++wrapdist;
						break;
			}

			/*
			 * Will we have to wrap the line at this point?
			 */

			if(in_line > (vtcap.cols - 1))
			{
				/*
				 * If we have a space in the current line
				 * and the distance of the space relative
				 * to the current position is less or equal
				 * than one third of the total columns of
				 * a display line, wrap this line at the
				 * space. Otherwise simply break the line
				 * at the current position.
				 */

				if(space > 0 && wrapdist <= (vtcap.cols / 3))
				{	
					*(buf + space) = '\n';
					in_line = (wrapdist + indent);
				}
				else
				{
					wrapdist = in_line = 0;
				}	

				space = 0;
			}
		}
	}

	strindex = 0;

	/*
	 * Output string in window
	 */

	if(!in_chat_window)
	{
		mv(1, vtcap.rows - 2);
		in_chat_window = 0xff;
	}	

	printf("%s", nlstr);

	if(vp.logswitch)
	{
		fprintf(vp.logfl, "%s", nlstr);
		vp.logcnt += strlen(nlstr);
	}

	while(strindex < size)
	{
		c = *(buf + strindex++);

		switch(c)
		{
			case CSI:	x = *(buf + strindex++);

					if((fg = (x >= C_FG_BLK && x <= C_FG_WHT) ? (x - C_FG_BLK) : -1) != -1)
					{
						if(HAS_COLOR)
						{
							if(vtcap.bold && vp.hicolor)
								tputs(vtcap.bold, 1, (void *)outc);

							tputs(tparm(vtcap.set_fg_color, fg), 1, (void *)outc);
						}
						else
						{
							switch(fg)
							{
								case 2:		if(vtcap.dim)
											tputs(vtcap.dim, 1, (void *)outc);
										else if(vtcap.bold)
											tputs(vtcap.bold, 1, (void *)outc);
										break;
								case 3:		if(vtcap.bold)
											tputs(vtcap.bold, 1, (void *)outc);
										else if(vtcap.underline)
											tputs(vtcap.underline, 1, (void *)outc);
										break;
								default:	break;
							}
						}
					}
					else if((bg = (x >= C_BG_BLK && x <= C_BG_WHT) ? (x - C_BG_BLK) : -1) != -1)
					{
						if(HAS_COLOR)
						{
							if(vtcap.bold && vp.hicolor)
								tputs(vtcap.bold, 1, (void *)outc);

							tputs(tparm(vtcap.set_bg_color, bg), 1, (void *)outc);
						}
						else
						{
							if(bg == 4)
							{
								if(vtcap.reverse)
									tputs(vtcap.reverse, 1, (void *)outc);
							}
						}

					}
					else if(x == C_OFF && vtcap.off)
						tputs(vtcap.off, 1, (void *)outc);
					else if(x == C_BOLD && vtcap.bold)
						tputs(vtcap.bold, 1, (void *)outc);
					else if(x == C_UL && vtcap.underline)
						tputs(vtcap.underline, 1, (void *)outc);
					else if(x == C_DIM && vtcap.dim)
						tputs(vtcap.dim, 1, (void *)outc);
					else if(x == C_BLINK && vtcap.blink)
						tputs(vtcap.blink, 1, (void *)outc);

					break;
			case '\n':	printf("%s", nlstr);

					if(vp.logswitch)
					{
						fprintf(vp.logfl, "%s", nlstr);
						vp.logcnt += strlen(nlstr);
						fflush(vp.logfl);
					}

					vsleep(0, PADTIME);

					if(strindex < size && indent)
					{
						printf("%*s", indent, " ");

						if(vp.logswitch)
						{
							fprintf(vp.logfl, "%*s", indent, " ");
							vp.logcnt += indent;
						}
					}

					break;
			default:	putchar(c);

					if(vp.logswitch)
					{
						fprintf(vp.logfl, "%c", c);
						++vp.logcnt;
					}

					break;
		}
	}

	pbc_enable();

	/*
	 * Release locked out signals
	 */

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));

	if(vp.logswitch)
		fflush(vp.logfl);
}

int real_len(char *s)
{
	int ret = 0;
	u_char c;

	while((c = *s++) != '\0')
	{
		if(c == CSI)
		{
			++s;
		}
		else
		{
			++ret;
		}
	}

	return(ret);
}

/*
 *
 * Low level screen functions
 *
 */

int outc(u_char x)
{
	putchar(x);
	return(0);
}

void mv(int x, int y)
{
	--x;
	--y;

	tputs((char *)tgoto(vtcap.pos, x, y), 1, (void *)outc);
}

void cls(void)
{
	tputs(vtcap.cls, 1, (void *)outc);
}

void keymode(int which)
{
	if(vtcap.ck_app && vtcap.ck_pos)
	{
		switch(which)
		{
			case 0x1:	tputs(vtcap.ck_app, 1, (void *)outc);
					break;
			default:	tputs(vtcap.ck_pos, 1, (void *)outc);
					break;
		}
	}
}

void scroll_reg(int start, int ende)
{
	--start;
	--ende;

	printf("%s", tparm(vtcap.scr_reg, start, ende));
}

void put_back_cursor(void)
{
	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	pbc_disable();

	if(in_chat_window)
	{
		mv(ED_SCRPOS, vtcap.rows);
		in_chat_window = 0;
	}

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));
}

void clear_input(void)
{
	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	mv(1, vtcap.rows);

	in_chat_window = 0;

	if(vtcap.clear2eol)
		tputs(vtcap.clear2eol, 1, (void *)outc);
	else if(vtcap.clear2eod)
		tputs(vtcap.clear2eod, 1, (void *)outc);

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));
}


syntax highlighted by Code2HTML, v. 0.9.1