/*
	ARTemis (Graphic Editor for FM-TOWNS)
	(c) MATSUUCHI Ryosuke 1992

	sub2.c

	ctox				16進文字を数値に変換

	putmsg_width		一定幅によるメッセージ出力
	dispAttentionMsg	注意メッセージ表示
	check_yes_no		確認入力

	ms_get				マウス入力
	ms_record_start		マウス動作記録開始
	ms_record_end		マウス動作記録終了
	ms_play_start		マウス動作再生開始

	commandMsPlay		マウス動作再生開始コマンド
	commandMsRec		マウス動作記録開始コマンド
	commandMsRecStop	マウス動作記録終了コマンド

	moscsr_timer		タイマー形状のマウスカーソルパターンへのポインタ

	set_intfunc			一定時間ごとに呼び出す関数の登録
	clr_intfunc			　　　　　　〃　　　　　　　取消
*/

#include <stdio.h>
#include <ctype.h>
#include <mos.h>
#include <malloc.h>
#include <fmcfrb.h>
#include "ge.h"
#include "dispman.h"



int ctox(char c)
{
	if ('0'<=c && c<='9')
		return c-'0';
	else if ('a'<=c && c<='f')
		return c-'a'+10;
	else
		return c-'A'+10;
}


#define	MSG_XLEN	16*12
/*--------------------------------------------------------*/
/*                   注意メッセージ表示                   */
/*--------------------------------------------------------*/

// #define	itemOK	2

static void dspmsg();

#include "sub2.md"

void putmsg_width(int x, int y, int width, char *msg, int col)
{
	if (msg == NULL)
		return;
	x += 4;
	y += 4;
	char msgbuf[256],*sp;  int m;
	sp = msg;
	m = 0;
	while (*sp != 0)
	{
		if (*sp == '\n')
		{
			msgbuf[m] = 0;
			ARTputstr12(x,y,msgbuf,col,DMgetmenuplt(White));
			// grp_putstr(x+1,y,msgbuf,Black);
			y += 16;
			m = 0;
			sp++;
		}
		else if ((m+1) >= (width/6))
		{
			msgbuf[m] = 0;
			ARTputstr12(x,y,msgbuf,col,DMgetmenuplt(White));
			// ARTputstr12(x+1,y,msgbuf,Black);
			y += 16;
			m = 0;
		}
		else if (iskanji(*sp))
		{
			msgbuf[m] = *sp;
			msgbuf[m+1] = *(sp+1);
			m += 2;
			sp += 2;
		}
		else
		{
			msgbuf[m] = *sp;
			m++;
			sp++;
		}
	}
	if (m != 0)
	{
		msgbuf[m] = 0;
		ARTputstr12(x,y,msgbuf,col,DMgetmenuplt(White));
		// grp_putstr(x+1,y,msgbuf,Black);
	}
}

static char	*msg = NULL;

static void dspmsg(int x, int y)
{
	putmsg_width(x,y, MSG_XLEN, msg, DMgetmenuplt(Black));
}


void	dispAttentionMsg(char *_msg)
{
	msg = _msg;
	DMerasecsr();
	if (menu_dispxy(-2,-2, &attention) != 0)
		return;
	for (;;) {
		DMdispcsr(ms.x, ms.y);
		do {
			ms_get(&ms);
		} while (ms.dx==0 && ms.dy==0 && ms.btn1==OFF && ms.btn2==OFF && key_chk()==0);
		DMerasecsr();
		limitCsrPos();
		if (ms.btn1 == OFFON) {
			int a;
			a = menu_where(ms.x,ms.y,&attention, NULL,NULL,NULL);
			if (a == itemOK)
				break;
		} else if (ms.btn2 == OFFON)
			break;
	}
	menu_erase();
}


/*--------------------------------------------------------*/
/*                    確認メニュー表示                    */
/*--------------------------------------------------------*/


/*
#define	itemGo		2
#define	itemCancel	3
*/

int check_yes_no(char *_msg)
{
	int r;
	msg = _msg;
	DMerasecsr();
	if (menu_dispxy(-2,-2, &menu_yes_no) != 0)
		return -1;
	for (;;) {
		DMdispcsr(ms.x, ms.y);
		do
		{
			ms_get(&ms);
		} while (ms.dx==0 && ms.dy==0 && ms.btn1==OFF && ms.btn2==OFF && key_chk()==0);
		DMerasecsr();
		limitCsrPos();
		if (ms.btn1 == OFFON) {
			int a;
			a = menu_where(ms.x,ms.y,&menu_yes_no, NULL,NULL,NULL);
			if (a == itemGo)
				{ r = 0;  break; }
			else if (a == itemCancel)
				{ r = -1;  break; }
		}
		else if (ms.btn2 == OFFON)
			{ r = -1;  break; }
	}
	menu_erase();
	return r;
}


