#include "dviout.h"
#include <ddeml.h>     // DDEMLライブラリを使用する
#include "option.h"

extern DDESTRUCT    g_ddeData;
extern char g_szFileName[MAX_PATH];

static int CheckMode( char* );
static int mode;
static BOOL exit_mode;
static BOOL sf_hyper = FALSE;

#define WINNORMAL 1
#define OPEN  2
#define REOPEN 3
#define PRINT 4
#define EXIT  5
#define VALUE 6
#define KEYINPUT 7
#define PAGEMOVE 8
#define PAGEHEAD 9
#define EXECPRINT 10
#define	WINICONIC 11

/**********************************************************************
***                      DDEML コールバック函数                     ***
**********************************************************************/
HDDEDATA CALLBACK DdeCallback( UINT iType, UINT iFmt, HCONV hConv,
							   HSZ hsz1, HSZ hsz2, HDDEDATA hData,
							   DWORD dwData1, DWORD dwData2 )
{
	char  szBuffer[1024];
	char *para;
	int i, pt, count;
	static int page;

	switch( iType )
	{
		case XTYP_CONNECT:
			exit_mode = FALSE;
			/* First, I check the service name.
			   I only allow wheter service name is DVIOUT or
			   WinDVI. the last is provided for compatibility
			   with WinDvi or WinDviPro. */
			DdeQueryString( g_ddeData.idInst, hsz2, 
				szBuffer, sizeof(szBuffer), 0 );
			if( strnicmp( szBuffer, "DVIOUT", 6 ) != 0
			 && stricmp( szBuffer, "WinDVI" ) != 0){
				return (HDDEDATA)FALSE;
			}

			/* Second, I check the topic name.
			   I only allow wheter topic is DVIOUT or
			   WinDVI or the DVI's file name. */
			DdeQueryString( g_ddeData.idInst, hsz1,
				szBuffer, sizeof(szBuffer), 0 );
			if( stricmp( szBuffer, "DVIOUT" ) != 0
			 && stricmp( szBuffer, "WinDVI" ) != 0
			 && stricmp( szBuffer, current_name ) != 0
			 && stricmp( szBuffer, g_winData.szAppName) != 0
			 && (stricmp( szBuffer, "DVIOUT1") != 0 ||
				  g_winData.szAppName[6] != 0) ){
				return (HDDEDATA)FALSE;
			}
			return (HDDEDATA)TRUE;

		case XTYP_REQUEST:
			DdeQueryString( g_ddeData.idInst, hsz2, 
				szBuffer, sizeof(szBuffer), 0 );

			if(!strcmp(szBuffer, "version"))
				para = strcpy(szBuffer, VERSION_NO) + 5;
			else if(!strcmp(szBuffer, "number")){
				strcpy(para = szBuffer, g_winData.szAppName+6);
				if(!*para)
					strcpy(para, "1");
			}
			else
				para = GetParaAny(szBuffer);
			if(para == NULL){
				if(!strcmp(szBuffer, "dvifile")){
					*szBuffer = 0;
					para = ((unsigned char)*g_szFileName > ' ')?current_name:szBuffer;
				}else if(!strcmp(szBuffer, "DVIfile")){
					para = szBuffer;
					if((unsigned char)*g_szFileName <= ' ')
						*para = 0;
					else
						GetShortPathName(current_name, szBuffer, MAX_PATH);
				}else if((unsigned char)*g_szFileName > ' '){
					if(!strcmp(szBuffer, "current_page"))
						wsprintf(para = szBuffer, "%d(%d)", 
							GetCurrentPage(), TransPage(GetCurrentPage()));
					else if(!strcmp(szBuffer, "total_page")){
						wsprintf(para = szBuffer, "%d(%d)", 
							GetTotalPage(), TransPage(GetTotalPage()));
					}else if(!strcmp(szBuffer, "time_stamp"))
						para = GetFTime();
				}
			}
			if(para != NULL)
				return DdeCreateDataHandle( g_ddeData.idInst, para, 
					strlen(para) + 1, 0,  hsz2, CF_TEXT, 0 );
			break;

		case XTYP_EXECUTE:
			DdeGetData( hData, szBuffer, sizeof(szBuffer), 0 );
			count = 0;
rep_exe:	for(i = pt = 0; szBuffer[i]; i++){
				if(szBuffer[i] == ']' && szBuffer[i+1] == '[')
					szBuffer[pt = i+1] = 0;
			}
			mode = CheckMode( szBuffer );
			if( !(mode | count++) )
				return (HDDEDATA)DDE_FNOTPROCESSED;
			if( szBuffer[0] == '"'
			  && szBuffer[strlen(szBuffer)-1] == '"' ){
				for( i = 0; (szBuffer[i] = szBuffer[i+1]) != 0; i++ );
				if(i)
					szBuffer[i-1] = 0;
			}
			switch( mode )
			{
				case WINNORMAL:
					if(IsIconic(g_winData.hMainWnd))
						ShowWindow(g_winData.hMainWnd, SW_RESTORE);
					SetForegroundWindow( g_winData.hMainWnd );
					break;
				case WINICONIC:
					ShowWindow(g_winData.hMainWnd, SW_MINIMIZE);
					break;
				case OPEN:
					if( !lstrcmp( g_szFileName, szBuffer) ){
						if(IsIconic(g_winData.hMainWnd))
							ShowWindow(g_winData.hMainWnd, SW_RESTORE);
						SetForegroundWindow( g_winData.hMainWnd );
						if( sf_hyper ) {
							sf_hyper = FALSE;
							SendMessage( g_winData.dviwin.hWnd, WM_USER_DO_HREF, 0, 0 );
						}
						break;
					}
					DefineDVIFileName( szBuffer );
					if(page < 0){
						para = SearchFileHistory(szBuffer, &page);
						if(para)
							DefineDVIFileName( szBuffer );
					}
					if(page > 0)
						SetStartPage(page);
					page = 0;
					SetColor(4);
					SendMessage( g_winData.hMainWnd, WM_USER_FILE_OPEN,
						0, 0 );
					break;
				case REOPEN:
					para = "FN";
					goto cmd;
				case EXECPRINT:
					if(mode == EXECPRINT)
						ExecPrint(szBuffer);
				case PRINT:
					para = "FP";
					goto cmd;
				case EXIT:
					exit_mode = TRUE;
					break;
				case PAGEMOVE:
					GotoPage(atoi(szBuffer));
					break;
				case PAGEHEAD:
					sf_hyper = FALSE;
					if(tolower(*szBuffer) == 'h') // history
						page = -1;
					else if(tolower(*szBuffer) == 'l') // last page
						page = GetTotalPage();
					else if(*szBuffer == '#'){
						SetHyperTag(szBuffer);
						sf_hyper = TRUE;
					}
					else
						page = atol(szBuffer);
					break;
				case VALUE:
					SetPara(szBuffer, SET_OPTION);
					break;
				case KEYINPUT:
					para = szBuffer;
cmd:				DoMacro(para, DDE);
					break;
				default:
					break;
			}
			if(pt){
				szBuffer[pt] = '[';
				for(i=0; (szBuffer[i] = szBuffer[pt+i]) != 0; i++);
				goto rep_exe;
			}
			return (HDDEDATA)DDE_FACK;

		case XTYP_DISCONNECT:
//          hConv = NULL;
			page = 0;
			if( exit_mode == TRUE ){
				DestroyWindow( g_winData.hMainWnd );
			}
			return NULL;

		default:
			break;
	}
	return (HDDEDATA)FALSE;
}

