/*
 * Sample Program for TextPorter
 *
 * Copyright (C) 2009, AntennaHouse Inc.  All Rights Reserved
 *
 * 2009.10.28 Takeshi Yoneki
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "text_oem.h"
#include "thr_func.h"
#ifdef DMC_WIN
#include <windows.h>
#endif

int WritePropertyToFile(CCmdFilePath& filename, DMC_PROPERTY* Property,Byte* GroupName);

#ifdef DMC_WIN
std::string UTF16To8(const std::wstring s) {
	int bufferCount = s.length() * 3 + 16;
	char *buffer = new char[bufferCount];
	WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, buffer, bufferCount, NULL, NULL);
	std::string result = buffer;
	delete [] buffer;
	return result;
}

std::wstring UTF8To16(const std::string s) {
	int bufferCount = s.length() * 2 + 16;
	wchar_t *buffer = new wchar_t[bufferCount];
	MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, bufferCount);
	std::wstring result = buffer;
	delete [] buffer;
	return result;
}

std::wstring AnsiToUTF16(const std::string s) {
	int bufferCount = s.length() * 2 + 16;
	wchar_t *buffer = new wchar_t[bufferCount];
	MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, buffer, bufferCount);
	std::wstring result = buffer;
	delete [] buffer;
	return result;
}

void TransUTF16ToUTF8(char *dst8, const wchar_t *src16, int dstBytes) {
	WideCharToMultiByte(CP_UTF8, 0, src16, -1, dst8, dstBytes, NULL, NULL);
}

void TransUTF8ToUTF16(wchar_t *dst16, const char *src8, int dstChars) {
	MultiByteToWideChar(CP_UTF8, 0, src8, -1, dst16, dstChars);
}
#endif

BOOL ThreadCallBack(LDDMC_OLEERR* OleErr)
{
	printf("This OleErr is level %d\n",OleErr->LevNum);
	printf("This OleErr's code is %d\n",OleErr->ErrCode);
	printf("This OleErr's Engine is %s\n",OleErr->DtctResult);
	if (OleErr->ErrCode) 
		return DMC_TRUE; // 2007/05/24 by show
	return DMC_FALSE;
}

RESULT_TYPE CALLING ThreadMain(void *arg) {
	int iRet = -1;
	CThreadCall *instance = (CThreadCall *)arg;
	if (instance != NULL) {
		iRet = instance->ThreadProc();
	}
	instance->m_iRet = iRet;
#if defined DMC_WIN
	return iRet;
#else
	return NULL;
#endif // #if defined DMC_WIN
}

struct SFuncNameList {
	const char *m_funcName;
	FUNC_TYPE m_funcType;
} theFuncNameList[] = {
	"DMC_GetText_V5", FT_GET_TEXT_V5,
	"DMC_GetPageText_V5", FT_GET_PAGE_TEXT_V5,
	"DMC_GetProperty_V5", FT_GET_PROPERTY_V5,
	"DMC_GetPwdText_V5", FT_GET_PWD_TEXT_V5,
	"DMC_GetPwdPageText_V5", FT_GET_PWD_PAGE_TEXT_V5,
	"DMC_GetPwdProperty_V5", FT_GET_PWD_PROPERTY_V5,
	"DMC_GetTextStream_V5", FT_GET_TEXT_STREAM_V5,
	"DMC_GetPageTextStream_V5", FT_GET_PAGE_TEXT_STREAM_V5,
	"DMC_GetText_V4", FT_GET_TEXT_V4,
	"DMC_GetPageText_V4", FT_GET_PAGE_TEXT_V4,
	"DMC_GetProperty_V4", FT_GET_PROPERTY_V4,
	"DMC_GetPwdText_V4", FT_GET_PWD_TEXT_V4,
	"DMC_GetPwdPageText_V4", FT_GET_PWD_PAGE_TEXT_V4,
	"DMC_GetPwdProperty_V4", FT_GET_PWD_PROPERTY_V4,
	"DMC_GetTextStream_V4", FT_GET_TEXT_STREAM_V4,
	"DMC_GetPageTextStream_V4", FT_GET_PAGE_TEXT_STREAM_V4,
	NULL, (FUNC_TYPE)0
};

const char *GetFuncNameByFuncType(FUNC_TYPE funcType) {
	for (int i = 0; theFuncNameList[i].m_funcName != NULL; i++) {
		if (theFuncNameList[i].m_funcType == funcType)
			return theFuncNameList[i].m_funcName;
	}
	return "";
}

FUNC_TYPE GetFuncTypeByFuncName(const char *funcName) {
	for (int i = 0; theFuncNameList[i].m_funcName != NULL; i++) {
		if (strcmp(theFuncNameList[i].m_funcName, funcName) == 0)
			return theFuncNameList[i].m_funcType;
	}
	return (FUNC_TYPE)0;
}

int CThreadCall::ThreadProc() {
	int iRet = -1;
	BOOL done = DMC_FALSE;
	CCmdFilePath appfile(m_appfile, m_paramEncode);
	CCmdFilePath txtfile(m_txtfile, m_paramEncode);
#ifdef DMC_WIN
	if (m_paramEncode == PE_UTF8) {
		switch (m_funcType) {
		case FT_GET_TEXT_V5:
			iRet = DMC_GetText_V5W(appfile, txtfile, &m_textInfo_V5, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PAGE_TEXT_V5:
			iRet = DMC_GetPageText_V5W(appfile, txtfile, &m_textInfo_V5, &m_pages, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PROPERTY_V5:
			iRet = DMC_GetProperty_V5W(appfile, &m_textInfo_V5, &m_property);
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V5.GroupName);
			break;
		case FT_GET_PWD_TEXT_V5:
			iRet = DMC_GetPwdText_V5W(appfile, txtfile, &m_textInfo_V5, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PAGE_TEXT_V5:
			iRet = DMC_GetPwdPageText_V5W(appfile, txtfile, &m_textInfo_V5, &m_pages, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PROPERTY_V5:
			iRet = DMC_GetPwdProperty_V5W(appfile, &m_textInfo_V5, &m_property, (Byte *)m_password.c_str());
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V5.GroupName);
			break;
		case FT_GET_TEXT_STREAM_V5:
		case FT_GET_PAGE_TEXT_STREAM_V5:
			iRet = ToStreamDmc(appfile, txtfile);
			break;
		default:
			printf("not implemented.\n");
			return iRet;
		}
		done = DMC_TRUE;
	}
#endif
	if (!done) {
		switch (m_funcType) {
		case FT_GET_TEXT_V5:
			iRet = DMC_GetText_V5(appfile, txtfile, &m_textInfo_V5, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PAGE_TEXT_V5:
			iRet = DMC_GetPageText_V5(appfile, txtfile, &m_textInfo_V5, &m_pages, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PROPERTY_V5:
			iRet = DMC_GetProperty_V5(appfile, &m_textInfo_V5, &m_property);
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V5.GroupName);
			break;
		case FT_GET_PWD_TEXT_V5:
			iRet = DMC_GetPwdText_V5(appfile, txtfile, &m_textInfo_V5, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PAGE_TEXT_V5:
			iRet = DMC_GetPwdPageText_V5(appfile, txtfile, &m_textInfo_V5, &m_pages, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PROPERTY_V5:
			iRet = DMC_GetPwdProperty_V5(appfile, &m_textInfo_V5, &m_property, (Byte *)m_password.c_str());
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V5.GroupName);
			break;
		case FT_GET_TEXT_V4:
			iRet = DMC_GetText_V4(appfile, txtfile, &m_textInfo_V4, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PAGE_TEXT_V4:
			iRet = DMC_GetPageText_V4(appfile, txtfile, &m_textInfo_V4, &m_pages, (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PROPERTY_V4:
			iRet = DMC_GetProperty_V4(appfile, &m_textInfo_V4, &m_property);
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V4.GroupName);
			break;
		case FT_GET_PWD_TEXT_V4:
			iRet = DMC_GetPwdText_V4(appfile, txtfile, &m_textInfo_V4, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PAGE_TEXT_V4:
			iRet = DMC_GetPwdPageText_V4(appfile, txtfile, &m_textInfo_V4, &m_pages, (Byte *)m_password.c_str(), (DMC_OLEERR_CALLBACK)ThreadCallBack);
			break;
		case FT_GET_PWD_PROPERTY_V4:
			iRet = DMC_GetPwdProperty_V4(appfile, &m_textInfo_V4, &m_property, (Byte *)m_password.c_str());
			if (iRet == 0)
				WritePropertyToFile(txtfile, &m_property, m_textInfo_V4.GroupName);
			break;
		case FT_GET_TEXT_STREAM_V5:
		case FT_GET_PAGE_TEXT_STREAM_V5:
		case FT_GET_TEXT_STREAM_V4:
		case FT_GET_PAGE_TEXT_STREAM_V4:
			iRet = ToStreamDmc(appfile, txtfile);
			break;
		default:
			printf("not implemented.\n");
			return iRet;
		}
	}
	printf("%s%s", GetFuncNameByFuncType(m_funcType), m_paramEncode == PE_UTF8 ? "W" : "");
	printf(" from ");
	appfile.print();
	printf(" to ");
	txtfile.print();
	if (iRet == 0) {
		printf(" succeeded");
		switch (m_funcType) {
		case FT_GET_PAGE_TEXT_V5:
		case FT_GET_PWD_PAGE_TEXT_V5:
		case FT_GET_PAGE_TEXT_STREAM_V5:
		case FT_GET_PAGE_TEXT_V4:
		case FT_GET_PWD_PAGE_TEXT_V4:
		case FT_GET_PAGE_TEXT_STREAM_V4:
			printf(", total pages: %d", m_pages);
			break;
		}
		printf(".\n");
	}
	else {
		printf(" failed, error code: %d\n", iRet);
	}
	return iRet;
}

static int CutZero( const char* str, int nlen,Byte* GroupName )
{
	int i=0;
	Byte  dw=0;
	Word  dw1=0;
	DWord dw2=0;

	if(!strcmp((const char*)GroupName,"ISO-10646-UCS-2") || !strcmp((const char*)GroupName,"UTF-16") ){
		for(i=0; i<nlen; i+=2) {
			dw1= *(Word*)(str+i);
			if( dw1 == 0 ) break;
		}
	}
	else if(!strcmp((const char*)GroupName,"ISO-10646-UCS-4")){
		for(i=0; i<nlen; i+=4) {
			dw2= *(DWord*)(str+i);
			if( dw2 == 0 ) break;
		}
	}
	else{
		for(i=0; i<nlen; i+=1) {
			dw= *(str+i);
			if( dw == 0 ) break;
		}
	}

	return i;
}

static void WriteFileString( FILE* fp, const char* str, int nlen,Byte* GroupName )
{
	int n= CutZero(str, nlen,GroupName);
	if( n>0 ) 
		fwrite(str,1,n,fp);
	else 
		fwrite("\0",1,1,fp);
}

static int APP_FileTellSize( FILE* file )
{
	int fSize = 0;
	int fCur = 0;

	fCur = ftell(file);
	if(fCur < 0) return -1;
	fseek(file, 0, SEEK_END);
	fSize = ftell( file );
	if(fSize < 0) return -1;
	fseek( file, fCur, SEEK_SET);
	return fSize;
}


int WritePropertyToFile(CCmdFilePath& filename, DMC_PROPERTY* pProp, Byte* GroupName)
{
	FILE* fp = filename.FOpenForWrite();
	if (!fp) {
		printf("can't open ");
		filename.print();
		printf("\n");
		return FileCantOpen;
	}

	WriteFileString(fp, pProp->title,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->author,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->keyword,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->subject,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->comment,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->manager,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->company,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->category,		MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->createdate,		MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->revision,		MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->lastrevisor,		MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->revisioncount,	MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->lastprintdate,	MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->edittime,		MAXDATABUF,GroupName);
	/*WriteFileString(fp, pProp->lastrevidate,	MAXDATABUF);*/
	WriteFileString(fp, pProp->creator,			MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->producer,		MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->encryptionflag,	32,GroupName);
	/*WriteFileString(fp, pProp->operat,			MAXCHARBUF);*/
	WriteFileString(fp, pProp->slides,			MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->paragraphs,		MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->bytes,			MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->notes,			MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->presentation,	MAXCHARBUF,GroupName);
	WriteFileString(fp, pProp->doctype,			MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->lastsavetime,	MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->owner,			MAXDATABUF,GroupName);
	
	/* word perfect */
	WriteFileString(fp, pProp->abstract, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->account, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->address, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->attachments, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->authorization, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->bill_to, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->blind_copy, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->carbon_copy, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->checked_by, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->client, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->department, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->descriptive_name, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->descriptive_type, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->destination, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->disposition, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->division, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->document_number, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->editor, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->forward_to, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->group, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->language, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->mail_stop, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->matter, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->office, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->project, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->publisher, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->purpose, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->received_from, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->recorded_by, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->recorded_date, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->reference, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->revision_date, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->revision_notes, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->section, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->security, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->source, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->status, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->telephone_number, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->typist, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->version_date, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->version_notes, MAXDATABUF,GroupName);
	WriteFileString(fp, pProp->version_number, MAXDATABUF,GroupName);

	long filesize=APP_FileTellSize(fp);
	if(filesize<0){
		return OtherProblems;
	}
	else if(filesize==0){
		if(fp){
			fclose(fp);
			filename.Remove();
		}
		return NoTextStringFound;
	}
	if(fp){
		fclose(fp);
	}
	return DMC_TRUE;
}
