/*************************************************************************
*	for sz or rz
*************************************************************************/

#include	<stdio.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	<ctype.h>
#include	<string.h>
#include	<time.h>
#include	<setjmp.h>
#ifdef	__HIGHC__
#	include	<msdos.cf>
#	include	<heap.cf>
#endif

#include	<sidework.h>
#include	<loader.h>
#include	<egb.h>
#include	<mos.h>
#include	<snd.h>

#include	<cnslib.h>
#include	<dialog.h>
#include	<doscons.h>
#include	<dta.h>
#include	<dtaname.h>
#include	<egbmacro.h>
#include	<event.h>
#include	<fslib.h>
#include	<keycode.h>
#include	<kyb.h>
#include	<menu.h>
#include	<moscur.h>
#include	<sbar.h>
#include	<setint.h>
#include	<spicon.h>

#include	"usrlib.h"
#include	"rsctrl.h"
#include	"flib.h"
#define	_MSGDAT_DEFINE
#include	"msgdat.h"

static	jmp_buf		JmpBuf;

static	DLG_T		*Dlg = NULL;
static	CNS_T		*Cns = NULL;
static	EVT_T		*Evt = NULL;
static	SBAR_T		*SbV = NULL;

#define				CNS_XS		(80)
#define				CNS_YS		(24)
#define				DLG_XS		(   4 + CNS_XS* 6 + 2+16+4)
#define				DLG_YS		(20+4 + CNS_YS*12 + 4)

int		RsPort   = 0;
int		RsBaud   = -1;
int		RsMd     = -1;
int		CtrlX    = FALSE;
int		QuickRet = FALSE;

#if	1
static				int		Ch;
static				UINT	Ec;
#define				BREAK_CHECK()	{						\
	Ch = EVT_getkey( &Ec );									\
	if ( Ch == 3 || (Ec&0xFF14) == (KA_C|KA_BIT_CTRL) )		\
		userbreak(1);										\
}
#else
#define				BREAK_CHECK()
#endif

static CONST char	RECODENAME_MAINARG[] = DTA_RECODENAME_MAINARG;
static CONST char	RECODENAME_DSPCTRL[] = DTA_RECODENAME_DSPCTRL;
DTACTRL_T			*DtaCtrl = NULL;

#define	MAIN_EVT_CANCEL	(9999)

static	PLT_RGB	PltDat[16] =
{
	/* G R  B								*/
	{ 0, 0, 0},	/* C_BALCK					*/
	{ 0, 0, 0},	/* C_BLUE or C_THROUGH		*/
	{ 7, 7, 8},	/* C_RED					*/
	{12,12,13},	/* C_MAGENTA				*/
	{ 6, 5, 7},	/* C_GREEN					*/
	{ 8, 7, 9},	/* C_CYAN					*/
	{10, 9,11},	/* C_YELLOW					*/
	{11,11,12},	/* C_WHITE					*/

	{ 5, 5, 6},	/* C_HBALCK					*/
	{ 0, 0,11},	/* C_HBLUE					*/
	{ 0,11, 0},	/* C_HRED					*/
	{ 0,11,11},	/* C_HMAGENTA				*/
	{11, 0, 0},	/* C_HGEEN					*/
	{11, 0,11},	/* C_HCYAN					*/
	{11,11, 0},	/* C_HYELLOW				*/
	{14,14,15}	/* C_HWHITE					*/
};

void	userbreak(int level)
{
	extern	void	signal_func(int level);
	signal_func( level );
}

static int	ExitLevel = 0;

void	userexit(int level)
{
	ExitLevel = level;
	longjmp(JmpBuf, 1);
}

void	USR_dspFlush(void)
{
	SbV->top = Cns->dspPos.lnD;
	SbV->dsp = Cns->dspYm;
	SbV->min = 0;
	SbV->max = Cns->linMaxD;
	SBAR_Vredraw(SbV);
}

int		USR_putc( int ch )
{
	BREAK_CHECK();

	ch &= 0xFF;
	if ( ch == '\n' )
	{
		CNS_puts( Cns,"\r\n");
		USR_dspFlush();
	} else
		CNS_putc( Cns, ch );
	return (ch);
}

int		USR_fputc( int ch, FILE *fp )
{
	ch &= 0xFF;

	if ( fp )
	{
		if ( fp == stdout || fp == stderr )
			return USR_putc( ch );
		else
			return fputc( ch, fp );
	}
}

void	USR_puts( CONST char *s )
{
	BREAK_CHECK();

	while ( *s )
	{
		if ( *s == '\n' )
		{
			CNS_puts( Cns, "\r\n" );
		} else
		{
			CNS_putc( Cns, *s );
		}
		++s;
	}
	USR_dspFlush();
}

