/*************************************************************************
*	プログラミング・ヘルパ
*************************************************************************/

char	   *MACROKEY_PGHELP_PATH = "ProgHelp_path";
char	   *_PGHELP_FN = "_index";

#define	_PGHELP_HASH_MAX		(16)
#define	_PGHELP_SIZ_FNINF		(16)

#define	_PGHELP_SIZ_TAG			(40)	/* タグサイズ					*/
#define	_PGHELP_SIZ_FNC			(28)	/* タグ格納する関数名の長さ		*/
#define	_PGHELP_POS_FNC			(_PGHELP_SIZ_TAG - _PGHELP_SIZ_FNC)
										/* タグ中の関数名格納位置		*/

int		_pgHelp_hash(char *name)
{
	int			hash, ch;

	hash = 0;
	while ( *name )
	{
		ch = (*name) & 0xFF;
		hash = hash + (ch * 31);
		++name;
	}
	return (hash & (_PGHELP_HASH_MAX-1));
}

int		_pgHelp(char *name)
{
	char	   *path, fnIndex[256], fn[256];
	char	   *fpIndex, *fp;
	int			ret, hash, numfn, n, ch, i;
	char		*s, *p, buf[BUFSIZ];
	char	   *fntbl, fninf[_PGHELP_SIZ_FNINF];
	char		tag[_PGHELP_SIZ_TAG+4], func[_PGHELP_SIZ_FNC+4];

	char		fbuf[64];
	long		fpos;

	int			x0, y0;
	char	   *dlg;
	char	   *txtPtr;

	DSP_writePage(1);
	x0 = y0 = DLGPOS_CENTER_OF_SCN;
	txtPtr = NULL;

	hash = _pgHelp_hash(name);
	if ( (path = AMAC_getName( SysMacro, MACROKEY_PGHELP_PATH)) == NULL )
	{
		sprintf(buf, "%sMANUAL/", AplGetStartPath() );
		AMAC_setKey( SysMacro, MACROKEY_PGHELP_PATH, buf );
		if ( (path = AMAC_getName( SysMacro, MACROKEY_PGHELP_PATH)) == NULL )
			return (ERR);
	}

	/* インデックファイル名の取得	------------------------------------*/
	sprintf( fnIndex, "%s%s.%03d", path, _PGHELP_FN, hash );
	if ( (fpIndex = FM_fopen(fnIndex,"rb")) == NULL )
#if	1
		return (ERR);
#else
	{	/* インデックスの作成	*/

		dlg = DLG_msgOpen(x0,y0, 8*68,16*8, C_MBLACK,C_DLGBASE,C_HGREEN,
		    "MAKE INDEX FILE" );
		if ( dlg == NULL )
			return (ERR);
		DLG_msgClear( dlg, -1 );

		/* カレント変更	--------------------------------------------------*/
		sprintf(buf, "%s.", path);
		FS_chdrv( toupper(*path) - 'A' );
		FS_chdir(buf);

		numfn = 0;	/* ファイル数	*/
		ret = FM_findfirst( "*.doc", 0, fbuf);
		while ( ret == 0 )
		{
			++numfn;
			ret = FM_findnext( fbuf );
		}
		if ( numfn == 0 || numfn > 127 )
		{
			DLG_msgClose(dlg);
			return (ERR);	/* ガイドファイルが存在しない	*/
		}

		/* ファイル名テーブルの作成	----------------------------------------*/
		if ( (fntbl = calloc(numfn * _PGHELP_SIZ_FNINF,1)) == NULL )
		{
			DLG_msgClose(dlg);
			return (ERR);
		}

		n = 0;	/* ファイル数	*/
		ret = FM_findfirst( "*.doc", 0, fbuf);
		while ( ret == 0 )
		{
			p  = fntbl + (n * _PGHELP_SIZ_FNINF);
			*p = n++;	/* ファイル番号	*/
			strcpy(p + 1,fbuf);
			ret = FM_findnext( fbuf );
		}

		/* ファイル名テーブルの書き出し	------------------------------------*/
		sprintf( fnIndex, "%s%s.tbl", path, _PGHELP_FN );
		if ( (fpIndex = FM_fopen(fnIndex,"wb")) == NULL )
		{
			DLG_msgClose(dlg);
			free(fntbl);
			DLG_tmpMsgTime( x0, y0, C_MBLACK, C_DLGBASE, COLMIX(C_ERROR,C_GRAY),
			    3, "  %s : \n  Can't create index file!! ", fnIndex );
			return (ERR);
		}
		fwrite(fntbl, numfn * _PGHELP_SIZ_FNINF,1, fpIndex);
		FM_fclose(fpIndex);

		MOS_DEC();
		FM_updateOff();
		for ( n = 0; n < numfn; ++n )
		{
_NEXT_FILE:
			p  = fntbl + (n * _PGHELP_SIZ_FNINF);
			sprintf( fn, "%s%s", path, p + 1 );
			DLG_msgPrintf(dlg, "Manual file No.%3d %s\r\n", n, p + 1 );
			if ( (fp = FM_fopen(fn,"rb")) == NULL )
				goto _NEXT_FILE;

			for(;;)
			{
_NEXT_LINE:		fpos = ftell(fp);
				if ( fgets(buf,BUFSIZ,fp) == NULL )
					break;
				s = buf;
				if ( *s != '.' )
					goto _NEXT_LINE;
				++s;
				while ( isspace(*s) )
					++s;
				memset( func, 0, _PGHELP_SIZ_FNC );
				for ( i = 0; i < _PGHELP_SIZ_FNC; ++i )
				{
					ch = *s;	++s;
					if ( isdigit(ch) == 0 && isalpha(ch) == 0 && ch != '_' )
						break;
					func[i] = ch;
				}
				if ( func[0] == '\0' )
					goto _NEXT_LINE;

				DLG_msgPrintf( dlg,
				    "%-32s .. no.%3d (%-12s) offset:%6ld\r\n",
				    func, n, p + 1, fpos );

				/* タグをインデックスに書き出す	----------------------------*/
				sprintf(fnIndex,"%s%s.%03d",
				    path, _PGHELP_FN, _pgHelp_hash(func) );
				if ( (fpIndex = FM_fopen(fnIndex,"ab")) == NULL )
					goto _NEXT_LINE;
				memset(tag,0,_PGHELP_SIZ_TAG);
				tag[0] = *p;
				_setDword(tag + 1, fpos);
				strncpy( tag + _PGHELP_POS_FNC, func, _PGHELP_SIZ_FNC);
				_setByte(tag + _PGHELP_POS_FNC + _PGHELP_SIZ_FNC, 0 );
				fwrite(tag,_PGHELP_SIZ_TAG,1,fpIndex);

				FM_fclose(fpIndex);
			} /* end of "for(;;) */
			FM_fclose(fp);
		}
		FM_updateOn();
		DLG_msgClose(dlg);
		MOS_INC();
		free(fntbl);

		/* インデックスを作成後にオープン	*/
		sprintf( fnIndex, "%s%s.%03d", path, _PGHELP_FN, hash );
		if ( (fpIndex = FM_fopen(fnIndex,"rb")) == NULL )
			return (ERR);
	}
#endif

	ret = 0;
	for(;;)
	{
		if ( fread(tag,_PGHELP_SIZ_TAG,1,fpIndex) < 1 )	/* ファイル位置情報	*/
		{
			ret = -1;
			break;
		}
		if ( strncmp( name, tag + _PGHELP_POS_FNC, _PGHELP_SIZ_FNC) == 0 )
			break;
	}
	FM_fclose(fpIndex);

	if ( ret )
	{	/* 指定の検索パターンはない	*/
		DLG_tmpMsgTime( DLGPOS_MOS_SET_CENTER, DLGPOS_MOS_SET_CENTER,
		    C_MBLACK, C_DLGBASE, COLMIX(C_ERROR,C_GRAY),
		    3, "  %s : \n  Pattern not found!! ", name );
		return (ERR);
	}

	/* ファイル名テーブルの読み込み	------------------------------------*/
	sprintf( fnIndex, "%s%s.tbl", path, _PGHELP_FN );
	if ( (fpIndex = FM_fopen(fnIndex,"rb")) == NULL )
	{
		DLG_tmpMsgTime( DLGPOS_MOS_SET_CENTER, DLGPOS_MOS_SET_CENTER,
		    C_MBLACK, C_DLGBASE, COLMIX(C_ERROR,C_GRAY),
		    3, "  %s : \n  Can't open index file!! ", fnIndex );
		return (ERR);
	}
	fpos = tag[0] * _PGHELP_SIZ_FNINF;
	fseek(fpIndex,fpos,SEEK_SET);
	fread(fninf,_PGHELP_SIZ_FNINF,1,fpIndex);
	FM_fclose(fpIndex);

	if ( fninf[0] != tag[0] )	/* ファイル番号が一致しない	*/
		return (ERR);

	sprintf(fn,"%s%s", path, fninf + 1);
	if ( (fp = FM_fopen(fn,"rb")) == NULL )
	{
		DLG_tmpMsgTime( DLGPOS_MOS_SET_CENTER, DLGPOS_MOS_SET_CENTER,
		    C_MBLACK, C_DLGBASE, COLMIX(C_ERROR,C_GRAY),
		    3, "  %s : \n  Can't open manual file!! ", fn );
		return (ERR);
	}
	fpos = _getDword(tag + 1);
	fseek(fp,fpos,SEEK_SET);

	/* 説明内容の読み込み	--------------------------------------------*/
	/* ヘッダ行のスキップ	*/
	while ( fgets(buf,BUFSIZ,fp) != NULL )
	{
		if ( buf[0] != '.' )
			break;
	}
	for(;;)
	{
		txtPtr = DLG_txtSetLinBuf( txtPtr, 8, 80, "%s", buf );
		if ( fgets(buf,BUFSIZ,fp) == NULL )
			break;
		if ( buf[0] == '.' )
			break;
	}
	FM_fclose(fp);

	if ( (dlg = DLG_txtOpen(x0,y0,80,20,txtPtr,0)) == NULL )
	{
		DLG_txtFreeLinBuf( txtPtr );
		return (ERR);
	}
	DLG_txtSetTitle( dlg, "PROGRAM HELPER" );
	DLG_txtSetGuideMsg( dlg, "Function : %s", name );
	DLG_txtStart( dlg );
	DLG_txtClose( dlg );
	DLG_txtFreeLinBuf( txtPtr );

	return (NORMAL);
}