static int CheckMode( char* sz )
{
	char temp[1024];
	int  type;
	int len = lstrlen( sz ); // lstrlen's return value doesn't include NULL.
	int	pos = 10;

	/* If length of string is strictly less than 10, this application
	   doesn't need such short string! */
	if( len < 10 ) return 0;

	/* First, I check [FileExit] or [FileOpen(filename)].
	   Both can be checked string length 10. */
	lstrcpyn( temp, sz, 11 ); // lstrcpyn's count include NULL.

	if( strcmp( temp, "[FileExit]" ) == 0 ){
		return EXIT;
	}
	else if( strcmp( temp, "[FileOpen(" ) == 0 ){
		/* For instance, [FileOpen(foo.dvi)] was given, because
		   it has length 19, last index is 18, so we search the
		   ')'char from last char. */
		int i;

		type = OPEN;

get_para:
		for( i = len - 1; i >= 0; i-- )
		{
			if( sz[i] == ')' ) break;
		}
		/* Here i indexes the position of ). */
		if( i < pos ) return 0;
		/* We set the file name which our users want to open to sz. */
		lstrcpyn( temp, sz+pos, i-pos+1 );
		lstrcpy( sz, temp );
		return type;
	}else if( strcmp( temp, "[ValueSet(" ) == 0 ){
		type = VALUE;
		goto get_para;
	}else if (strcmp( temp, "[Function(" ) == 0 ){
		type = KEYINPUT;
		goto get_para;
	}else if (strcmp( temp, "[PageMove(" ) == 0 ){
		type = PAGEMOVE;
		goto get_para;
	}else if (strcmp( temp, "[PageOpen(" ) == 0 ){
		type = PAGEHEAD;
		goto get_para;
	}

	/* Second we check the string of which length is larger than 11. */
	if( len < 11 ) return 0;
	lstrcpyn( temp, sz, 12 );
	if( strcmp( temp, "[WinNormal]" ) == 0 ) return WINNORMAL;
	else if(strcmp( temp, "[WinIconic]" ) == 0) return WINICONIC;
	else if(strcmp( temp, "[FilePrint]" ) == 0 ) return PRINT;
	else if(strcmp( temp, "[FilePrint(" ) == 0 ){
		type = EXECPRINT;
		pos = 11;
		goto get_para;
	}
	
	/* Third we chech the string of which length is larger than 12. */
	if( len < 12 ) return 0;
	lstrcpyn( temp, sz, 13 );
	if( strcmp( temp, "[FileReopen]" ) == 0 ) return REOPEN;
	return 0;
}
