#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>
#include <guidbg.h>

char	*guiEgbPtr ;			/*	EGB のワークアドレス	*/

/*	どうさに最低必要なメモリ(この例では128Kbytes)	*/
#define MimMemory (1024*128)
// #define DEBUG

/*	alertMemFunc関数の追い越し禁止フラグ	*/
static int		alertMemFlag = FALSE ;

/*	アラートメッセージ						*/
static char	*alertStrMem[] =
				{"時計ｰ：\nメモリが不足しています", "確認"};

/****************************************************************/
/*	メモリ不足時のアラート関数（イベント登録関数）				*/
/****************************************************************/
void alertMemFunc()
{
	/*	メモリ不足のアラート表示	*/
	MMI_CallMessage(MMI_GetApliId(), GM_ALERT, 
						AM_ALERT1 | AM_ALERTB0E,(int)alertStrMem) ;

	/* alertMemFunc関数の追い越し禁止解除	*/
	alertMemFlag = FALSE ;
}

extern int	iconBaseWindowID ;
extern int	iconMenuID[] ;
extern int	iconMenuItemID[] ;
extern int	dialogBaseHyperID ;
extern int	iconBaseHyperID ;
extern int	timeSetMessageID[];

#include <eintm.h>
#include <mos.h>
#include <smsg.h>
#define T4GDATASIZE (7480)
extern int	t4QuitFuncRet ;
extern int	t4UpdateFlag ;//-1:ｱｯﾌﾟﾃﾞｰﾄ不可 0:ｱｯﾌﾟﾃﾞｰﾄ可 1:一時強制全ｱｯﾌﾟﾃﾞｰﾄ
extern int	t4Hour[];		//タイマー時刻(時)
extern int	t4Minute[];		//タイマー時刻(分)
extern int	t4Switch[];		//スイッチの状態 0:解除 1:設定
extern char	t4GBuffer[];	//グラフィックデータバッファ
extern int	t4x,t4y;		//座標
extern int	t4SMSGFlag;		//0:常駐していない 1:常駐している
extern char	t4MenuMessage[3][11];
extern char sBufS[6][7];
extern int	t4ClipFlag;
int			t4mode = 0;		//モード 0:のびている 1:ちじんでいる

extern void t4PreScreenChangeFunc(void);
extern void t4PostScreenChangeFunc(void);
extern void t4IdleTask(void);

/*= リジューム用設定=================================================*/
FRAME	RSM_FRAME;
int		RSM_SWITCH[5] ={ 0,0,0,0,0} ;
int		RSM_HOUR[3] =  { 13,16, 1};
int		RSM_MINUTE[3] ={ 54,59,30};
char	RSMID[]="%%% 時計ｰ %%%";
char	RSMTITLE[]="時計ｰ    Programmed by 機拡";
/*===================================================================*/