/*--------------------------------------------------------*/
/*                   マウスの動作の記録                   */
/*--------------------------------------------------------*/


#define	MSBUF	100		/* 記録領域の大きさ（キロバイト） */


static bool ms_recording = NO;
static bool ms_playing = NO;
static int  rec_time0 = 0;		// 記録を開始したときの MOS_getTime 値
static int  play_time0 = 0;		// 再生を開始したときの MOS_getTime 値
static MSDAT play_ms;			// 再生時のマウス状態記録用


typedef struct
{
	int			time;
	short int	x,y;	// マウス座標
	char		btn;	// 上位4ビット=左ボタン  下位4ビット=右ボタン
} ms_record;


static ms_record *msbuf = NULL;
static int msbuf_maxnum = 0;
static int msbuf_num = 0;		// 記録／再生時のカウンタ


static int alloc_msbuf()
// 0:正常終了
{
	if (msbuf == NULL)
	{
		if ((msbuf = malloc(1024*MSBUF)) == NULL)
		{
			dispAttentionMsg("マウス動作の記録のための記憶領域が不足しています");
			return -1;
		}
		msbuf_maxnum = (1024 * MSBUF) / sizeof(ms_record);
	}
	return 0;
}


void  ms_record_start()
{
	if (alloc_msbuf() == 0)
	{
		dispAttentionMsg("マウス動作記録開始");
		ms_recording = YES;
		rec_time0 = MOS_getTime();
		msbuf_num = 0;
	}
}


void ms_record_end()
{
	if (ms_recording)
	{
		msbuf[msbuf_num].time = -1;
		ms_recording = NO;
		dispAttentionMsg("マウス動作記録終了");
	}
}


void ms_play_start()
{
	if (alloc_msbuf() == 0)
	{
		dispAttentionMsg("マウス動作再生開始");
		play_ms = ms;
		ms_playing = YES;
		play_time0 = MOS_getTime();
		msbuf_num = 0;
	}
}


void  ms_get(MSDAT *ms)
{
	if (ms_playing)
	{
		rdmos(&play_ms);
		if (msbuf[msbuf_num].time == -1 || play_ms.btn1 == OFFON)
		{
			ms_playing = NO;
			ms->btn1 = ms->btn2 = OFF;
			dispAttentionMsg("マウス動作再生終了");
			/* goto _getmouse; */
			return;
		}
		int t;
		t = MOS_getTime() - play_time0;
		if (msbuf[msbuf_num].time <= t)
		{
			int newx,newy;
			newx = msbuf[msbuf_num].x;
			newy = msbuf[msbuf_num].y;
			ms->dx = newx - ms->x;
			ms->dy = newy - ms->y;
			ms->x  = newx;
			ms->y  = newy;
			ms->x  = newx;
			ms->btn1 = (msbuf[msbuf_num].btn >> 4) & 15;
			ms->btn2 = msbuf[msbuf_num].btn & 15;
			msbuf_num++;
			return;
		}
		else
			return;
	}
	else
	{
_getmouse:
		rdmos(ms);
		;
		static int btn2click = 0;
		static int inter;
		if (ms->btn2 == OFFON)
		{
			inter = MOS_getTime() - btn2click;
			btn2click += inter;
		}
		else
			inter = 10000;
		;
		if (ms_recording)
		{
			if (msbuf_num >= msbuf_maxnum-1)
			{
				ms_record_end();
				return;
			}
			ms_record t;
			t.time = MOS_getTime() - rec_time0;
			t.x = ms->x;
			t.y = ms->y;
			t.btn = ms->btn1 * 16 + ms->btn2;
			if (msbuf_num == 0)
			{
				msbuf[msbuf_num] = t;
				msbuf_num++;
			}
			else
			{
#define	PRE	msbuf[msbuf_num-1]
				if (PRE.x != t.x || PRE.y != t.y || PRE.btn != t.btn)
				{
					msbuf[msbuf_num] = t;
					msbuf_num++;
				}
#undef PRE
			}
		}
	}
}


void commandMsPlay()
{
	ms_play_start();
}


void commandMsRec()
{
	ms_record_start();
}


void commandMsRecStop()
{
	ms_record_end();
}


