// AsciiCE2.cpp : Implementation of CAsciiCE

#include "stdafx.h"
#include "CEPrEngine.h"
#include "PRCE_DLL_ASCIICE.h"
#include "MiscShared.h"

#ifdef USE_ASCII

/////////////////////////////////////////////////////////////////////////////
// New to AsciiCE2
BOOL FLAG_JustFormfed=FALSE;

int nMaxBuff,nCurBuffCnt,nNextBuffIx,nLastBuffIx;
DWORD m_dThreadId;
BYTE* lpReadBuff=NULL;
HANDLE hAsciiThread=NULL;
HANDLE hReadMutex=NULL;

BOOL QuitReadThread=FALSE;
BOOL ReadThreadRunning=FALSE;
BOOL ReadThreadStarted=FALSE;

int sav_globPort,sav_globSpeed,sav_globHandshake,sav_globPrType;

#ifdef USE_ATLCOM

int AsciiCE2_ctr=0;
/****************************************************************************
\****************************************************************************/
CAsciiCE2::CAsciiCE2() {
	if (AsciiCE2_ctr++>0) {
		PrCEMsgBox(IDS_MULTINSTASCIICE2);
	}
	FLAG_IsRunMode=true;
	HRESULT hRet=GetAmbientUserMode(FLAG_IsRunMode);
	if (FAILED(hRet)) {
		FLAG_IsRunMode=TRUE;
	}
	if (globAsciiCE2==NULL) globAsciiCE2=this;
	ASC_StartUp(&dummyabort);
}

/****************************************************************************
\****************************************************************************/
CAsciiCE2::~CAsciiCE2() {
	ASC_ShutDown(&dummyabort);
	AsciiCE2_ctr--;
	if (AsciiCE2_ctr<=0) globAsciiCE2=NULL;
}