void	USR_fputs( CONST char *s, FILE *fp )
{
	if ( fp )
	{
		if ( fp == stdout || fp == stderr )
			USR_puts( s );
		else
			fputs( s, fp );
	}
}

void	USR_printf( CONST char *form, ... )
{
	va_list		arg;
	char		tmp[BUFSIZ];

	va_start( arg, form );
	vsprintf( tmp, form, arg );
	va_end(arg);

	USR_puts( tmp );
}

void	USR_fprintf( FILE *fp, CONST char *form, ... )
{
	va_list		arg;
	char		tmp[BUFSIZ];

	va_start( arg, form );
	vsprintf( tmp, form, arg );
	va_end();

	if ( fp )
	{
		if ( fp == stdout || fp == stderr )
			USR_puts( tmp );
		else
			fputs( tmp, fp );
	}
}

int		USR_getch(void)
{
	int		ch;
	UINT	ec;

	if ( (ch = EVT_getkey( &ec )) == 0xFFFF )
		return (0);
	else
	{
		if ( ch == 3 || (ec&0xFF14) == (KA_C|KA_BIT_CTRL) )
			userbreak(0);
		return (ch & 0xFF);
	}
}

static	void	dspFunc( DLG_T *dlg )
{
	int		evtPos = 0;
	int		x1 = dlg->fr.x0;
	int		y1 = dlg->fr.y0;
	int		x2 = x1 + dlg->fr.xs - 1;
//	int		y2 = y1 + dlg->fr.ys - 1;
	int		cx1, cy1, cx2, cy2;

	boxfHol( x1+2, y1+2, x2-2, y1+2+18, PSET, C_WHITE, C_HWHITE, C_DARK );
	DSP_str( x1+4, y1+4, C_MBLACK, C_WHITE, 16,
	    "%s file(s) with ZMODEM/YMODEM/XMODEM Protocol",
#ifdef	_SZ
		"Send",
#else
		"Receive",
#endif
	    MAIN_VER );

	/*	[EXIT]ボタン	--------------------------------------------*/
	{
		CONST int	x = x2 - 18;
		CONST int	y = y1 + 3;
		EGB_writeMode( EgbPtr, OPAQUE );
		EGB_paintMode( EgbPtr, 0x022);
		EGB_color( EgbPtr, 0, C_DARK );
		EGB_color( EgbPtr, 1, C_WHITE );
		_EGB_PUTBLOCKCOLOR(0, x, y, x+15, y+15, getds(), _icn16x16_closeBtn );
		boxHol( x, y, x+15, y+15, PSET, C_HWHITE, C_DARK );
		_EVT_SETMOS( Evt, evtPos++, MAIN_EVT_CANCEL, MOSEVT_BTN, BTN_LEFT,
		    x, y, x+15, y+15, 0, NULL );
   }

	/*	ダイアログ移動用	----------------------------------------*/
	_EVT_SETMOS( Evt, evtPos++, 0, MOSEVT_NOACT|MOSEVT_QUICK, BTN_LEFT,
	    x1+2, y1+2, x2-2, y1+2+18, DLG_defMoveFunc, dlg );

	/* コンソール領域	*/
	cx1 = x1+4;
	cy1 = y1+24;
	cx2 = x1 + 4 + CNS_XS* 6 - 1;
	cy2 = y1 +24 + CNS_YS*12 - 1;

	box( cx1-1, cy1-1, cx2+1, cy2+1, PSET, C_WHITE );
	box( cx1-2, cy1-2, cx2+2, cy2+2, PSET, C_DARK  );
	CNS_changeScnSize( Cns, cx1, cy1, cx2, cy2 );
	CNS_flush( Cns, ERR, ERR);

	/* スクロールバー	*/
	SBAR_Vdsp( SbV, cx2+5, cy1, 16, cy2-cy1+1 );
	USR_dspFlush();
}

static int		funcSbarV( int evtNo, SBAR_T *sbV )
{
	CNS_T	*cns = Cns;

	if ( cns->linMaxD < cns->dspYm )
	{
		sbV->top = 0;
		return (0);
	} else if ( sbV->top > cns->homeY )
		sbV->top = cns->homeY;

	switch( evtNo )
	{
		case	SBEVT_SLIDE:
			MOS_DEC();
			CNS_jump( cns, sbV->top );
			MOS_INC();
			break;
		case	SBEVT_INC:
			if ( sbV->top <= cns->homeY )
			{
				MOS_DEC();
				CNS_nextLine( cns, 1 );
				MOS_INC();
			}
			break;
		case	SBEVT_DEC:
			MOS_DEC();
			CNS_prevLine( cns, 1 );
			MOS_INC();
			break;
	}
	return (0);
}


