/*
*	©Copyright 2002-2006, Microsoft Corporation
*	Written by Sergey Vasilevskiy, 2002-2006.
*/

#include "stdafx.h"

#ifndef MAX_PORT
#define MAX_PORT 0xfffe	//for command-line parameter checking
#endif

using namespace TPCE;

HANDLE	hListenStopEvent;

//command-line parameters
unsigned short		shPort		= TRPort;
char*				szDBServer	= "localhost";
char*				szDB		= "tpce";
bool				bVerbose	= false;
eClientDriverType	eClientType = eMDAC;
char*				szMEEToUse	= NULL;

/*
*	Print command-line parameters
*/
void Usage(char *szProgName)
{
	cout<<"Usage: "<<endl;
	cout<<szProgName<<" -s database_server -d database -p port_to_listen_on -c [MDAC/SNAC] -m MEE_Name -v\n";
	cout<<"     -v causes verbose output\n\n";
    cout<<"     MEE_Name (from Benchcraft profile) is required if more than 1 MEE have been launched\n\n";
}

/*
 *       Make sure that the switch value falls between its valid
 *       min and max.  If not print an error message and reset the
 *       the switcth to a valid number.
 */
int CheckSwitch( int value, int min, int max, char *header ) 
{

    if ( value < min  ) {
        fprintf( stderr, "Number of %s must be >= %d - assuming %d\n", header, min, min );
        return( min );
     }
     else if ( value > max ) {
        fprintf( stderr, "Number of %s must be <= %d - assuming %d\n", header, max, max );
        return( max );
     }
     return( value );
}

/*
 *       Parse the command line.
 */
void ParseCommandLine( int argc, char *argv[] )
{
	int   arg;
	char  *sp;
	char  *vp;


	/*
	*  Scan the command line arguments
	*/
	for ( arg = 1; arg < argc; ++arg ) {

		/*
		*  Look for a switch 
		*/
		sp = argv[arg];
		if ( *sp == '-' ) {
			++sp;
		}
		*sp = tolower( *sp );

		/*
		*  Find the switch's argument.  It is either immediately after the
		*  switch or in the next argv
		*/
		vp = sp + 1;
		if ( *vp == 0 && (arg<(argc-1)) && (*argv[arg+1]!='-') ) {
			if ( ++arg > argc ) {;
				Usage(argv[0]);
				exit( 1 );
			}
			vp = argv[arg];
		}

		/*
		*  Parse the switch
		*/
		switch ( *sp ) {	  

	  case 's':
		  szDBServer = vp;
		  break;

	  case 'd':
		  szDB = vp;
		  break;

	  case 'p':
		  shPort = CheckSwitch( atoi( vp ), 1, MAX_PORT, "port to listen on" );
		  break;	  

	  case 'c':
		  if (_stricmp(vp, "SNAC") == 0)
		  {
			  eClientType = eSNAC;
		  }
		  break;

	  case 'v':
		  bVerbose = true;
		  break;

      case 'm':
          szMEEToUse = vp;
          break;

	  default:
		  Usage(argv[0]);
		  exit( 1 );
		}
	}
}

/*
*	Keyboard-reading thread.
*/
void RunKeyboardThread(void *ptr)
{	
	char		c;
	HANDLE		hStdIn;
	DWORD		dwCharsRead;
	int			ret;
	DWORD		Mode = 0;
	CDateTime	TimeNow;

	//cout<<"Keyboard thread started"<<endl;

	try
	{
	hStdIn = GetStdHandle(STD_INPUT_HANDLE);	//get stdin

	Mode = ENABLE_PROCESSED_INPUT;
	SetConsoleMode(hStdIn, Mode);

	while( TRUE )	//get only keyboard events
	{ 
		ret = ReadConsole(hStdIn, &c, 1, &dwCharsRead, NULL);
		if (ret == 0)
			cout<<"Error: "<<GetLastError()<<endl;
		
		if (c=='q')
		{
			//TimeNow.SetToCurrent();
			TimeNow.Set();

			cout<<TimeNow.ToStr(iDateTimeOutputStyle)<<" quitting\n";			
			SetEvent(hListenStopEvent);
			break;
		}
	}
	}
	catch (...)
	{
		cout<<"Unhandled exception in RunKeyboardThread."<<endl;
	}
}

int main(int argc, char* argv[])
{
	WSADATA	wsock_data;	

	PrintEGenVersion();

	ParseCommandLine(argc, argv);

	cout<<"Attempting to start server with the following parameters:"<<endl;	
	cout<<"DB Server:         "<<szDBServer<<endl;
	cout<<"DB:                "<<szDB<<endl;
	cout<<"Port to listen on: "<<shPort<<endl;
	cout<<"Client driver:     "<<szClientDriverTypeStr[eClientType]<<endl;
	cout<<"MEE to use:        "<<(szMEEToUse == NULL ? "[default]" : szMEEToUse)<<endl;
	cout<<"Verbose output:    "<<(bVerbose ? "yes" : "no")<<endl<<endl;
	
	try
	{		
		if ( WSAStartup(2, &wsock_data) != 0 )	//ask for v2 of Windows Sockets
			throw new CSystemErr(CSystemErr::eNone, "TRMain::main");

		if ( (hListenStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
			throw new CSystemErr(CSystemErr::eCreateEvent, "TRMain::main");

		//Start keyboard thread
		if ( _beginthread(RunKeyboardThread, 0, NULL) == -1L)
			throw new CSystemErr(CSystemErr::ebeginthread, "TRMain::main");

		CMEEServer* serv = new CMEEServer(szDBServer, szDB, shPort, bVerbose, hListenStopEvent, eClientType, szMEEToUse);
		cout<<"Server started (press 'q' to shut down).\n";

		serv->ListenAndDispatchThread(NULL);
	}
	catch (CBaseErr *pErr)
	{
		cout<<"exception occured"<<endl;
		cout<<"Error: "<<pErr->ErrorNum()<<", "<<pErr->ErrorText()<<" in "<<pErr->ErrorLoc()<<endl;
	}
	catch (std::bad_alloc e)
	{
		cout<<"new() failed. "<<e.what()<<endl;
	}
	catch (...)
	{
		cout<<"Unhandled exception."<<endl;
	}

	cout<<"Server exited.\n";

	return 0;
}

