#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <egb.h>
#include "symbol.h"

#define	ON		1
#define	OFF		0
#define	S_INT	1
#define	US_INT	2
#define	L_INT	3
#define	UL_INT	4
#define	CHAR	5
#define	POINTER	6
#define	ERR		1
#define	NOERR	0

static char	*egbwork;
static int	basex,basey;
static int	fcolor,bcolor;
static int	line,wide;
static int	cx,cy;
static char	*his[30];
static int	hisofs;
static char hisdata[30][81];
static va_list	ap;

typedef union
{
	short int	s;
	long int	l;
	unsigned short int	us;
	unsigned long int	ul;
	char	c;
	void	*p;
} VALUE;

static void	waitVsync()
{
	char	para[16];
	DWORD( para + 0 ) = 0;
	EGB_palette( egbwork, 1, para );
	return;
}

static void	boxpaint()
{
	EGB_writeMode( egbwork, 0 );
	EGB_foreColor( egbwork, bcolor );
	EGB_paintColor( egbwork, bcolor );
	EGB_paintMode( egbwork, 0x22 );
	waitVsync();
	EGB_box( egbwork, basex, basey, basex+wide*8, basey+line*16 );
	return;
}

void	VC_cls()
{
	boxpaint();
	cx = cy = 0;
	return;
}

void	VC_setWriteColor( int c )
{
	fcolor = c;
	return;
}

void	VC_setBackColor( int c )
{
	bcolor = c;
	return;
}

void	VC_locate( int x, int y )
{
	cx = x;
	cy = y;
	return;
}

void	VC_init( char *work, int bx, int by, int w, int l, int fc, int bc )
{
	int		i;
	egbwork = work;
	basex = bx;
	basey = by;
	wide = w;
	line = l;
	for( i=0; i<30; i++ )
		his[i] = hisdata[i];
	hisofs = 0;
	bcolor = bc;
	fcolor = fc;
	cx = cy = 0;
	boxpaint();
	for( i=0; i<line; i++ )
		*(hisdata[i]) = 0;

	return;
}

static void	nextline()
{
	char	para[128];
	int		i,j;

	++ cy;
	cx = 0;

	*(his[hisofs]) = 0;
	his[hisofs] = hisdata[hisofs];
	hisofs = (++ hisofs) % line;
	*(his[hisofs]) = 0;
	if( cy >= line )
	{
		-- cy;
		boxpaint();
		EGB_foreColor( egbwork, fcolor );
		EGB_paintMode( egbwork, 0x02 );
		j = hisofs;
		for( i=0; i<line; i++ )
		{
			j = (++ j) % line;
			symbol( egbwork, basex, basey + i * 16 + 15, his[j] );
		}
	}
	return;
}

static void	VC_puts( char *p, int l )
{
	char	para[128];
	int		i,j;

	if( l == 0 )
		return;
	i = strlen( p );
	if( l == -1 || i<l )
		l = i;
	while( cx+l > wide )
	{
		i = wide - cx;
		VC_puts( p, i );
		l -= i;
		p += i;
		nextline();
	}
	for( i=0; i<l; i++ )
	{
		if( *(p+i) == '\n' )
		{
			VC_puts( p, i );
			l -= i+1;
			p += i+1;
			i = -1;
			nextline();
		}
	}
	EGB_foreColor( egbwork, fcolor );
	EGB_paintMode( egbwork, 0x02 );
	strncpy( para+6, p, l );
	*(para+6+l) = 0;
	strncpy( his[hisofs], p, l );
	his[hisofs] += l;
	symbol( egbwork, basex + cx * 8, basey + cy * 16 + 15, para+6 );
	cx += l;
	return;
}

static int	valueToStrings( char *c )
{
	int		type,i,j;
	VALUE	val,d;

	type = va_arg( ap, int );
	switch( type )
	{
		case S_INT:	
			val.s = va_arg( ap, short int );
			if( val.s < 0 )
			{
				*c++ = '-';
				val.s = -val.s;
			}
			d.s = 10000;
			while( d.s )
			{
				if( val.s >= d.s || d.s == 1 )
				{
					i = ( val.s % ( d.s*10 ) ) / d.s;
					*c++ = '0' + i;
				}
				d.s /= 10;
			}
			break;
		case US_INT:
			val.us = va_arg( ap, unsigned short int );
			d.us = 10000;
			while( d.us )
			{
				if( val.us >= d.s || d.us == 1 )
				{
					i = ( val.us % ( d.us*10 ) ) / d.us;
					*c++ = '0' + i;
				}
				d.us /= 10;
			}
			break;
		case L_INT:
			val.l = va_arg( ap, long int );
			if( val.l < 0 )
			{
				*c++ = '-';
				val.l = -val.l;
			}
			d.l = 1000000000;
			while( d.l )
			{
				if( val.l >= d.l || d.l == 1 )
				{
					i = ( val.l % ( d.l*10 ) ) / d.l;
					*c++ = '0' + i;
				}
				d.l /= 10;
			}
			break;
		case UL_INT:
			val.ul = va_arg( ap, unsigned long int );
			d.ul = 1000000000;
			while( d.ul )
			{
				if( val.ul >= d.ul || d.ul == 1 )
				{
					i = ( val.ul % ( d.ul*10 ) ) / d.ul;
					*c++ = '0' + i;
				}
				d.ul /= 10;
			}
			break;
		case CHAR:
			val.c = va_arg( ap, char );
			d.c = 100;
			while( d.c )
			{
				if( val.c >= d.c || d.c == 1 )
				{
					i = ( val.c % ( d.c*10 ) ) / d.c;
					*c++ = '0' + i;
				}
				d.c /= 10;
			}
			break;
		default:
			return ERR;
	}
	*c = 0;
	return NOERR;
}

int		VC_printf( char *fmt, ... )
{
	int		type;
	int		comflag = OFF;
	VALUE	val;
	char	c[16];
	int		bufl = 0;

	va_start( ap, fmt );
/*	{FILE *fp;fp=fopen("out","a");fprintf(fp,"wide=%d\n",wide);fclose(fp);}*/

	while( *fmt )
	{
		if( *fmt == '%' )
		{
			++fmt;
			switch( *fmt )
			{
				case 'd':
					VC_puts( fmt-bufl-1, bufl );
					bufl = 0;
					if( valueToStrings( c ) )
						return ERR;
					VC_puts( c, -1 );
					comflag = ON;
					break;
				case 's':
					VC_puts( fmt-bufl-1, bufl );
					bufl = 0;
					type = va_arg( ap, int );
					if( type != POINTER )
						return ERR;
					val.p = va_arg( ap, void * );
					VC_puts( val.p, -1 );
					comflag = ON;
					break;
			}
			if( comflag == ON )
			{
				comflag = OFF;
				++fmt;
				continue;
			}
		}
		if( *fmt == '\n' )
		{
			VC_puts( fmt-bufl, bufl );
			bufl = -1;
			nextline();
		}
		++fmt;
		++bufl;
	}
	VC_puts( fmt-bufl, bufl );
	va_end( ap );
	return;
}