static	int		dsp_init(void)
{
	/* イベント用	*/
	Evt = EVT_alloc(NULL,8);
	SbV = SBAR_Vopen(Evt, funcSbarV, NULL );
	Cns = CNS_open();

	/* ダイアログオープン	*/
	Dlg = DLG_open( DLGPOS_CENTER_OF_SCN, DLGPOS_CENTER_OF_SCN,
	    DLG_XS, DLG_YS, C_DLGBASE, dspFunc, NULL );
	if ( Evt == NULL || SbV == NULL || Dlg == NULL || Cns == NULL )
		return (ERR);
	Cns->page = DspCtrl.writePage;
	SbV->attr |= (SBATT_SLIDEQUICK | SBATT_MAXADJUST);
	DLG_dsp(Dlg);

	return (NORMAL);
}

void	dsp_term(void)
{
	if ( Cns )
	{
		CNS_close( Cns );
		Cns = NULL;
	}
	if ( Dlg )
	{
		DLG_close( Dlg );
		Dlg = NULL;
	}
}


static	void	hit_any_key(void)
{
	int		ch;
	UINT	ec;

	USR_puts("\n**** Hit any key *****\n");
	MOS_curType(MOSCUR_NORMAL);
	MOS_CON();

	LOOP
	{
		int		ret;

		USR_dspFlush();

		if ( (ret = EVT_chk(Evt,EVTIGN_KEY)) >= 0 )
		{
			if ( ret == MAIN_EVT_CANCEL )
				break;
		} else
		{
			ch = EVT_getkey(&ec);
			if ( ch != 0xFFFF || (ec & 0xFF00) != 0xFF00 )
			{	ec &= 0xFF14;
				switch( ec )
				{
					case	KA_UP:
					case	KA_W|KA_BIT_CTRL:
					case	KA_PREV:
						MOS_DEC();
						CNS_prevLine( Cns, 1 );
						MOS_INC();
						break;
					case	KA_DOWN:
					case	KA_Z|KA_BIT_CTRL:
					case	KA_NEXT:
						MOS_DEC();
						CNS_nextLine( Cns, 1 );
						MOS_INC();
						break;
					case	KA_UP|KA_BIT_SHIFT:
					case	KA_R|KA_BIT_CTRL:
						MOS_DEC();
						CNS_prevLine( Cns, Cns->dspYm );
						MOS_INC();
						break;
					case	KA_DOWN|KA_BIT_SHIFT:
					case	KA_C|KA_BIT_CTRL:
						MOS_DEC();
						CNS_nextLine( Cns, Cns->dspYm );
						MOS_INC();
						break;
					default:
						goto	LOOP_EXIT;
				}
			} else
				EVT_idl();
		}
	}
LOOP_EXIT:
	return;
}

/*************************************************************************
*	システム初期化
*************************************************************************/
static	int		init( int *argc, char **argv[], int _argc, char **_argv )
{
	DSPCTRL		*dsp = NULL;
	DTARECODE_T	*dsp_recode = NULL;
	DTARECODE_T	*arg_recode = NULL;

#ifdef	__HIGHC__
	/* メモリ取得用設定	*/
	Init_allocated_storage = 0;
#endif

	*argc = _argc;
	*argv = _argv;

	if ( DTA_isAtPcl() )
	{
		/* 子プロセス起動	*/
		CONST char		*args = PROG_EXP;

		if ( (DtaCtrl = DTA_openCheck()) != NULL )
		{
			if ( (dsp_recode = DTA_openRecode( DtaCtrl, RECODENAME_DSPCTRL)) != NULL )
			{	/* 表示システムの情報あり	*/
				dsp = dsp_recode->ptr;
			}
			if ( (arg_recode = DTA_openRecode( DtaCtrl, RECODENAME_MAINARG)) != NULL )
			{	/* パラメータの指定あり	*/
				args = arg_recode->ptr;
			}
		}
		if ( (*argc = FS_argSet( args, argv )) < 1 )
			return (ERR);
	}

	set_ctrl_c();
	set24h();

	/* 表示システム初期化	*/
	if ( DSP_pcl_sysInit( dsp ) )
		return	(ERR);

	MosInf.scrollPage = 0xFF;		/* スクロールなし	*/

	DSP_set_defFnt( FNTYPE_USR1 );
	GetFnt12Ptr(0);				/* ank font 12 初期設定		*/
	KBF_sysInit();				/* キーボードシステム初期化	*/
	KBF_kan_off();				/* かな漢字変換禁止			*/
	RS_init();
	sdk_control(0);				/* サイドワーク起動禁止		*/

	/* パレット設定	*/
	if ( dsp == NULL )
		DSP_setPlt(PltDat);

#if	0
	/* 起動ディレクトリの設定	*/
	if ( FS_setStartPath( StartPath, *argv[0] ) )
		return (ERR);

	/* CCI システム初期化	*/
	if ( CCI_init( CodeSize, HeepSize) )
		return (ERR);
#endif

	return (NORMAL);
}