//==========================================================================
int userFunc(apliId, messId, info, data)
int	apliId;
int	messId;
int	info;
int	data;
{
	register int	ret;

	ret = ILLEGAL_FUNCTION;

	switch(messId)
	{
		case	GM_QUIT :
//			extern int iconMenuItemID[] ;
//			MMI_SendMessage( iconMenuItemID[5], MM_EXEC, 2, 0, 0 );
			MMI_SetHaltFlag( TRUE );
			t4QuitFuncRet = NOERR;

			ret = t4QuitFuncRet ;
			break;
		/*	アプリケーションを終了する場合はNOERRを、
			アプリケーションを終了しない場合はILLEGAL_FUNCTIONを返す
			(この例では、exit_idonIdの呼び出し関数で、exitFuncRetの値をきめて、
			その値が戻り値になる)	*/

		/*	どっかから制御が来た	*/
		case	GM_WAKE :
		 {
		 	EVENT ev;

			/*	alertMemFunc関数の追い越し禁止判定			*/
			if(alertMemFlag != FALSE)
				break ;

			/*	動作メモリのチェック	*/
			if(TL_checkMemory(1) * 4096 < MimMemory )	
			{
				/*	alertMemFunc関数の追い越し禁止	*/
				alertMemFlag = TRUE ;

				/*	メモリ不足の場合はアラート処理関数をイベント登録する	*/
				MMI_FlushEvnt() ;	/*	イベントキューをフラッシュ	*/
				ev.what = EVEXEC ;
				ev.shift = 0 ;
				ev.info = (int)alertMemFunc ;
				ev.time  = MOS_getTime() ; 
				MMI_SetEvnt(&ev) ;
				break ;
			}
			if(t4mode==1){
				t4mode = 0;
				MMI_SendMessage( iconBaseHyperID , MM_ERASE , 0);
				MMI_SendMessage( dialogBaseHyperID , MM_ERASE , 0);
//				MMI_SendMessage( aboutDialogID , MM_ERASE , 0);
				//ウィンドゥをのばす
				FRAME fr;
				EIN_getObjectFrame(iconBaseWindowID,&fr);
				fr.rdwy = fr.rdwy + 23 ;
				MMI_SendMessage(iconBaseWindowID,MM_MOVE,1,&fr);
				//のばした所にメニューを表示
				MMI_SendMessage(iconMenuID[0],MM_ATTACH,1,iconBaseWindowID);
				MMI_SendMessage( iconBaseHyperID ,MM_SHOW , 0);
				MMI_SendMessage( dialogBaseHyperID , MM_SHOW , 0);
			}
			t4UpdateFlag = 1;
			break ;
		}
		/*	GM_WAKEでは、シェル呼び出し関数の戻り値は
			常にILLEGAL_FUNCTIONにすること(普通はswitch文の前で、
			設定してあるから、処理が終わった段階でbreakしてよい)	*/

		case	GM_SLEEP :
			#ifdef DEBUG
			printf("時計ｰ(GM_SLEEP)\n");
			#endif
			if(t4mode==0){
				t4mode=1;
				MMI_SendMessage( iconBaseHyperID , MM_ERASE , 0);
				MMI_SendMessage( dialogBaseHyperID , MM_ERASE , 0);
				//ウィンドゥをちじめる
				FRAME fr;
				EIN_getObjectFrame(iconBaseWindowID,&fr);
				fr.rdwy = fr.rdwy - 23 ;
				MMI_SendMessage(iconBaseWindowID,MM_MOVE,1,&fr);
				//メニューをはずす
				MMI_SendMessage(iconMenuID[0],MM_DETACH,0);
				MMI_SendMessage( iconBaseHyperID ,MM_SHOW , 0);
				MMI_SendMessage( dialogBaseHyperID , MM_SHOW , 0);
			}
			t4UpdateFlag = 1;
			break;

		case	GM_PAUSE :
			t4UpdateFlag = -1; //	アップデート禁止
			break;

		case	GM_CONTINUE :
			t4UpdateFlag = 0 ; //	アップデート許可
			break;

//		case	GM_ENVIRONMENT :
//			if(info)
//				environmentPopFunc(); /*環境復帰処理関数(ユーザーが設定)*/
//			else
//				environmentPushFunc(); /*環境退避処理関数(ユーザーが設定)*/
//			ret = NOERR;
//			break;
		/*	GM_ENVIRONMENTの時、環境退避をする場合はNOERRを、
			そうでない場合はILLEGAL_FUNCTIONを(普通はswitch文の前で
			設定してあるから、処理が終わった段階でbreakしてよい)返す	*/

		case	GM_PRESCRCHG :
			t4PreScreenChangeFunc();
			break;

		case	GM_POSTSCRCHG :
			t4PostScreenChangeFunc();
			break;

		case	GM_SHOW :
			t4UpdateFlag = 1;	//一時強制全アップデート
			#ifdef DEBUG
			printf("時計ｰ(GM_SHOW):強制アップデート");
			#endif
			break;

		case	GM_ERASE :
			t4UpdateFlag = -1;	//アップデート禁止
			break;

		default : break;
	}

	return(ret);
}

