#include <iostream>
#include <conio.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire.h>
#ifdef linux
#else
  #include <mvDisplay/Include/mvDisplayWindow.h>
#endif

using namespace mvIMPACT::acquire;
using namespace std;

#ifdef linux
#define NO_DISPLAY
#define PRESS_A_KEY				\
		cout << "Press a key..." << endl;	\
		getchar();
#else
#undef NO_DISPLAY
#define PRESS_A_KEY				\
		cout << "Press a key..." << endl;	\
		_getch();
#endif

//-----------------------------------------------------------------------------
Device* getDeviceFromUserInput( const DeviceManager& devMgr )
//-----------------------------------------------------------------------------
{
	unsigned int devCnt = devMgr.deviceCount();
	if(devCnt == 0 )
	{
		cout << "No MATRIX VISION device found!" << endl;
		return 0;
	}

	// display every device detected
	for( unsigned int i=0; i<devCnt; i++ )
	{
		Device* pDev = devMgr[i];
		if( pDev )
		{
			cout << "[" << i << "]: " << pDev->serial.read() 
				<< " (" << pDev->product.read() << ", family: "
				<< pDev->family.read() << ")" << endl;
		}
	}

	// get user input
	cout << endl << "Please enter the number in front of the listed device followed by [ENTER] to open it: ";
	unsigned int devNr = 0;
	cin >> devNr;

	if( devNr >= devCnt )
	{
		cout << "Invalid selection!" << endl;
		return 0;
	}

	cout << "Using device number " << devNr << "." << endl;
	return devMgr[devNr];
}

//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
//-----------------------------------------------------------------------------
{
	DeviceManager devMgr;
	Device* psDev = getDeviceFromUserInput( devMgr );
	if( psDev == 0 )
	{
		cout << "Unable to continue!";
		PRESS_A_KEY
	}

	try
	{
		psDev->open();
	}
	catch( ImpactAcquireException& e )
	{
		// this e.g. might happen if the same device is already opened in another process...
		cout << "An error occurred while opening the device(error code: " << e.errCode() << "). Press any key to end the application..." << endl;
		PRESS_A_KEY
		return 0;
	}

	FunctionInterface sFI( psDev );

	// make sure there is at least 1 request to capture an image
	// requests are structures containing information for the driver how to capture an image
	// and return information about the image back to user when the image has been captured
	sFI.ensureRequests(1);

	// send a request to the default request queue of the device and wait for the result.
	sFI.imageRequestSingle();
	const int iMaxWaitTime_ms = 500;
	// wait for results from the default capture queue
	int iRequestNr = sFI.imageRequestWaitFor( iMaxWaitTime_ms );

	// check if the image has been captured without any problems
	if( !sFI.isRequestNrValid( iRequestNr ) )
	{
		// If the error code is -2119(DEV_WAIT_FOR_REQUEST_FAILED), the documentation will provide 
		// additional information under TDMR_ERROR in the interface reference (
		cout << "imageRequestWaitFor failed (" << iRequestNr << ")"
			 << ", timeout value too small?" << endl;
		return 0;
	}

	const Request* psRequest = sFI.getRequest(iRequestNr);
	if( !sFI.isRequestOK( psRequest ) )
	{
		cout << "ERROR! Code " << psRequest->getResult().result << endl;
		return 0;
	}
#ifndef NO_DISPLAY
	cout << "Please note that there will be just one refresh for the display window, so if it is" << endl
		 << "hidden under another window the result will not be visible." << endl;
	// everything went well. Display the result
	const ImageBuffer& sIB = psRequest->getImageBuffer();
	// initialise display window
	HDISP hDisp = mvInitDisplayWindow( "mvIMPACT_acquire sample" );
	mvShowDisplayWindow( hDisp );
	// tell the display were to find the data
	TDisp* pDisp = mvGetDisplayStructure( hDisp );
	mvDispSetImage( pDisp, sIB.vpData, sIB.iWidth, sIB.iHeight, sIB.pChannels[0].iPixelPitch*8, sIB.pChannels[0].iLinePitch );
	mvDispUpdate( pDisp );
#endif // NO_DISPLAY
	// unlock the buffer to let the driver know that you no longer need this buffer
	sFI.imageRequestUnlock( iRequestNr );

	cout << "Press any key to end the application" << endl;
	PRESS_A_KEY
#ifndef NO_DISPLAY
	// free resources
	mvDestroyImageWindow( hDisp );
#endif // NO_DISPLAY
	return 0;
}