/*--------------------------------------------------------*/
/*                マウスカーソルを定義する                */
/*--------------------------------------------------------*/


static char *csr_timer[] =
{
	"00000000000000000000000000000000",
	"00000111110000111100001111100000",
	"00011111111001ffff10011111111000",
	"000111111111001111001111111f1000",
	"00111111111000011000011111111100",
	"001f1f1110001111111100011111f100",
	"001ff11100111ffffff111001111f100",
	"0011110111fffff11fffff111011f100",
	"001110011ffffff11ffffff110011100",
	"00010011fff1ffffffff1fff11001000",
	"0000001ffffffff1fffffffff1000000",
	"000001fffffffff1ffffffffff100000",
	"000001ff1ffffff1fffffff1ff100000",
	"000011fffffffff1ffffffffff110000",
	"00001ffffffffff1fffffffffff10000",
	"00001ffffffffff1fffffffffff10000",
	"00001f11fffffff11fffffff11f10000",
	"00001f11fffffff111111fff11f10000",
	"00001ffffffffffffffffffffff10000",
	"00001ffffffffffffffffffffff10000",
	"000011ffffffffffffffffffff110000",
	"000011ff1ffffffffffffff1ff110000",
	"000001ffffffffffffffffffff100000",
	"0000011ffffffffffffffffff1100000",
	"00000011fff1ffffffff1fff11000000",
	"000000111ffffff11ffffff111000000",
	"0000000111fffff11fffff1110000000",
	"0000000011111ffffff1111100000000",
	"00111101101111111111110110111100",
	"011ff1111000111111110001111ff110",
	"01111111100000000000000111111110",
	"00000000000000000000000000000000",
	NULL
};


static char moscsr[2+512+128];


char *moscsr_timer()
{
	int i,j;
	// if (moscsr == NULL)
	//	if ((moscsr = malloc(2+512+128)) == NULL)
	//		return NULL;
	moscsr[0] = 4;
	moscsr[1] = 32;
	// パターンデータの作成
	for (i=0; i<32; i++)
	{
		for (j=0; j<16; j++)
		{
			moscsr[2+16*i+j] = ctox(*(csr_timer[i]+2*j  ))
							 + ctox(*(csr_timer[i]+2*j+1))*16;
		}
	}
	// ANDデータの作成
	for (i=0; i<32; i++)
	{
		unsigned long andpat = 0;
		for (j=0; j<32; j++)
		{
			if (ctox(*(csr_timer[i]+j)) != 0)
				andpat |= (1 << j);
		}
		andpat = ~andpat;
		*(unsigned long *)&moscsr[2+512+4*i]   = (andpat>>24)&255;
		*(unsigned long *)&moscsr[2+512+4*i+1] = (andpat>>16)&255;
		*(unsigned long *)&moscsr[2+512+4*i+2] = (andpat>> 8)&255;
		*(unsigned long *)&moscsr[2+512+4*i+3] = andpat&255;
	}
	return moscsr;
}


/*--------------------------------------------------------*/
/*            一定時間ごとに関数を呼び出す処理            */
/*--------------------------------------------------------*/


static bool intenable = NO;
static unsigned int _intfunc_timer = 0;
static unsigned int _intfunc_timeinterval = 0;
static void (*intfunc)();


static void _call_intfunc()
{
	if (!intenable || intfunc == NOFNC)
		return;
	if (_intfunc_timer >= _intfunc_timeinterval)
	{
		(*intfunc)();
		_intfunc_timer = 0;
	}
	else
		_intfunc_timer++;
}


int set_intfunc(void (*func)(), int timer)
// 一定時間ごとに呼び出す関数の登録
// timer : 呼び出す時間間隔(1/10 秒単位)
{
	intenable = NO;
	_intfunc_timeinterval = timer;
	_intfunc_timer = _intfunc_timeinterval - 1;
	intfunc = func;
	// return MOS_setEvent(_call_intfunc);
	intenable = YES;
	return 0;
}


int clr_intfunc()
{
	intenable = NO;
	intfunc = NOFNC;
	// return MOS_setEvent(NOFNC);
	return 0;
}


static int _timno;


void int_init()
{
	TIM_TIME timer;
	timer.mode = 0;
	timer.inf  = 0;
	timer.adr  = (unsigned long)_call_intfunc;
	timer.adr_seg = 0;
	timer.hcycle = 0;
	timer.lcycle = 10;
	// TIM_settime(&timer, &_timno);
}


void int_end()
{
	// TIM_clrtime(_timno);
}


/* end of sub2.c */