/****************************************************************************
\****************************************************************************/
HRESULT CAsciiCE2::OnDraw(ATL_DRAWINFO& di)
{
	HRESULT hRet=GetAmbientUserMode(FLAG_IsRunMode);
	if (FAILED(hRet)) {
		FLAG_IsRunMode=TRUE;
	}
	if (FLAG_IsRunMode) return S_OK;

	RECT& rc = *(RECT*)di.prcBounds;
	HBRUSH hBrush, hOldBrush;
	hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
	hOldBrush = (HBRUSH)SelectObject(di.hdcDraw, hBrush);
	Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
	SelectObject(di.hdcDraw, hOldBrush);

	LPCTSTR pszText = _T("AsciiCE2");
	DrawText(di.hdcDraw, pszText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	return S_OK;
}

#include <comdef.h>
/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::Text(BSTR TextString)
{
	//USES_CONVERSION;

	if (TextString==NULL || !CheckAscii()) {
		return S_OK;
	}


	//char *outstr=OLE2A(TextString);
	//int slen=strlen(outstr);
	//PrintBuff((BYTE*) outstr,slen);

	int blen=SysStringLen(TextString);
	PrintStr((LPTSTR) TextString,blen);

/* NOTE: OLE2A doesn't allow for BSTRs that have "0" in string... tried
     adding the code below but it had problems if called from eVC with simple
	 _T() (non-BSTR) string. So just won't support BSTR strings with 
	 embedded zeros
	DWORD *dptr=((DWORD*) TextString)-1;
	slen=((int) *dptr)/2;
	outstr=(char*) LocalAlloc(LPTR,slen+1);
	char* bptr=outstr;
	SHORT* sptr=(SHORT*) TextString;
	for (int lp=0;lp<slen;lp++) {
		*(bptr++) = (char) *(sptr++);
	}
	PrintBuff((BYTE*) outstr,slen);
	LocalFree(outstr);
*/
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::CrLf()
{
	ASC_CrLf(&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::Char(long ch)
{
	ASC_Char(ch,&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::RepeatChar(long ch, long repeatcnt)
{
	ASC_RepeatChar(ch,repeatcnt,&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::FormFeed()
{
	ASC_FormFeed(&dummyabort);
	return S_OK;
}

/*  see PrCEUser.h
// SelectPort() - Port parameter
#define PORT_PRINTERCE			-1		//Shared between AsciiCE and PrinterCE
#define PORT_COM1				 0 
#define PORT_COM2				 1
#define PORT_LPT				 2 
#define PORT_IR					 3
#define PORT_COM3			 	 4
#define PORT_COM4				 5
#define PORT_COM5				 6
#define PORT_COM6				 7
#define PORT_TOFILE				 8
#define PORT_NETPATH			 9
#define PORT_IP					10
#define PORT_SOCKETCOM			11
#define PORT_ANYCOM				12
#define PORT_COM7				13
#define PORT_COM8				14
#define PORT_COMPAQ				15
#define PORT_BELKIN				16
#define PORT_COM9				17
#define PORT_BTQUIKPRINT		18
#define PORT_COM0				19
//--------------------------------
#define MAXPORTS				20

#define SOFTWARE_HANDSHAKE	0
#define HARDWARE_HANDSHAKE	1
#define NO_HANDSHAKE		2

#define S_4800		0
#define S_9600		1
#define S_19200		2
#define S_38400		3
#define S_57600		4
#define S_115200	5
*/

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::SelectPort(long Port,long BaudRate,long Handshake,long *ErrVal)
{
#ifdef DEBUG
//	DbgPrintf(_T("2:Port=%d, baud=%d, handsh=%d"),Port,BaudRate,Handshake);
#endif


	AbortPrint=FALSE;
	*ErrVal = (ASC_SelectPort(Port,BaudRate,Handshake,0,&dummyabort)) ? VARIANT_TRUE : VARIANT_FALSE;
	return S_OK;
}

/*****************************************************************************
AsciiCE can share same port as PrinterCE IF:
 - PrinterCE is created and the port is selected before calling AsciiCE's SelectPort
 - The "Port" is defined as "PORT_PRINTERCE"
*****************************************************************************/
STDMETHODIMP CAsciiCE2::SelectPortEx(long Port,long BaudRate,long Handshake,long ReadBufferSize,long *ErrVal)
{
#ifdef DEBUG
//	DbgPrintf(_T("2ex:Port=%d, baud=%d, handsh=%d, readbuff=%d"),Port,BaudRate,Handshake,ReadBufferSize);
#endif
	AbortPrint=FALSE;
	*ErrVal = (ASC_SelectPort(Port,BaudRate,Handshake,ReadBufferSize,&dummyabort)) ? VARIANT_TRUE : VARIANT_FALSE;
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::ClosePort()
{
	ASC_ClosePort(&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::Init(BSTR RegID, BOOL *pSuccess)
{
	//SEE ALSO PrinterCE::Init()
	USES_CONVERSION;

	LPTSTR id=OLE2W(RegID);
	*pSuccess = (ProcessRegistration(id)==0) ? VARIANT_FALSE : VARIANT_TRUE;
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::get_Capabilities(long *pVal)
{
	*pVal=globGetCapabilities();
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::get_Peek(long *pVal)
{
	*pVal=ASC_Peek(&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::PrDialogBoxText(BSTR MainText, BSTR TitleText, BSTR CancelBtnText)
{
	SharedPrDialogBoxText(MainText,TitleText,CancelBtnText);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::get_StatusCheck(long *pVal)
{
	*pVal=(StartedPageFlag) ? AbortPrint : LastPageErr;
	//New 6/17/02
	if (*pVal==vbAbortOperation) {
		AbortPrint=LastPageErr=FALSE;
	}
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::put_SetErrorLevel(long newVal)
{
	/* Error Levels:
		#define vbErrLevelNone	0 // No errors returned (can access via StatusCheck())
		#define vbErrLevelAll	1 // All Errors returned
		#define vbErrLevelTask	2 // Only AbortPrint and AbortLastTask returned (not User Cancel)
		#define vbErrLevelJob	3 // Only AbortPrint returned
	*/
	if (newVal<0 || newVal>3) {
		AbortOperationError(ERR_INVALIDARG);
	}
	else CurErrLevel=newVal;
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::put_SetReportLevel(long newVal)
{
	/*
		#define vbReportErrors				0
		#define vbNoReportErrors			1
		#define vbReportSeriousErrors		2
		#define vbNoReportErrorsSkipCancel	3
	*/
	if (newVal<vbReportErrors || newVal>vbNoReportErrorsSkipCancel) {
		AbortOperationError(ERR_INVALIDARG);
	}
	else FLAG_ReportLevel=newVal;
	return S_OK;
}


/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::PrDialogBox(long Operation, long* Status)
{
	*Status=SharedPrDialogBox(Operation);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::get_GetVersion(long *pVal)
{
	*pVal=VERSION_ID;
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::get_About(BSTR *pVal)
{
	USES_CONVERSION;
	TCHAR BuildStr[180];
	wsprintf(BuildStr,_T("%s\r%s (%s) - %s\r%s"),ID_STRING,ID_PLATFORM,ID_PROCESSOR,VERSION_STRING,ID_COMPANY);
	*pVal=SysAllocString(T2OLE(BuildStr));
	return S_OK;
}

#define READMODE_NORMAL		0
#define READMODE_FLUSHZEROS	1

//#define READMODE_
#define READRESULT_ERR			0
#define READRESULT_OK			1
#define READRESULT_FULLBUFFER	2
#define READRESULT_TIMEOUT		3


/*****************************************************************************
*****************************************************************************/
/*
long CopyBufferToVariantArray(VARIANT *inVar,BYTE* buff,long bcnt)
{
	VARIANT *pvbSrc;
	SAFEARRAY FAR * psa;

	VARTYPE vttype=inVar->vt;

	if ((vttype & VT_ARRAY) == 0) return 0;	//Not an array
	vttype &= (~VT_ARRAY);
	BOOL byref=(vttype & VT_BYREF);
	vttype &= (~VT_BYREF);
	psa=(byref) ? *(inVar->pparray) : inVar->parray;
	HRESULT hr;

	int lp;
	//NOTE: Add check for size of array
	long ubound,lbound;
	SafeArrayGetLBound(psa,1,&lbound);
	SafeArrayGetUBound(psa,1,&ubound);
	BYTE *bBuff;
	USHORT *sBuff;
	ULONG *lBuff;
	if (lbound>0) return 0;
	if (ubound<bcnt) bcnt=ubound;

	switch (vttype) {
	case VT_VARIANT:
		hr= SafeArrayAccessData(psa,(void**)&pvbSrc);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++,pvbSrc++) {
			pvbSrc->bVal = (BYTE) buff[lp];
			pvbSrc->vt = VT_UI1;
		} //for
		break;
	case VT_UI1:
	case VT_I1:
		hr = SafeArrayAccessData(psa,(void**)&bBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			bBuff[lp]=(BYTE) buff[lp];
		}
		break;
	case VT_UI2:
	case VT_I2:
		hr = SafeArrayAccessData(psa,(void**)&sBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			sBuff[lp]=(USHORT) buff[lp];
		}
		break;
	case VT_UI4:
	case VT_I4:
		hr = SafeArrayAccessData(psa,(void**)&lBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			lBuff[lp]=(ULONG) buff[lp];
		}
		break;
	}
	SafeArrayUnaccessData(psa);
	return bcnt;
}
*/

/*****************************************************************************
*****************************************************************************/
long CopyVariantArrayToBuffer(VARIANT *inVar,BYTE* buff,long bcnt)
{
	USES_CONVERSION;
	VARIANT *pvbSrc;
	SAFEARRAY FAR * psa;

	unsigned short vttype=inVar->vt;


	if ((vttype & VT_TYPEMASK)==VT_BSTR) {
//	if ((vttype & VT_BSTR)!=0) {
		//If passes 0 for bcnt, use string length
		if (bcnt==0) {
			bcnt=SysStringLen(inVar->bstrVal);
		}

		//Have to decide if convert to ASCII or just dump whole array.
		//if (blen>=bcnt) {
		TCHAR *tptr=OLE2T(inVar->bstrVal);
		char *cptr=T2A(tptr);	// allocated on the stack, so is freed on return
		//int tmplen=strlen(cptr);
		//if (tmplen<bcnt) bcnt=tmplen;
		memcpy(buff,cptr,bcnt);
		return bcnt;

	}
	if ((vttype & VT_ARRAY) == 0) return 0;	//Not an array
//	vttype &= (~VT_ARRAY);
	BOOL byref=(vttype & VT_BYREF);
//	vttype &= (~VT_BYREF);

	vttype &= VT_TYPEMASK;

	psa=(byref) ? *(inVar->pparray) : inVar->parray;
	HRESULT hr;

	int lp;

	//NOTE: Add check for size of array
	long ubound,lbound;
	SafeArrayGetLBound(psa,1,&lbound);
	SafeArrayGetUBound(psa,1,&ubound);
	BYTE *bBuff;
	USHORT *sBuff;
	ULONG *lBuff;
	if (lbound>0) return 0;
//JTFF 9/11/01	if (ubound<bcnt) bcnt=ubound;
	if (ubound<bcnt) bcnt=ubound+1;
	

	switch (vttype) {
	case VT_BSTR:
	case VT_VARIANT:
		hr= SafeArrayAccessData(psa,(void**)&pvbSrc);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++,pvbSrc++) {
			switch (pvbSrc->vt) {
			case VT_UI1:
			case VT_I1:
				buff[lp]=(BYTE) pvbSrc->bVal;
				break;
			case VT_UI2:
			case VT_I2:
				buff[lp]=(BYTE) pvbSrc->iVal;
				break;
			case VT_UI4:
			case VT_I4:
				buff[lp]=(BYTE) pvbSrc->lVal;
				break;
			default:
				//unrecognized...
				bcnt--;
				break;
			}
		} //for
		break;
	case VT_UI1:
	case VT_I1:
		hr = SafeArrayAccessData(psa,(void**)&bBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			buff[lp]=(BYTE) bBuff[lp];
		}
		break;
	case VT_UI2:
	case VT_I2:
		hr = SafeArrayAccessData(psa,(void**)&sBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			buff[lp]=(BYTE) sBuff[lp];
		}
		break;
	case VT_UI4:
	case VT_I4:
		hr = SafeArrayAccessData(psa,(void**)&lBuff);
		if (FAILED(hr)) return 0;
		for (lp=0;lp<bcnt;lp++) {
			buff[lp]=(BYTE) lBuff[lp];
		}
		break;
	default:
		//unrecognized...
		bcnt=0;
		break;
	} //switch
	SafeArrayUnaccessData(psa);
	return bcnt;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::Write(unsigned char * lpBuffer,long nNumberOfBytesToWrite,long* lpNumberOfBytesWritten)
{
	*lpNumberOfBytesWritten=ASC_Write(lpBuffer,nNumberOfBytesToWrite,&dummyabort);
	return S_OK;

	long written;
	written=ASC_Write(lpBuffer,nNumberOfBytesToWrite,&dummyabort);
	if (lpNumberOfBytesWritten) {
		*lpNumberOfBytesWritten=written;
	}
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::WriteVar(VARIANT* lpBuffer,long nNumberOfBytesToWrite,VARIANT* lpNumberOfBytesWritten)
{
	lpNumberOfBytesWritten->vt=VT_I4;
	if (!CheckAscii()) {
		lpNumberOfBytesWritten->lVal=0;
		return S_OK;
	}
	long cnt=nNumberOfBytesToWrite;
	BYTE *tmpbuff=(BYTE*) LocalAlloc(LPTR,cnt+1);

	cnt=CopyVariantArrayToBuffer(lpBuffer,tmpbuff,cnt);

	lpNumberOfBytesWritten->lVal=PrintBuff((BYTE*) tmpbuff,cnt);
	LocalFree(tmpbuff);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::ReadString(long nMaxChars,long nLastChar,long nModeFlags,long nTimeToWait,long* lpResultFlags,long *lpCharsRead,BSTR *lpString)
{
	USES_CONVERSION;

	if (!CheckAscii()) {
		*lpCharsRead=0;
		return S_OK;
	}
	BYTE *tmpBuff=(BYTE*) LocalAlloc(LPTR,nMaxChars+1);
	//Read(nMaxChars,nLastChar,nModeFlags,nTimeToWait,lpResultFlags,lpCharsRead,tmpBuff);
	*lpCharsRead=ASC_Read(nMaxChars,nLastChar,nModeFlags,nTimeToWait,(int*) lpResultFlags,tmpBuff,&dummyabort);
	*lpString = SysAllocString(A2OLE((char*) tmpBuff));
	LocalFree(tmpBuff);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::ReadStringVar(long nMaxChars,long nLastChar,long nModeFlags,long nTimeToWait,VARIANT* lpResultFlags,VARIANT *lpCharsRead,BSTR *lpString)
{
	long ResultFlags,CharsRead;
	lpCharsRead->vt=VT_I4;
	lpResultFlags->vt=VT_I4;
	if (!CheckAscii()) {
		lpCharsRead->lVal=0;
		lpResultFlags->lVal=(AbortPrint==ERR_USERCANCELLED) ? READRESULT_USERCANCEL : READRESULT_ERR;
		return S_OK;
	}
	ReadString(nMaxChars,nLastChar,nModeFlags,nTimeToWait,&ResultFlags,&CharsRead,lpString);
	lpCharsRead->lVal=CharsRead;
	lpResultFlags->lVal=ResultFlags;
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::ReadChar(short* bval)
{
	*bval=ASC_ReadChar(&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::Read(long nMaxBytes,long nLastChar, long nModeFlags,long nTimeToWait,long* lpResultFlags,long *lpBytesRead,unsigned char *lpBuffer)
//STDMETHODIMP CAsciiCE2::Read(long nMaxBytes,long nLastChar, long nModeFlags,long nTimeToWait,long* lpResultFlags,long *lpBytesRead,char *lpBuffer)
{
	*lpBytesRead=ASC_Read(nMaxBytes,nLastChar,nModeFlags,nTimeToWait,(int*) lpResultFlags,lpBuffer,&dummyabort);
	return S_OK;
}

/*****************************************************************************
*****************************************************************************/
STDMETHODIMP CAsciiCE2::ReadVar(long nMaxBytes,long nLastChar, long nModeFlags,long nTimeToWait,VARIANT* lpResultFlags,VARIANT *lpBytesRead,VARIANT *lpBuffer)
{
	lpBytesRead->vt=VT_I4;
	lpResultFlags->vt=VT_I4;
	if (!CheckAscii()) {
		lpBytesRead->lVal=0;
		lpResultFlags->lVal=(AbortPrint==ERR_USERCANCELLED) ? READRESULT_USERCANCEL : READRESULT_ERR;
		return S_OK;
	}
	BYTE *tmpbuff=(BYTE*) LocalAlloc(LPTR,nMaxBytes+1);
	long tmpResultsFlags,tmpBytesRead;
	//Read buffer
	tmpBytesRead=ASC_Read(nMaxBytes,nLastChar,nModeFlags,nTimeToWait,(int*) &tmpResultsFlags,tmpbuff,&dummyabort);

//Chgd with v2.11
//	tmpBytesRead=CopyBufferToVariantArray(lpBuffer,tmpbuff,tmpBytesRead);
//New:
	lpBuffer->bstrVal=CComBSTR(tmpBytesRead+1,(char*) tmpbuff);
	lpBuffer->vt=VT_BSTR;


	lpBytesRead->lVal=tmpBytesRead;
	lpResultFlags->lVal=tmpResultsFlags;
	LocalFree(tmpbuff);
	return S_OK;
}

#endif //#ifdef USE_ASCII
#endif
