// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// $Header$
// GT0149 Applications Protocol Integration Test Harness
// blank application
// created by: mark j davey
// mjd systems solutions ltd
// mark@mjdss.com
// This is the 'main' code entry point for the Test Harness Application.
// As other projects adopt policy, then separate DLL's will be created for
// each group which can be specified (or colocated) for inclusion.
// This way the harness is sanitized from the project knowledge domain
// 
//

#include <e32base.h>
#include <e32cons.h>
#include <uri8.h>
#include <bacline.h>

//----------------------------------------------------------------------------
//  application specific includes

#include "GT0149.h"
#include "ECommandIDs.h"
#include "ErrorCodes.h"
#include "TEngine.h"
#include "CCmdFamily.h"
#include "CCmdBase.h"
#include "CCmdStandard.h"
#include "CCmdMisc.h"
#include "CCmdLog.h"
#include "CLogFile.h"
#include "HttpSessionCmds.h"
#include "HttpTransactionCmds.h"

//----------------------------------------------------------------------------

#if defined (HTTP_INTEGRATION)

// for StartC32()
#if !defined __C32COMM_H__
	#include <c32comm.h>
#endif

#if !defined __IN_SOCK_H__
	#include <in_sock.h>
#endif

#if defined (__WINS__)
	#define PDD_NAME		_L("ECDRV")
#else
	#define PDD_NAME		_L("EUART1")
	#define PDD2_NAME		_L("EUART2")
	#define PDD3_NAME		_L("EUART3")
	#define PDD4_NAME		_L("EUART4")
#endif

#define LDD_NAME		_L("ECOMM")

//----------------------------------------------------------------------------
//	Integration Domain specific includes

#include "CHTTPFamily.h"

#endif

//----------------------------------------------------------------------------
//  create this (Console) ONLY if we're NOT being driven from the command line

LOCAL_D CConsoleBase *Console;

//----------------------------------------------------------------------------
//	Global Defines for 

GLDEF_D TBool exitConsoleAtExit = ETrue;
GLDEF_D TBool consoleRequired = EFalse;
GLDEF_D TBool debugRequired = EFalse;
GLDEF_D TInt sysError = KErrNone;
TPtrC ScriptFilename;
TBuf<256> Arguments;
TInt nArgs;

//----------------------------------------------------------------------------
//  method defs

LOCAL_C TInt ExecuteManagerL(void);
LOCAL_C TInt CreateFrameworkCommandsL(CCmdFamily *);
LOCAL_C void TestHarnessMainL(void);
LOCAL_C void pressAnyKey(void);
LOCAL_C void reportError(void);
LOCAL_C void processCommandLine(void);

//----------------------------------------------------------------------------

#if defined (HTTP_INTEGRATION)

//	specialist commands here...
//	ideally this is a method from a dynamically loaded DLL...

LOCAL_C void InitCommsL();
LOCAL_C TInt CreateHTTPIntegrationCommands(CCmdFamily *);


#endif

//----------------------------------------------------------------------------
//	Register the fundamental 'framework' commands

