// ProductInfoCtl.cpp : Implementation of the CProductInfoCtrl ActiveX Control class.

#include "stdafx.h"
#include <sys/stat.h>
#include "ProductInfo.h"
#include "ProductInfoCtl.h"
#include "ProductInfoPpg.h"
#include "ModeSet.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

char FileBuffer[128];

IMPLEMENT_DYNCREATE(CProductInfoCtrl, COleControl)

short   LastError;

typedef enum
    {
      NONE,
      FailToConnect,
    } LASTERROR;

/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CProductInfoCtrl, COleControl)
	//{{AFX_MSG_MAP(CProductInfoCtrl)
	// NOTE - ClassWizard will add and remove message map entries
	//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG_MAP
	ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CProductInfoCtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CProductInfoCtrl)
	DISP_FUNCTION(CProductInfoCtrl, "PortSet", PortSet, VT_I2, VTS_BSTR VTS_I4 VTS_I2 VTS_BSTR VTS_I2 VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "Open", Open, VT_I2, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "Close", Close, VT_BOOL, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "GetMode", GetMode, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SetMode", SetMode, VT_BOOL, VTS_BSTR VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "Commit", Commit, VT_BOOL, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "Restart", Restart, VT_BOOL, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "GetModeSize", GetModeSize, VT_I2, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "GetModeType", GetModeType, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "GetFirstModeName", GetFirstModeName, VT_BSTR, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "GetNextModeName", GetNextModeName, VT_BSTR, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "GetModeHelp", GetModeHelp, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "GetLastError", GetLastError, VT_I2, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "GetNVRamMode", GetNVRamMode, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendTerminate", SendTerminate, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "SendModeSet", SendModeSet, VT_BOOL, VTS_BSTR VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendModeQuery", SendModeQuery, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendRegistration", SendRegistration, VT_BOOL, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "SendDataNOP", SendDataNOP, VT_BOOL, VTS_NONE)
	DISP_FUNCTION(CProductInfoCtrl, "SendImageToDisplay", SendImageToDisplay, VT_BOOL, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendFile", SendFile, VT_BOOL, VTS_BSTR VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendDisplayText", SendDisplayText, VT_BOOL, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "SendSpecialText", SendSpecialText, VT_BOOL, VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "Push", Push, VT_BOOL, VTS_BSTR VTS_BSTR VTS_BSTR)
	DISP_FUNCTION(CProductInfoCtrl, "ReOpen", ReOpen, VT_I2, VTS_BSTR)
	//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CProductInfoCtrl, COleControl)
	//{{AFX_EVENT_MAP(CProductInfoCtrl)
	// NOTE - ClassWizard will add and remove event map entries
	//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CProductInfoCtrl, 1)
	PROPPAGEID(CProductInfoPropPage::guid)
END_PROPPAGEIDS(CProductInfoCtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CProductInfoCtrl, "PRODUCTINFO.ProductInfoCtrl.1",
	0x3c80ddc6, 0xc4a3, 0x11d6, 0xa8, 0x56, 0, 0x50, 0x56, 0x40, 0x37, 0x37)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CProductInfoCtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DProductInfo =
		{ 0x3c80ddc4, 0xc4a3, 0x11d6, { 0xa8, 0x56, 0, 0x50, 0x56, 0x40, 0x37, 0x37 } };