static	void	term(int errLevel)
{
	if ( DtaCtrl )
	{
		if ( DtaCtrl->head )
			DtaCtrl->head->ret = errLevel;
		DTA_flush( DtaCtrl );
		DTA_freeCtrl( DtaCtrl );
		DtaCtrl = NULL;
	}

	RS_end();
	KBF_sysEnd();
	DSP_sysEnd();

	reset24h();
}

static	int		is_rsspeed( int spd )
{
	return ( spd ==  300 || spd ==  600 || spd ==  1200 || spd == 2400
	  || spd == 4800 || spd == 9600 || spd == 19200 );
}
static	int		get_baud(int spd)
{
	switch( spd )
	{
		case   300:	return RSBAUD_300;
		case   600:	return RSBAUD_600;
		case  1200:	return RSBAUD_1200;
		case  2400:	return RSBAUD_2400;
		case  4800:	return RSBAUD_4800;
		case  9600:	return RSBAUD_9600;
		case 19200:	return RSBAUD_19200;
		case 38400:	return RSBAUD_38400;
		default:	return (-1);
	}

}

/*************************************************************************
*	オプションパラメータの解析
*************************************************************************/
static	int		dec_opt( int *argc, char **argv[], int _argc, char **_argv )
{
	int		i, pos;
	char	**av;

	if ( _argc < 1 )
		return (ERR);

	if ( (av = calloc(sizeof(char *),_argc)) == NULL )
		return (ERR);
	*argv = av;
	av[0] = _argv[0];
	*argc = 1;
	pos   = 1;
	for ( i = 1; i < _argc; ++i )
	{
		char	*s;

		s = _argv[i];
		if ( *s != '$' )
		{
			av[pos++] = s;
			++(*argc);
			continue;
		}
		/* オプションデコード	*/
		++s;
		if ( *s != '-' )
		{	/* プログラム名	*/
			av[0] = s;
		} else
		{
			++s;	/* skip '-' */
			switch ( toupper(*s) )
			{
				case 'Q':
				{
					QuickRet = TRUE;
					break;
				}
				case 'E':	/* 実行スピード		*/
				{
					int					speed;
					extern	unsigned	Effbaud;
					++s;
					speed = atoi(s);
					if ( is_rsspeed(speed) )
						Effbaud =~ speed;
					break;
				}
				case 'B':	/* Baud（シリアルスピード）	*/
				{
					++s;
					RsBaud = get_baud( atoi(s) );
					break;
				}
				case 'M':	/* 通信モード	*/
				{
					int		md;
					md = 0;
					++s;
					while ( *s )
					{
						switch ( toupper(*s) )
						{
							case '7':	md &= (~RSMD_BIT_8);
							case '8':	md |=  RSMD_BIT_8;
							case 'N':	md &= ~(RSMD_PARITY);	break;
							case 'O':	md |= (RSMD_PARITY);	break;
							case 'E':	md |= (RSMD_PARITY|RSMD_PARITY_EVEN);	break;
							case '1':	md &= (~RSMD_STOPBIT_2);
							case '2':	md |=   RSMD_STOPBIT_2;
						}
						++s;
					}
					RsMd = md;
					break;
				}
			}
		}
	}
	return (NORMAL);
}

void	main(int _argc, char *_argv[])
{
	int			ret;
	int 		argc;
	char		**argv;

	if ( init(&argc,&argv,_argc,_argv) )
	{
		ret = 1;
	} else
	{
		if ( dsp_init() )
		{
			ret = 1;
		} else
		{
			int		i;

			if ( (i = setjmp(JmpBuf)) > 0 )
			{
				ret = i;
				goto END_EXIT;
			}
			{
				int 		ac;
				char		**av;
			
				if ( dec_opt(&ac,&av,argc,argv) == NORMAL )
					zm_main(ac,av);
				ret = 0;
			}
END_EXIT:
			if ( !QuickRet )
				hit_any_key();
			dsp_term();
		}
		term(ret);
	}
	FM_all_fclose();
	pcl_exit(0);
	exit(ret);
}