void main()
{
	static MMICTRL mmi ={
				SCREEN16 | SCREENIGNORE,	// ページ0側解像度
				SCREENUNUSED,				// ページ1側解像度
				0, 							// 書き込みページ
				SCREENAVAILABLE, 			// 表示ページ
				0, 							// 表示プライオリティ
				SCREENAVAILABLE,			// 色数
				SCREENEXPAND, 				// VRAMの横の長さ
				0, 							// メモリ領域の大きさ
				NULL, 						// メモリ領域のアドレス
				0, 							// ユーザ領域の大きさ
				NULL, 						// ユーザ領域のアドレス
				0, 0, 						// 画面枠	lupx,lupy
				0, 0,						//			rdwx,rdwy
				-16384, -16384,				// 移動枠	lupx,lupy
				16383, 16383,				//			rdwx,rdwy
				15, 						// 白色
				8,  						// 黒色
				7,  						// 灰色
				6	 						// 反転色
	};

	extern int APL_init() ;
	extern int APL_end() ;

	/*	初期化処理	*/
	if (MMI_Open( &mmi ) == NOERR)
	{
		/*	初期化に成功すればメインループに入る.	*/
		if (APL_init() == NOERR){
			MMI_ExecSystem() ;
			APL_end();
		}
	}

	/*	終了処理	*/
	MMI_Close() ;

}