const IID BASED_CODE IID_DProductInfoEvents =
		{ 0x3c80ddc5, 0xc4a3, 0x11d6, { 0xa8, 0x56, 0, 0x50, 0x56, 0x40, 0x37, 0x37 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwProductInfoOleMisc =
	OLEMISC_INVISIBLEATRUNTIME |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CProductInfoCtrl, IDS_PRODUCTINFO, _dwProductInfoOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::CProductInfoCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CProductInfoCtrl

BOOL CProductInfoCtrl::CProductInfoCtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegInsertable | afxRegApartmentThreading to afxRegInsertable.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_PRODUCTINFO,
			IDB_PRODUCTINFO,
			afxRegInsertable | afxRegApartmentThreading,
			_dwProductInfoOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::CProductInfoCtrl - Constructor

CProductInfoCtrl::CProductInfoCtrl()
{
	InitializeIIDs(&IID_DProductInfo, &IID_DProductInfoEvents);

	// TODO: Initialize your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::~CProductInfoCtrl - Destructor

CProductInfoCtrl::~CProductInfoCtrl()
{
	// TODO: Cleanup your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::OnDraw - Drawing function

void CProductInfoCtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
	// TODO: Replace the following code with your own drawing code.
	pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
	pdc->Ellipse(rcBounds);
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::DoPropExchange - Persistence support

void CProductInfoCtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.

}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::GetControlFlags -
// Flags to customize MFC's implementation of ActiveX controls.
//
// For information on using these flags, please see MFC technical note
// #nnn, "Optimizing an ActiveX Control".
DWORD CProductInfoCtrl::GetControlFlags()
{
	DWORD dwFlags = COleControl::GetControlFlags();


	// The control can activate without creating a window.
	// TODO: when writing the control's message handlers, avoid using
	//		the m_hWnd member variable without first checking that its
	//		value is non-NULL.
	dwFlags |= windowlessActivate;
	return dwFlags;
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl::OnResetState - Reset control to default state

void CProductInfoCtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}


/////////////////////////////////////////////////////////////////////////////
// CProductInfoCtrl message handlers

short CProductInfoCtrl::PortSet(LPCTSTR IPAddress, long DataRate, short DataBits, LPCTSTR Parity, short StopBits, LPCTSTR FlowControl) 
{
    char    stopbit[ 30 ];
    char    control[ 30 ];
    char    parity [ 30 ];

    strcpy( stopbit, ((StopBits == 1) ? "-cstopb" : "cstopb") );

    switch( *FlowControl )
      {
        case 'H':                                           /* Hardware */
            strcpy( control, "clocal crtscts -ixon" );
            break;
                                                            
        case 'X':                                           /* Xon/Xoff */
            strcpy( control, "clocal ixon -crtscts" );
            break;

        default:
            strcpy( control, "clocal -crtscts -ixon" );
        }


    switch( *Parity )
      {
        case 'E':                                           /* Even     */
            strcpy( parity, "parenb -parodd" );
            break;
                                                            
        case 'O':                                           /* Odd      */
            strcpy( parity, "parenb parodd" );
            break;

        default:
            strcpy( parity, "-parenb" );
        }


    sprintf( FileBuffer, 
	         "stty -F /dev/ttyS0 ispeed %d ospeed %d cs%d %s %s icrnl hupcl -icanon %s cread -echo -echoe -echok min 1\n", 
              DataRate, DataRate, DataBits, stopbit, parity, control );

    return PushBuffer( IPAddress, FileBuffer, "setscanner2" ); 
}


short CProductInfoCtrl::Open(LPCTSTR IPAddress) 
{
        LastError = NONE;

        if ( !connectUnit(IPAddress) )
        {
            LastError = FailToConnect; 
            return 0; 
        }

        NumberOfModes = InitModeArray( );
        return NumberOfModes;
}


BOOL CProductInfoCtrl::Close( void ) 
{
        return disconnectUnit( );
}


BSTR CProductInfoCtrl::GetMode(LPCTSTR ModeName) 
{
	    CString      strResult;

        getMode( ModeName, strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();

        return strResult.AllocSysString();
}

BOOL CProductInfoCtrl::SetMode(LPCTSTR ModeName, LPCTSTR ModeValue) 
{
    char    Mode[ 255 ];

    sprintf( Mode, "%s = %s", ModeName, ModeValue );
    SendPacket( pkt, Mode );
    return RecvPacket( pkt );
}



BOOL CProductInfoCtrl::Commit( void )
{
        SetMode( "Commit", "TRUE" );
        return TRUE;
}

BOOL CProductInfoCtrl::Restart( void ) 
{
    SendPacket( pkt, "RESTART=TRUE" );
    return TRUE;
}

short CProductInfoCtrl::GetModeSize(LPCTSTR ModeName) 
{
    int i;

    i = GetNameIndex( ModeName );
    return mode[ i ].Size;
}


BSTR CProductInfoCtrl::GetModeType(LPCTSTR ModeName) 
{
	    CString      strResult;

        getModeType( ModeName, strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();

        return strResult.AllocSysString();
}


BSTR CProductInfoCtrl::GetFirstModeName( void ) 
{
	    CString      strResult;

        getFirstModeName( strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();

        return strResult.AllocSysString();
}


BSTR CProductInfoCtrl::GetNextModeName( void ) 
{
	    CString      strResult;

        getNextModeName( strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();
        return strResult.AllocSysString();
}



BSTR CProductInfoCtrl::GetModeHelp(LPCTSTR ModeName) 
{
	    CString      strResult;

        getModeHelp( ModeName, strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();
        return strResult.AllocSysString();
}

BSTR CProductInfoCtrl::GetNVRamMode(LPCTSTR ModeName) 
{
	    CString      strResult;

        getNVRamMode( ModeName, strResult.GetBuffer(BUFFER_SIZE), BUFFER_SIZE);
	    strResult.ReleaseBuffer ();

        return strResult.AllocSysString();
}


short CProductInfoCtrl::GetLastError() 
{
	return LastError;
}



void CProductInfoCtrl::SendTerminate() 
{
    int	total  = 0;

    memset( pkt,0,BUFFER_SIZE);

    total = sizeof( pkt->header ) + 1;
    pkt->header.token = SLT_TERMINATE;
    pkt->header.length = htonl( total);

    sendPacket( (char *) pkt, ntohl( pkt->header.length ));
}


BOOL  SendMode( LPCTSTR Mode )
{
    int	  total  = 0;

    memset( pkt,0,BUFFER_SIZE);

    total = sizeof( pkt->header ) + strlen( Mode ) + 1;
    pkt->header.token = SLT_MODESETQUERY;
    pkt->header.length = htonl( total);

    if( *Mode )
	    strcpy( pkt->body.modesetquery.modesetquery, Mode );

    return sendPacket( (char *) pkt, ntohl( pkt->header.length ));
}


BOOL CProductInfoCtrl::SendModeSet(LPCTSTR ModeName, LPCTSTR ModeValue) 
{
    char  Mode[ 255 ];

    sprintf( Mode, "%s = %s", ModeName, ModeValue );

    return SendMode( Mode );
}

BSTR CProductInfoCtrl::SendModeQuery(LPCTSTR ModeName) 
{
	  CString   strResult;
    LPTSTR    Buffer;
    char     *p;
    int       total;

    SendMode( ModeName );

    RecvPacket( pkt );

    p = pkt->body.moderesponse.moderesponse;

    total = strcspn( p, " =\t" ); 

    p   += total;
    p   += strspn( p, "= \t" );
    total = strcspn( p, "\n\r\t" );

    Buffer = strResult.GetBuffer(BUFFER_SIZE);
    
    strncpy( Buffer, p, total );
    Buffer[ total ] = 0;
    ClearTrailingWhiteSpace( Buffer );

	  return strResult.AllocSysString();
}

BOOL CProductInfoCtrl::SendRegistration() 
{
    int	  total  = 0;

    memset( pkt,0,BUFFER_SIZE);

    total = sizeof( pkt->header ) + 1;
    pkt->header.token = SLT_REGISTRATION;
    pkt->header.length = htonl( total);

    return sendPacket( (char *) pkt, ntohl( pkt->header.length ));
}

BOOL CProductInfoCtrl::SendDataNOP() 
{
    int	  total  = 0;

    memset( pkt,0,BUFFER_SIZE);

    total = sizeof( pkt->header ) + 1;
    pkt->header.token    = SLT_REGISTRATION;
    pkt->body.data.type	 = SLD_NOP;
    pkt->header.length   = htonl( total);

    return sendPacket( (char *) pkt, ntohl( pkt->header.length ));

	return TRUE;
}


BOOL SendBuffer( char *file, int fileSize, char *TargetFileName, SLOPPIFILE FileType )
{
    char  *cbuf;
    int		TargetPathSize = 0;
    
    memset( pkt,0,BUFFER_SIZE);

    cbuf = pkt->body.data.data.file.theFile;


    if( FileType == SLF_GIF )
    {
      if ( file )
        memcpy( (cbuf + TargetPathSize), file, fileSize + 1);
    }
    else 
    {
      if ( TargetFileName )
	      strcpy( cbuf, TargetFileName );

	    TargetPathSize = strlen( TargetFileName ) + 1;

      if ( file )
        memcpy( (cbuf + TargetPathSize), file, fileSize );
    }

    pkt->header.length			  = htonl(fileSize + sizeof (SLPACKET) + TargetPathSize);
    pkt->header.token			    = SLT_DATA;
    pkt->body.data.type		    = SLD_FILE;
    pkt->body.data.data.file.file.length   = htonl(fileSize);
    pkt->body.data.data.file.file.token    = (SLOPPITOKEN) FileType;

    return sendPacket( (char *)pkt, ntohl( pkt->header.length ));
}

BOOL localSendFile( LPCTSTR File, LPCTSTR TargetFileName, SLOPPIFILE FileType )
{
    struct      stat	cstat;
    char       *buf;
    FILE       *filePtr;
    BOOL        status = FALSE;

    if ( stat( File, &cstat ))
        return status;
  
    buf = ( char *) malloc( cstat.st_size );

    if ( !buf )
        return status;

    filePtr = fopen( File, "rb" );

    if ( filePtr )
    {
      if ( fread( buf, cstat.st_size, 1, filePtr ) )
        status = SendBuffer( (char*) buf, cstat.st_size, (char *) TargetFileName, FileType );
    
      fclose( filePtr );
    }

	  free( buf );

    return status;
}



BOOL CProductInfoCtrl::SendImageToDisplay( LPCTSTR File ) 
{
    return localSendFile(File, File, SLF_GIF );
}



BOOL CProductInfoCtrl::SendFile(LPCTSTR File, LPCTSTR TargetFileName) 
{
    return localSendFile(File, TargetFileName, SLF_FILE );
}


BOOL SendText( char *Text, SLOPPIDATA TextType )
{
    char  *cbuf;
    
    memset( pkt,0,BUFFER_SIZE);

    cbuf = pkt->body.data.data.info;

    if ( Text )
	    strcpy( cbuf, Text );

    pkt->header.length			  = htonl( strlen(Text) + 1 + sizeof (SLPACKET) );
    pkt->header.token			    = SLT_DATA;
    pkt->body.data.type		    = TextType;

    return sendPacket( (char *)pkt, ntohl( pkt->header.length ));
}


BOOL CProductInfoCtrl::SendDisplayText(LPCTSTR Text) 
{
    return SendText( (char *) Text, SLD_DISPLAYTEXT );
}


BOOL CProductInfoCtrl::SendSpecialText(LPCTSTR Text) 
{
    return SendText( (char *) Text, SLD_SPECIALTEXT );
}

BOOL CProductInfoCtrl::Push(LPCTSTR IPAddress, LPCTSTR File, LPCTSTR TargetFileName) 
{
	// TODO: Add your dispatch handler code here

	return PushFile( IPAddress, File, TargetFileName );
}

short CProductInfoCtrl::ReOpen(LPCTSTR IPAddress) 
{
	// TODO: Add your dispatch handler code here

    LastError = NONE;

    if ( !connectUnit(IPAddress) )
    {
        LastError = FailToConnect; 
        return 0; 
    }

    SendPacket( pkt, "ForceResponse=TRUE" );
    RecvPacket( pkt );
    SendPacket( pkt, "ForceError=TRUE" );
    RecvPacket( pkt );
    SendPacket( pkt, "ForceHelpText=TRUE" );
    RecvPacket( pkt );
     
    return TRUE;
}