LOCAL_C TInt CreateFrameworkCommandsL(CCmdFamily *aList)
{
aList->RegisterL(CCmdRemark::NewL(THA_KCmdRemark, THA_TxtCmdRemark)); 
aList->RegisterL(CCmdRemark::NewL(THA_KCmdComment, THA_TxtCmdComment)); 

aList->RegisterL(CCmdExit::NewL(THA_KCmdExit, THA_TxtCmdExit )); 
aList->RegisterL(CCmdExit::NewL(THA_KCmdExit, THA_TxtCmdQuit )); 
aList->RegisterL(CCmdExit::NewL(THA_KCmdExit, THA_TxtCmdStop )); 

aList->RegisterL(CCmdEchoMode::NewL( THA_KCmdEchoMode, THA_TxtCmdEchoMode));

aList->RegisterL(CCmdPause::NewL(THA_KCmdPause, THA_TxtCmdPause));

aList->RegisterL(CCmdHold::NewL(THA_KCmdHold, THA_TxtCmdHold));
aList->RegisterL(CCmdLogPath::NewL(THA_KCmdLogPath, THA_TxtCmdLogPath));
aList->RegisterL(CCmdLogFile::NewL(THA_KCmdLogFile, THA_TxtCmdLogFile));
aList->RegisterL(CCmdEndLog::NewL(THA_KCmdEndLog, THA_TxtCmdEndLog));

aList->RegisterL(CCmdSetPrompt::NewL(THA_KCmdSetPrompt, THA_TxtCmdSetPrompt));
aList->RegisterL(CCmdSetPath::NewL(THA_KCmdSetPath, THA_TxtCmdSetPath));

aList->RegisterL(CCmdCall::NewL(THA_KCmdCall, THA_TxtCmdCall, THA_TxtCmdCallHelp));

aList->RegisterL(CCmdReturn::NewL(THA_KCmdReturn, THA_TxtCmdReturn));
aList->RegisterL(CCmdCheckMode::NewL(THA_KCmdCheckMode, THA_TxtCmdCheckMode));
aList->RegisterL(CCmdPrint::NewL(THA_KCmdPrint, THA_TxtCmdPrint, THA_TxtCmdPrintHelp));

aList->RegisterL(CCmdDefine::NewL(THA_KCmdDefine, THA_TxtCmdDefine, THA_TxtCmdDefineHelp));
aList->RegisterL(CCmdListAll::NewL(THA_KCmdListAll, THA_TxtCmdListAll, THA_TxtCmdListAllHelp)); 

//	new command: IF, ELSE, ENDIF
aList->RegisterL(CCmdIf::NewL(THA_KCmdIf, THA_TxtCmdIf, THA_TxtCmdIfHelp)); 
aList->RegisterL(CCmdElse::NewL(THA_KCmdElse, THA_TxtCmdElse, THA_TxtCmdElseHelp)); 
aList->RegisterL(CCmdEndIf::NewL(THA_KCmdEndIf, THA_TxtCmdEndIf, THA_TxtCmdEndIfHelp)); 

// Register CASE and SELECT COMMANDS (TVi)
aList->RegisterL(CCmdCase::NewL(ECase, KTxtCase));
aList->RegisterL(CCmdEndCase::NewL(EEndCase, KTxtEndCase));
aList->RegisterL(CCmdSelect::NewL(ECmdSelect, KTxtCmdSelect));

return KErrNone;
}

//----------------------------------------------------------------------------

#if defined (HTTP_INTEGRATION)

//----------------------------------------------------------------------------
//	provide any framework infrastructure configuration

LOCAL_C void InitCommsL()
{
TInt ret = User::LoadPhysicalDevice(PDD_NAME);
User::LeaveIfError(ret == KErrAlreadyExists ? KErrNone : ret);

#ifndef __WINS__
ret = User::LoadPhysicalDevice(PDD2_NAME);
ret = User::LoadPhysicalDevice(PDD3_NAME);
ret = User::LoadPhysicalDevice(PDD4_NAME);
#endif

ret = User::LoadLogicalDevice(LDD_NAME);
User::LeaveIfError(ret == KErrAlreadyExists?KErrNone:ret);
ret = StartC32();
User::LeaveIfError(ret == KErrAlreadyExists?KErrNone:ret);
}

//----------------------------------------------------------------------------
//	Register the fundamental 'framework' commands