int APL_init()
{
	extern MMIINIT	initDataICONGUI ;
	extern MMIINIT	initDataABOUTGUI ;
	extern MMIINIT	initDataT_SETGUI ;

	register int	ret ;

	/*	EGB ワークアドレスの取得.	*/
	guiEgbPtr = MMI_GetEgbPtr() ;

	/*	ハイパ型部品の初期化			*/
	if ((ret = MMI_initHyper()) < 0)
		return ret ;
	/*	ダイアログ型部品の初期化		*/
	if ((ret = MMI_initDialogL40()) < 0)
		return ret ;
	/*	ウインドウ型部品の初期化		*/
	if ((ret = MMI_initWindowL40()) < 0)
		return ret ;
	/*	メッセージ型部品の初期化		*/
	if ((ret = MMI_initMessageL40()) < 0)
		return ret ;
	/*	メニュー型部品の初期化			*/
	if ((ret = MMI_initMenuL40()) < 0)
		return ret ;
	/*	ボタン型部品の初期化			*/
	if ((ret = MMI_initButtonL40()) < 0)
		return ret ;
	/*	ドロウボタン型部品の初期化		*/
	if ((ret = MMI_initDrawButtonL40()) < 0)
		return ret ;
	/*	アイコンボタン型部品の初期化	*/
	if ((ret = MMI_initIconL40()) < 0)
		return ret ;
	/*	メニューアイテム型部品の初期化	*/
	if ((ret = MMI_initMenuItemL40()) < 0)
		return ret ;
	/*	スクロール型部品の初期化		*/
	if ((ret = MMI_initScrollBarL40()) < 0)
		return ret ;

	/*	背景データの初期化						*/

	/*	データの登録		*/
	if ((ret = MMI_Init(&initDataICONGUI)) < 0)
		return ret ;

	if ((ret = MMI_Init(&initDataABOUTGUI)) < 0)
		return ret ;

	if ((ret = MMI_Init(&initDataT_SETGUI)) < 0)
		return ret ;

	MMI_SendMessage(MMI_GetBaseObj(), MM_SETEXEC, 1, userFunc);
	MMI_CallMessage(MMI_GetApliId(), GM_TITLE, (int)RSMTITLE, 0);

	// GUI色をメニュー色に設定
	KH_initGuiColor();

	//===============================================================
	//					リジューム読み込み
	//===============================================================
	char	work[RSMWORKSIZE];	// リジュームマネージャのワークエリア
	char	buf[300];
	char	*ptr;
	int		size, x, y,i,j;
	FRAME fr;
	EIN_getObjectFrame(iconBaseWindowID,&fr);

	// リジュームマネージャの初期化(アプリのIDタグ登録)
	EIN_rsmInit( work, RSMID );
	// 読み込みバッファ設定
	EIN_rsmBufSet( work, buf, 1023 );
	// リジューム情報読み込み
	size = EIN_rsmLoad( work );
	#ifdef DEBUG
	printf("時計ｰ:resume size=%d\n",size);
	#endif
	if ( size > 0 ){
		//アイコン表示位置
		if( ((ptr = strstr(buf,"\nICON: ")) != NULL ) &&
					(sscanf(ptr,"\nICON: %d %d\n",&x,&y) > 1 ) ){
			RSM_FRAME.lupx = x;
			RSM_FRAME.lupy = y;
			RSM_FRAME.rdwx = x+(fr.rdwx-fr.lupx);
			RSM_FRAME.rdwy = y+(fr.rdwy-fr.lupy);
			#ifdef DEBUG
			printf("時計ｰ(ICON): move to (%d,%d)\n",x,y);
			#endif
			MMI_SendMessage(iconBaseWindowID,MM_MOVE,1,&RSM_FRAME);
		}
		//タイマー時刻
		if( ((ptr = strstr(buf,"\nTIMER: ")) != NULL ) &&
					(sscanf(ptr,"\nTIMER: %d:%d %d:%d %d:%d\n",
						&(RSM_HOUR[0]),&(RSM_MINUTE[0]),
						&(RSM_HOUR[1]),&(RSM_MINUTE[1]),
						&(RSM_HOUR[2]),&(RSM_MINUTE[2]) ) > 1 ) ){
			for(i=0;i<3;i++){
				t4Hour[i]=RSM_HOUR[i];
				t4Minute[i]=RSM_MINUTE[i];
			}
			#ifdef DEBUG
			printf("時計ｰ(TIMER): %d:%d %d:%d %d:%d\n",
								RSM_HOUR[0],RSM_MINUTE[0],
								RSM_HOUR[1],RSM_MINUTE[1],
								RSM_HOUR[2],RSM_MINUTE[2] );
			#endif
		}
		//スイッチ状態
		if( ((ptr = strstr(buf,"\nSWITCH: ")) != NULL ) &&
					(sscanf(ptr,"\nSWITCH: %d %d %d %d %d\n",&(RSM_SWITCH[0]),
						&(RSM_SWITCH[1]),&(RSM_SWITCH[2]),
						&(RSM_SWITCH[3]),&(RSM_SWITCH[4])) > 1 ) ){
			for(i=0;i<5;i++) t4Switch[i]=RSM_SWITCH[i];
			#ifdef DEBUG
			printf("時計ｰ(SWITCH): %d %d %d %d %d\n",RSM_SWITCH[0],
						RSM_SWITCH[1],RSM_SWITCH[2],
						RSM_SWITCH[3],RSM_SWITCH[4]);
			#endif
		}
	} else { ;
	#ifdef DEBUG
	printf("時計ｰ:Can't find resume file.\n");
	#endif
	}

	//サウンドメッセージ初期化
	//しなくてよい？(サウンドワークがわからないから、初期化できない)
	if( SMSG_chk() == 0 ){
		t4SMSGFlag = 0;
		#ifdef DEBUG
		printf("時計ｰ:サウンドメッセージ常駐なし\n");
		#endif
	} else {
		t4SMSGFlag = 1;
		#ifdef DEBUG
		printf("時計ｰ:サウンドメッセージ常駐あり\n");
		#endif
	}

	//タイマー時刻をメニューと、ボタンに書き込む
	for(i=0;i<3;i++){
		sprintf(&(t4MenuMessage[i][0]),"%2d時 %2d分",t4Hour[i],t4Minute[i]);
		sprintf(&(sBufS[i*2][0]),"%2d時",t4Hour[i]);
		sprintf(&(sBufS[i*2+1][0]),"%2d分",t4Minute[i]);
		MMI_SendMessage(iconMenuItemID[i+6],MM_SETMSG,1,
											&(t4MenuMessage[i][0]));
		MMI_SendMessage(timeSetMessageID[i*2+1],MM_SETMSG,1,
											&(sBufS[i*2][0]));
		MMI_SendMessage(timeSetMessageID[i*2+2],MM_SETMSG,1,
											&(sBufS[i*2+1][0]));
	}
	//スイッチの内容をメニューに反映させる
	for(i=0;i<5;i++){
		if(t4Switch[i] == 1){
			//セット
			MTL_setAtrObj( iconMenuItemID[i+6] , MS_CHECKL40 );
		} else {
			//リセット
			MTL_resetAtrObj( iconMenuItemID[i+6] , ~MS_CHECKL40 );
		}
	}

	//グラフィックデータファイルの読み込み
	for(i=0;i<130;i++) buf[i]=0;
	char name[] = "tokei4.dat\0" ;
	MMI_CallMessage(MMI_GetApliId(),GM_QUERYID,QM_DIRECTRY,(int)buf);
	i=0;j=0;
	while(buf[i]!='\0') i++ ;
	while(name[j]!='\0') { buf[i+j] = name[j]; j++;}
	FILE *fp;
	if((fp=EIN_fopen(buf,"rb"))==NULL){
		#ifdef DEBUG
		printf("時計ｰ:Can't open '%s'.\n",buf);
		#endif
		return -1 ;						//time4.datが見つからなければ起動しない
	} else
	fread( t4GBuffer , 1, T4GDATASIZE,fp);
	fclose(fp);

	EIN_getObjectFrame(iconBaseWindowID,&fr);
	t4PostScreenChangeFunc();
	t4x = fr.lupx + 6;
	t4y = fr.lupy + 4;

	t4mode=0;
	MMI_CallMessage( MMI_GetApliId() , GM_SLEEP ,0,0 );

//	MMI_SendMessage(MMI_GetBaseObj(), MM_SHOW, 0) ;
	t4UpdateFlag = 1;
	t4ClipFlag = 0;
	MMI_SetIdleTaskFunc( t4IdleTask );
	t4IdleTask();

	return NOERR ;
}