/*************************************************************************
*	カーソル位置の単語の説明を見る
*************************************************************************/

int		TxdUsr_pg_help( char *txd )
{
	int			ret, ch, len;
	char		func[_PGHELP_SIZ_FNC+4];
	size_t		curLnL, curOfs;
	char	   *dlg;

	if ( TxdGet_selFlag(txd) != 0 )		/* 選択中なら処理しない	*/
		return (0);

	/* 現在カーソル位置を取得	*/
	curLnL = TxdGet_curPosLnL(txd);
	curOfs = TxdGet_curPosOfs(txd);

	if ( (ch = TXD_getch(txd)) > 0 && ch < 256 && (isalpha(ch) || ch == '_') )
	{
		len = 0;
		while( len < _PGHELP_SIZ_FNC )
		{
			ch = TXD_getch(txd);
			TXD_cmdJump( txd, TXD_CUR_RIGHT );
			if ( isalpha(ch) || isdigit(ch) || ch == '_' )
			{
				func[len++] = ch;
			} else
				break;
		}
		func[len] = '\0';
		TXD_jumpPos( txd, curLnL, curOfs );
		if ( len == 0 )
			return (NORMAL);
	} else
		func[0] = '\0';

	DSP_writePage(1);
	dlg = DLG_getsOpen( DLGPOS_MOS_SET_HOME, DLGPOS_MOS_SET_HOME, 320,
	    "検索パターンを入力してください。" );
	DLG_getsSetTitle( dlg, "PATTERN" );
	ret = DLG_getsStart( dlg, _PGHELP_SIZ_FNC, func );
	DLG_getsClose(dlg);
	if ( ret <= 0 )
		return (0);

	_pgHelp( func );

	return (0);
}