LOCAL_C TInt CreateHTTPIntegrationCommands(CCmdFamily *aList)
{
aList->RegisterL(CCmdConnect::NewL(THA_KHTTP_Connect, THA_TxtCmdConnect, THA_TxtCmdConnectHelp)); 
aList->RegisterL(CCmdDisconnect::NewL(THA_KHTTP_Disconnect, THA_TxtCmdDisconnect, THA_TxtCmdDisconnectHelp)); 
aList->RegisterL(CCmdTransaction::NewL(THA_KHTTP_Transaction, THA_TxtCmdTransaction, THA_TxtCmdTransactionHelp)); 
aList->RegisterL(CCmdEndTransaction::NewL(THA_KHTTP_EndTransaction, THA_TxtCmdEndTrans, THA_TxtCmdEndTransHelp)); 
aList->RegisterL(CCmdShowTransaction::NewL(THA_KHTTP_ShowTransaction, THA_TxtCmdShowTrans, THA_TxtCmdShowTransHelp)); 

return KErrNone;
}

#endif

//----------------------------------------------------------------------------
//	This is where it's at
//	
//	Create the scheduler, the Command Tree, Look for PlugIn Language DLL's etc
//	Offer Console *or* script processing

LOCAL_C TInt ExecuteManagerL(void)
{
TInt StackObjects = 0;

//	Create scheduler etc
CActiveScheduler *Scheduler = new (ELeave) CActiveScheduler;
CleanupStack::PushL(Scheduler);
++StackObjects;

//	no problems, so install it
CActiveScheduler::Install(Scheduler);

if (Console)
	Console->Printf(KTHAWelcomeMessage);

//	create the Test Engine and get it cracking...
CTEngine *Engine = CTEngine::NewLC(Console);
++StackObjects;

//	create command list and register

CCmdFamily *Commands = CCmdFamily::NewLC();
++StackObjects;

if (Engine)
	{

	//	we have a basic 'set' of framework commands that are applicable whatever the project
	//	area. as a result these are 'static'
	CreateFrameworkCommandsL(Commands);

	//	now determine if there are any app specific commands to add to 'Commands'
	//	since this is the 'dynamic' part of the system. All the project commands are
	//	to be supplied in a separate '.dll' which we load and append the commands.
	//	e.g.	we have a set of WAP framework commands
	//	CreateWAPFrameworkCommandsL(Commands);

#if defined (HTTP_INTEGRATION)

	InitCommsL();

	//	ideally do search and load of "dll's"
	CreateHTTPIntegrationCommands(Commands);

#endif

	//	now register the command list to the Test Harness Engine
	Engine->SetCmdFamily(Commands);

	//	Set our own prompt for the console
	if (Console)
		(void) Engine->SetPrompt(THA_CommandPrompt);

	if (nArgs > 1)
		sysError = Engine->Run(ScriptFilename, Arguments);
	else
		{
		sysError = KErrNone;
		Engine->Run();
		}
	}
else
	sysError = KErrUnabletoCreateTestEngine;

//	and start it!
if (sysError != KErrNone)
	//	reset the scheduler to run 'as interactive'
	Engine->Run();

//	kick off the scheduler...
CActiveScheduler::Start();

//  finish Console

	CleanupStack::PopAndDestroy(StackObjects); 

//	unnecessary (since global!)
return sysError;
}
 
//----------------------------------------------------------------------------
//  must have some command lines. 
//  <scriptname[.ths]> must be first parameter
//  -c = Console required once script executed
//  -d = debug mode on (log to Console as well)
//  read the command line
//  If we've got a script provided, then do not create a Console object
//  unless we have a -d (for debug) mode command