int APL_end()
{
	//リジューム保存

	char	work[RSMWORKSIZE];
	char	buf[300];
	char	aplpath[128];
	FRAME	fr;
	register int ret;
	
	// アイコンの枠座標を得る
	EIN_getObjectFrame(iconBaseWindowID,&fr);
	
	// 情報が更新されていたら保存
	if ( (RSM_FRAME.lupx	!= fr.lupx) ||
	     (RSM_FRAME.lupy	!= fr.lupy) ||
	     (RSM_SWITCH[0]		!= t4Switch[0]) ||
	     (RSM_SWITCH[1]		!= t4Switch[1]) ||
	     (RSM_SWITCH[2]		!= t4Switch[2]) ||
	     (RSM_SWITCH[3]		!= t4Switch[3]) ||
	     (RSM_SWITCH[4]		!= t4Switch[4]) ||
	     (RSM_HOUR[0]		!= t4Hour[0]) ||
	     (RSM_HOUR[1]		!= t4Hour[1]) ||
	     (RSM_HOUR[2]		!= t4Hour[2]) ||
	     (RSM_MINUTE[0]		!= t4Minute[0]) ||
	     (RSM_MINUTE[1]		!= t4Minute[1]) ||
	     (RSM_MINUTE[2]		!= t4Minute[2]) ){
		#ifdef DEBUG
		printf("時計ｰ:リジューム保存\n");
		#endif
		// マネージャ初期化
		EIN_rsmInit( work, RSMID );
		// バッファ設定(アプリ識別ID,更新時刻は自動設定されます)
		EIN_rsmBufSet( work, buf, 1023 );
		// アプリディレクトリ保存
		MMI_CallMessage( MMI_GetApliId(), GM_QUERYID, QM_PATH, (int)aplpath );
		EIN_rsmBufPrintf( work, "APLPATH: %s", aplpath );
		// アプリ名保存
		EIN_rsmBufPrintf( work, "TITLE:   %s", RSMTITLE );
		// コメント保存
		EIN_rsmBufCat( work, "COMMENT: アラーム付きデジタル時計。メニューが引っ込んで小さくなります。");

		// アイコン位置保存
		EIN_rsmBufPrintf( work, "ICON: %d %d", fr.lupx, fr.lupy );
		// タイマー保存
		EIN_rsmBufPrintf( work, "TIMER: %d:%d %d:%d %d:%d",
				t4Hour[0],t4Minute[0],t4Hour[1],t4Minute[1],
				t4Hour[2],t4Minute[2]);
		// スイッチ状態保存
		EIN_rsmBufPrintf( work, "SWITCH: %d %d %d %d %d",t4Switch[0],
						t4Switch[1],t4Switch[2],t4Switch[3],t4Switch[4]);
		// バッファ終端(^A)設定
		EIN_rsmBufTail( work );
		// バッファをセーブ
		ret = EIN_rsmSave( work );

		#ifdef DEBUG
		printf("時計ｰ: resume save size %d\n",ret);
		#endif

	}

	return NOERR ;
}
