/* Copyright (c) 2000-2003                  */
/*   Yamashita Lab., Ritsumeikan University */
/*   Studio ARC, ASTEM RI/Kyoto             */
/*   All rights reserved                    */

#include	<stdio.h>
#include	<stdlib.h>

#ifndef WIN32
#include	<unistd.h>
#endif

#include	"confpara.h"

#ifdef WIN32
#include <windows.h>
#include "chaone.h"
#endif

/*
#define CHASEN "/usr/local/bin/chasen"
#define CHASENRC "chasenrc"
*/

typedef struct _pipe_chain {
	char *command[20];
	int last;	/* 最後のプロセスのみ 1 にする。他は 0 に。*/
} PIPE_CHAIN;

PIPE_CHAIN pchain[3];
char chasen_rc_option[] = "-r";

/*
PIPE_CHAIN pchain[] = {
	{ { CHASEN, "-r", CHASENRC, (char *)0 }, 0 },
	{ { CHAONE, (char *)0 }, 0 },
	{ { POSTP, (char *)0 }, 1 }
};
*/

int TmpMsg(char *,...);
int ErrMsg(char *,...);
int make_pipe_child(PIPE_CHAIN *,int *);

int chasen_process = 0;

#ifndef WIN32
void set_command( char *str, char *command[] )
{
	int i;
	char *c;

	command[0] = str;
	i = 1;  c = str+1;
	while( *c != '\0' )  {
		if( *c == ' ' || *c == '\t' )  *c = '\0';
		if( *(c-1) == '\0' && *c != ' ' && *c != '\t' )  {
			command[i] = c;
			++i;
		}
		++c;
	}
	command[i] = '\0';
}
#endif

#ifdef WIN32
// Load Library functions
typedef int  (__cdecl *chasen_getopt )( char*[], FILE * );
typedef char*  (__cdecl *chasen_sparse )( char* );
#endif

/**
 * Analysis to ChasenDLL
 * in     char* pszText : 解析対象文字列
 * return char*         : 解析結果
 */
char* make_chasen_process( char* pszText )
{
	HINSTANCE hLib;
	// set libchasen.dll
	chasen_getopt chasen_getopt_func;
	// get libchasen.dll
	chasen_sparse chasen_sparse_func;
	// installation place of Chasen (C:\Program Files\chasen\\etc\chasenrc)
	//char *opt[] = { NULL , "-r","C:\\Program Files\\chasen\\etc\\chasenrc", NULL };
	char *opt[] = { NULL, chasen_rc_option, chasen_rc, NULL };
	// libchasen load
	if( ( hLib = LoadLibrary( chasen_dll ) ) != 0 )
	{
		if( ( chasen_getopt_func = ( chasen_getopt )GetProcAddress( hLib, "chasen_getopt_argv" ) ) != 0 )
		{
			( *chasen_getopt_func )( opt, stdout );
		}

		if( ( chasen_sparse_func = ( chasen_sparse )GetProcAddress( hLib, "chasen_sparse_tostr" ) ) != 0 )
		{
			char* str = NULL;
			str = ( *chasen_sparse_func )( pszText );
			return make_chaone_process( str );
			//return str;
		}
	}
	return NULL;
}

#ifndef WIN32
int make_chasen_process( int *fd_in, int *fd_out )
{
	int to_parent[2];

	if( chasen_process != 0 )  return 0;

	pchain[0].command[0] = chasen_bin;
	pchain[0].command[1] = chasen_rc_option;
	pchain[0].command[2] = chasen_rc;
	pchain[0].command[3] = '\0';

	if( chaone_bin[0] == '\0' )  {
		pchain[0].last = 1;		/* set 1 if this process is the last */
	} else {
		pchain[0].last = 0;
		set_command( chaone_bin, pchain[1].command );
		pchain[1].last = 1;	
	}

	/* to_parent は「最後の子 -> 親」で使う。*/
	if( pipe(to_parent) < 0 )  {
		ErrMsg( "pipe error in init_text_analysis\n" );
		return -1;
	}

	/* 親が書き込むfdはこのルーチンの中で決まる。*/
	*fd_out = make_pipe_child( pchain, to_parent );
	if( *fd_out < 0 )  return -1;

	*fd_in = to_parent[0];		/* 親はここから読み出す。*/
	close( to_parent[1] );		/* 親はここへは書かない。*/
	chasen_process = 1;
#ifdef PRINTDATA
	TmpMsg( "* chasen start.\n" );
#endif
	return 0;
}
#endif

/* 子へ書き込むときのfdを返す。 */
int make_pipe_child( PIPE_CHAIN *pc, int *to_parent )
{
#ifndef WIN32
	pid_t pid;
	int to_child[2], out;

	/* to_child は「親 -> 子」で使う。*/
	if( pipe(to_child) < 0 )  {
		ErrMsg( "pipe error in init_text_analysis\n" );
		return -1;
	}

	switch( (pid=fork()) ) {
	case 0:					/* child */
		/* 子はここへは書かない。*/
		close( to_child[1] );

		/* 読み込み先を標準入力に */
		if( to_child[0] != 0 )  {
			dup2( to_child[0], 0 );
			close( to_child[0] );
		}

		/* 書き込み先の設定 */
		if( pc->last )  {
		  /* 最後の子 */
			close( to_parent[0] );	/* 子はここから読まない */
			/* 最後の子は親へ書き込む。*/
			if( to_parent[1] != 1 )  {
				dup2( to_parent[1], 1 );
				close( to_parent[1] );
			}
		} else {
		  /* 途中の子 */
			/* 書き込むfdはこのルーチンの中で決まる。*/
			out = make_pipe_child( (pc+1), to_parent );
			/* 書き込み先を標準出力に */
			if( out != 1 )  {
				dup2( out, 1 );
				close( out );
			}
			close( to_parent[0] );	/* 途中の子プロセスでは使わない。 */
			close( to_parent[1] );	
		}

		if( execv( pc->command[0], pc->command ) < 0 )  {
			ErrMsg( "execv error in init_text_analysis\n" );
			exit(1);
		}
		break;

	case -1:				/* error */
		ErrMsg( "fork error\n" );
		return -1;

	default:				/* parant */
		close( to_child[0] );	/* 親はここから読まない。*/
		return to_child[1];		/* 親はここへ書き込む。*/
	}
#endif
	return 0;
}