LOCAL_C void processCommandLine(void)
{
TInt iIgnore;
CCommandLineArguments *cmdArgs = CCommandLineArguments::NewLC();

nArgs = cmdArgs->Count();
iIgnore = nArgs;
if (nArgs == 1)  //  arg(0) is '.exe' name (arg==1)
	// no args (apart from Exename) means assume Interactive (Console) session required
  consoleRequired = ETrue;

else
	{
	//  get the Command File name - why?
	TPtrC ExeFilename;
	ExeFilename.Set(cmdArgs->Arg(0));

	//  construct call arguments
	for (TInt i = 1; i < nArgs; ++i)
		{
		//  look for command/control flags
		TInt Pos = cmdArgs->Arg(i).Find(KControlFlagSeparator);
		if (Pos != KErrNotFound)
			{
			//	valid argument (i.e. has a - in front) but is it supported?
			//	require a Console? (Console created and displayed once script 
			if (cmdArgs->Arg(i).Find(KControlFlagRequiredScript) != KErrNotFound)
				{
				//	remove the -s from the filename and do not add this to the 
				//	argument list				
				//ScriptFilename.Set(cmdArgs->Arg(i).Mid(2));
				ScriptFilename.Set(cmdArgs->Arg(i).Mid(KControlFlagRequiredScript().Length()));
				sysError = KSysCmdParameter;
				}

			//	require a Console? (Console created and displayed once script 
			else if (cmdArgs->Arg(i).Find(KControlFlagRequireConsole) != KErrNotFound)
				{
				consoleRequired = ETrue;
				sysError = KSysCmdParameter;
				--iIgnore;
				}

			else if (cmdArgs->Arg(i).Find(KControlFlagDebugViaConsole) != KErrNotFound)
				{
				debugRequired = ETrue;
				consoleRequired = ETrue;
				sysError = KSysCmdParameter;
				--iIgnore;
				}

			else
				sysError = KErrCommandFlagNotDefined;
			}

		//	get the args - use spaces to separate and 'fill out'
		Arguments.Append(_L(" "));          //  put a space in between them!
		if (sysError == KAppendParameter)
			Arguments.Append(cmdArgs->Arg(i));  //  copy in the argument

		}
	}

//	update the num args to those we're really interested in
nArgs = iIgnore;

//	clear the error
sysError = KErrNone;

//	no longer need them (args) so delete them!
CleanupStack::PopAndDestroy();
}

//----------------------------------------------------------------------------
//  Application Start Point
//  Integration Test Harness
//
//  The application can be passed a parameter <scriptname> which is autoexecuted

LOCAL_C void TestHarnessMainL(void)
{
TInt StackObjects = 0;

//	see what's cooking on the command line...
processCommandLine();

//	create the Console if required and title it
Console = Console::NewL(_L("GT0149 Integration Test Harness"), TSize(KConsFullScreen, KConsFullScreen));
CleanupStack::PushL(Console);
++StackObjects;

//	execute the bit we want

if (sysError == KErrNone)
	TRAP(sysError, ExecuteManagerL());

//	report any errors
if (sysError != KErrNone)
	{
	reportError();
	if (nArgs != 1)  //  arg(0) is '.exe' name (arg==1)
		pressAnyKey();
	}

//  inform user we're closing...
if (Console)
	{
	Console->Printf(_L("\r\n[press any key]"));
		
	//  get the keypress
	Console->Getch();
	}

//  finish Console
if (StackObjects > 0)
	CleanupStack::PopAndDestroy(StackObjects); //  2=Console & cmdArgs
}

//----------------------------------------------------------------------------
//	simple log error message

LOCAL_C void reportError()
{
if (Console)
  {
	Console->Printf(_L("\r\nThe following error code was returned: %d"), sysError);
	Console->Printf(_L("\r\nPlease report this to the appropriate project team"));
	}
}

//----------------------------------------------------------------------------

LOCAL_C void pressAnyKey()
{
if (Console)
	{
	Console->Printf(_L("\r\n[Press any key]"));
	Console->Getch();
	Console->Printf(_L("\n"));
	}
}

//----------------------------------------------------------------------------

GLDEF_C TInt E32Main()
// Main program - run the Test Harness within a TRAP harness, reporting any errors that
// occur via the panic mechanism. Test for memory leaks using heap marking.
{
__UHEAP_MARK;
CTrapCleanup* tc = CTrapCleanup::New();

TRAPD(err, TestHarnessMainL());
if (err!=KErrNone)
	User::Panic(_L("\r\nIntegration Test Harness failed with error code: %i"), err);

  delete tc;

__UHEAP_MARKEND;
return KErrNone;
}

//----------------------------------------------------------------------------


