Subversion Repositories DevTools

Rev

Rev 2269 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

#pragma warn -com
#include <LoggingMacros.h>
#pragma warn +com

#include <vcl.h>
#pragma hdrstop

#include "time.h"
#include "pcreposix.h"

#include "About.h"
#include "DataModule.h"
#include "DefinedVariable.h"
#include "DefinedVariableTable.h"
#include "EvaluationContext.h"
#include "FieldExpression.h"
#include "FileCtrl.hpp"
#include "GenerationProperties.h"
#include "ICryptographicServerProxy.h"
#include "IHash.h"
#include "InitProgress.h"
#include "IMessageDigest.h"
#include "ISecurityWrapperFactory.h"
#include "Iteration.h"
#include "IXmlSchemaWrapperElement.h"
#include "Login.h"
#include "Main.h"
#include "ParameterScope.h"
#include "Registry.hpp"
#include "ScenarioParameters.h"
#include "Sequence.h"
#include "SequenceCollection.h"
#include "TestScenario.h"
#include "TestScenarioProperties.h"
#include "TestScenarioTemplate.h"
#include "TimeEstimate.h"
#include "TransactionFieldTemplate.h"
#include "TransactionConfig.h"
#include "TransactionSpecification.h"
#include "TransactionSpecificationValue.h"
#include "TransactionSpecificationValueKey.h"
#include "TransactionStream.h"
#include "TransactionTemplateCollection.h"
#include "Utilities.h"
#include <algorithm>
#include <ctype.h>

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "Grids_ts"
#pragma link "TSDBGrid"
#pragma link "TSGrid"
#pragma link "TXMLSchema"
#pragma link "AdvGrid"
#pragma link "BaseGrid"
#pragma link "DBAdvGrd"
#pragma link "DBAdvNavigator"
#pragma link "AdvPageControl"
#pragma link "AsgFindDialog"
#pragma link "DBAdvGrd"
#pragma link "DBAdvGrid"
#pragma resource "*.dfm"
TMainForm *MainForm;

#define TDBADVGRID_FIXED   0
#define INCLUDE_PARENTS    TDBADVGRID_FIXED

const char *TMainForm::g_headerStructure  = "SysHdr_t";
const int   TMainForm::g_messagePanel     = 0;


/**
 * Process paint message.
 */
void ProcessPaintMessages( HWND Handle )
{
   MSG msg;
   while ( PeekMessage( &msg, Handle, WM_PAINT, WM_PAINT, PM_REMOVE ) )
   {
      DispatchMessage( &msg );
   }
}
//---------------------------------------------------------------------------

const bool __fastcall TMainForm::openSecurityFactory( const char * library )
{



    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    memset (&pi, 0, sizeof(pi));
    memset (&si, 0, sizeof(si));

    si.cb = sizeof(si);
    si.dwFlags |=STARTF_USESHOWWINDOW;
    si.wShowWindow|=SW_SHOWNORMAL;

    if ( ! CreateProcess(
            "C:\\WINDOWS\\system32\\cmd.exe ",
            "/c C:..\\..\\ERGsec\\scripts\\exprc_cryptoserver.bat" ,
            NULL,
            NULL,
            true,
            NORMAL_PRIORITY_CLASS,
            NULL,
            NULL,
            &si,
            &pi))
    {
            MessageBox(0, "Could not launch crypto server. \n The UD will not have a proper MAC.", "Error", MB_ICONSTOP);
    }
#if 0
    else
    {
            AnsiString  message;
            message.sprintf("process id is %d ",  pi.dwProcessId);
            MessageDlg(message, mtError, TMsgDlgButtons() << mbOK, 0) ;
    }
#endif


   m_securityWrapper = ::LoadLibrary( library );
   if ( m_securityWrapper )
   {
      m_getSecurityWrapperFactory
         = reinterpret_cast< getSecurityWrapperFactory_t >(
            ::GetProcAddress(
               m_securityWrapper,
               "getSecurityWrapperFactory" ) );

      if ( m_getSecurityWrapperFactory )
      {
         m_securityWrapperFactory = &m_getSecurityWrapperFactory();
         if ( m_securityWrapperFactory )
         {
            return ( m_securityWrapperFactory->start() );
         }
      }
   }

   return ( false );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::closeSecurityFactory()
{
   if ( m_securityWrapperFactory )
   {
      m_securityWrapperFactory->stop();
      m_securityWrapperFactory = 0;
   }
   m_getSecurityWrapperFactory = 0;
   if ( m_securityWrapper )
   {
      ::FreeLibrary( m_securityWrapper );
      m_securityWrapper = 0;
   }
}
//---------------------------------------------------------------------------

__fastcall TMainForm::TMainForm(TComponent* Owner)
:  TForm(Owner),
   m_progressBar( 0 ),
   m_securityWrapper( 0 ),
   m_getSecurityWrapperFactory( 0 ),
   m_securityWrapperFactory( 0 ),
    //m_transferManager( 0 ),
    m_Registry( 0 ),
    m_currentiteration (25),
    m_currentproject("SLS")
{
   //TestCasesTabSheet->TabVisible = false;
   //TestScenariosTabSheet->TabVisible = false;

   m_Registry = new TRegistry;
   m_Registry->RootKey = HKEY_CURRENT_USER;
   if (! m_Registry->OpenKey("\\Software\\ERG\\TxnTestManager", true) )
   {
      m_Registry->CloseKey();
      delete m_Registry;
      m_Registry = NULL;
   }
        else
        {
        // read in project from the registry
         if (m_Registry->ValueExists("MRUProjectCode"))
        {
         m_currentproject = m_Registry->ReadString("MRUProjectCode");
        }
        // read in iteration from the registry
        if (m_Registry->ValueExists("MRUProjectIteration"))
      {
         m_currentiteration = m_Registry->ReadInteger("MRUProjectIteration");
      }  
        }
   m_progressBar = new ProgressBar( MainStatusBar );
   
   /* eventually get this from the registry */
   m_engineering_mode = true;
   
   openSecurityFactory();
}
//---------------------------------------------------------------------------

__fastcall TMainForm::~TMainForm()
{
   closeSecurityFactory();

   delete m_progressBar;
   m_progressBar = 0;

    //delete m_transferManager;
    //m_transferManager = 0;

    delete m_Registry;
    m_Registry = 0;

}
//---------------------------------------------------------------------------



void __fastcall TMainForm::FormShow(TObject *Sender)
{
#ifdef LOGGING_ACTIVE
    ProgrammerLogging::start("TxnTestManager.ini");
#endif

    bool retryLogin;
    do
    {
        retryLogin = false;

        if (LoginForm->ShowModal() == mrOk)
        {
            try
            {
                // Initialise Startup TabSheets
                TestsPageControl->ActivePage = TestCaseTabSheet;
                TestParametersPageControl->ActivePage = IterationParametersTabSheet;

                // Initialise the Database connection
                Data_Module->IntegrationDBConnection->Connected = false;

                AnsiString connectionString;
                connectionString.sprintf( "Provider=OraOLEDB.Oracle.1;Data Source=%s", LoginForm->DatabaseEdit->Text );
                Data_Module->IntegrationDBConnection->ConnectionString = connectionString;
                Data_Module->IntegrationDBConnection->Open(LoginForm->UsernameEdit->Text, LoginForm->PasswordEdit->Text);
                if (!Data_Module->IntegrationDBConnection->Connected)                           
                {
                    MessageDlg("Failed to connect to datasource with specified username and password.",
                                mtError, TMsgDlgButtons() << mbOK, 0);
                    retryLogin = true;
                }
                else
                {
                     // we have a databse connection so use it
                     // but first display the database name on the bottom ight hand corner
                     MainStatusBar->Panels->Items[ 2 ]->Alignment = taRightJustify ;
                     MainStatusBar->Panels->Items[ 2 ]->Text =  LoginForm->DatabaseEdit->Text + "      ";

                    MASSTxnsQuery->Active = false;
                    TestCaseQuery->Active = false;
                    TxnSpecQuery->Active = false;
                    TxnValuesQuery->Active = false;
                    TxnHdrValuesQuery->Active = false;
                    IterationParamsQuery->Active = false;
                    SequenceGeneratorQuery->Active = false;
                    // TxnStepsQuery->Active = true;  ?? can't do yet as we don't have a default scenario

                    srand( static_cast< unsigned >( time( 0 ) ) );
                    int    first_rand_seed = rand();

                    srand( first_rand_seed << (first_rand_seed & 0x00FF) );
                    //              int    first_rand = rand();

                    // Locate the XML SWIS Schema
                    XMLSchema->Active = true;
                    vector<string>  schemas;
                    if (XMLSchema->GetSchemas(schemas))
                    {
                        vector<string>::iterator   itr = schemas.begin();

                        while (itr != schemas.end())
                        {
                            AnsiString    xml_schema = (*itr).c_str();

                            if (xml_schema.Pos(MASSUDWriter) == 1)
                            {
                                m_xml_schemas.push_back(xml_schema.c_str());
                            }

                            ++itr;
                        }
                    }

                    if (m_xml_schemas.size() == 0)
                    {
                        MessageDlg("Failed to locate any MASS UD Writer XMLs\n"
                                   "Check XMLSchema.ini file",
                                   mtError, TMsgDlgButtons() << mbOK, 0);
                    }
                    
                    
                    // use the iteration held in the registry to complete the preparation for the form
                    LoadIteration(Sender);
                    bool allow;
                    TestCaseGridRowChanging(Sender, 0, 1, allow = true );
                    MASSTxnTabSheet->Visible = false;
                    //InitialiseUdTransferManager();
                }

            }
            catch( EOleException & e )
            {
                AnsiString msg = "Failed to connect to datasource with specified username and password.\n"
                    + e.Message + ".";
                MessageDlg(msg, mtError, TMsgDlgButtons() << mbOK, 0);
                retryLogin = true;
            }
            catch(...)
            {
                Close();
            }
        }
        else
        {
            Close();
        }
    } while( retryLogin );
}

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

const bool __fastcall TMainForm::findSchema( std::string &     handle,
                                  const AnsiString &  projectCode,
                                  const int &      iteration )
{
   std::string project;
   std::string majorVersion;

   for ( std::vector< std::string >::const_iterator
         where = m_xml_schemas.begin();
        where != m_xml_schemas.end();
        ++where )
   {
      if ( XMLSchema->GetAttributeProperty( *where, "project", project ) &&
          ( projectCode == AnsiString( project.c_str() ).UpperCase() ) )
      {
         if ( ( XMLSchema->GetAttributeProperty( *where, "majorversion", majorVersion ) ) &&
             ( iteration == atoi( majorVersion.c_str() ) ) )
         {
            handle = *where;
            return ( true );
         }
      }
   }
   handle.erase();

   return ( false );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LoadIteration(TObject *Sender)
{
   AnsiString  sql_statement;
   
   if (!findSchema( m_schema_handle, m_currentproject.UpperCase(), m_currentiteration ))
   {
       AnsiString  message;
       message.sprintf("Failed to match project %s and iteration %d in schema xml file",
                        m_currentproject, m_currentiteration);
       MessageDlg(message, mtError, TMsgDlgButtons() << mbOK, 0);
   }

   buildTransactionTemplates( m_transactionTemplates, m_currentproject, m_currentiteration );
   ApplyTemplates->Enabled = ( m_transactionTemplates.getTemplateCount() > 0 );

   // Load the Project/Iterations MASS Txns
   MASSTxnsQuery->Close();
   sql_statement="";
   sql_statement.sprintf("SELECT * FROM MASS_TXNS WHERE PROJECTCODE='%s' AND ITERATION=%d AND ENABLED = 'Y' ORDER BY NAME,UDTYPE,UDSUBTYPE",
                    m_currentproject.c_str(),
                    m_currentiteration);
   MASSTxnsQuery->SQL->Text = sql_statement;
   MASSTxnsQuery->Open();

   InitialiseMASSTxns();

    // Refresh the TestCases
   if (TestCaseQuery->Active)
   {
      TestCaseQuery->Close();
   }
   TestCaseQuery->Open();

   // Load the Project/Iterations Iteration Parameters
   IterationParamsQuery->Close();
   sql_statement="";
   sql_statement.sprintf("SELECT * FROM ITERATION_PARAMS "
                    "WHERE PROJECT_CODE='%s' AND ITERATION=%d"
                    "AND TESTSCENARIO_NO IS NULL AND SUPPORTED <> 0"
                    "ORDER BY NAME",
                    m_currentproject.c_str(),
                    m_currentiteration);
   IterationParamsQuery->SQL->Text = sql_statement;
   IterationParamsQuery->Open();

   SequenceGeneratorQuery->Close();
   sql_statement="";
   sql_statement.sprintf("SELECT * FROM SEQGEN "
                    "WHERE PROJECT_CODE='%s' AND ITERATION=%d"
                    "ORDER BY SEQNAME",
                    m_currentproject.c_str(),
                    m_currentiteration);
   SequenceGeneratorQuery->SQL->Text = sql_statement;
   SequenceGeneratorQuery->Open();

#if 0  // TxnHdr not supported in TSB
    // Load the Project/Iterations TXNHDR Parameters
    TxnHdrValuesQuery->Close();
    sql_statement="";
    sql_statement.sprintf("SELECT * FROM TXNHDR_VALUES "
                    "WHERE PROJECT_CODE='%s' AND ITERATION=%d",
                    m_currentproject.c_str(),
                    m_currentiteration);
   TxnHdrValuesQuery->SQL->Text = sql_statement;
   TxnHdrValuesQuery->Open();
#endif
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LoadTestCaseNodes(TTreeNode *testcase_node)
{
   bool  initially_expanded = testcase_node->Expanded;

    TestCaseTreeView->Items->BeginUpdate();

   testcase_node->DeleteChildren();

    TADOQuery  *txnquery = new TADOQuery(this);
    txnquery->Connection = Data_Module->IntegrationDBConnection;

    AnsiString sql_statement;
    sql_statement.sprintf("SELECT MASS_TXNS.NAME,TRANSACTION_SPECIFICATION.TXNSPEC_NO "
                          "FROM MASS_TXNS,TRANSACTION_SPECIFICATION "
                          "WHERE TRANSACTION_SPECIFICATION.TESTSCENARIO_NO=%d "
                          "AND   MASS_TXNS.PROJECTCODE=TRANSACTION_SPECIFICATION.PROJECT_CODE "
                          "AND   MASS_TXNS.ITERATION=TRANSACTION_SPECIFICATION.ITERATION "
                          "AND   MASS_TXNS.UDTYPE=TRANSACTION_SPECIFICATION.UDTYPE "
                          "AND   MASS_TXNS.UDSUBTYPE=TRANSACTION_SPECIFICATION.UDSUBTYPE "
                          "ORDER BY TRANSACTION_SPECIFICATION.SEQ_NO",
                          (int)testcase_node->Data);
    txnquery->SQL->Text = sql_statement;
    txnquery->Open();
    while (!txnquery->Eof)
    {
        AnsiString  txnname   = txnquery->FieldByName("NAME")->AsString;
        int       txnspec_no  = txnquery->FieldByName("TXNSPEC_NO")->AsInteger;

        TestCaseTreeView->Items->AddChildObject(testcase_node, txnname.c_str(), (TObject *)txnspec_no);

        txnquery->Next();
    }

    delete txnquery;

    if (initially_expanded)
    {
      testcase_node->Expand(true);
    }
   /*
    else
    {
       testcase_node->Collapse(true);
    }
         */
    TestCaseTreeView->Items->EndUpdate();
}
//---------------------------------------------------------------------------



void __fastcall TMainForm::EditTestCaseExecute(TObject *Sender)
{
   //
   

}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewEnter(TObject *Sender)
{
//   if (!TestScenariosTabSheet->TabVisible)
//    {
//        TestScenariosTabSheet->TabVisible = true;
//        TestCasesTabSheet->TabVisible = false;
//    }


   // MainPageControl->ActivePage = ScenarioStepsTabSheet;
      
   
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseQueryAfterPost(TDataSet *DataSet)
{
    if (TestCaseQuery->Active)
    {
      TestCaseQuery->Close();
    }
    
    TestCaseQuery->Open();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TxnStepsQueryAfterPost(TDataSet *DataSet)
{
 
 /* This routine was added to copy the exisiting TestCaseQuery behaviour but I am not sure if it is needed. */
 //  if (TxnStepsQuery->Active)
 //   {
 //     TxnStepsQuery->Close();
 //   }
    
 //   TxnStepsQuery->Open();


 //        MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "posting txn steps";
 //                 Application->ProcessMessages();

}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TxnStepsNewRow(TDataSet *DataSet)
{
 /*   AnsiString message;
    message = "Record " + IntToStr(TxnStepsQuery->RecNo) + " of " + IntToStr(TxnStepsQuery->RecordCount);

          MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                  Application->ProcessMessages();
  */    
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::StepsGridNewRow (TObject *Sender, int ARow)
{
/*    AnsiString message;
    message = "new grid row at  " + IntToStr(ARow);

         MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                  Application->ProcessMessages();
*/

}
//---------------------------------------------------------------------------

void __fastcall TMainForm::StepsGridRowChanging(TObject *Sender,
      int OldRow, int NewRow, bool &Allow)
{
 /*   AnsiString message;
    message = "chnaged grid row at  " + IntToStr(NewRow);

         MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                  Application->ProcessMessages();
 //Application->MessageBox(message.c_str(),"hello box",NULL);
 */
 
   // TestCaseGridRowChanging(Sender, 0, 1, Allow);
 
}
//---------------------------------------------------------------------------


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

void __fastcall TMainForm::loadLegacyParameters( TransactionTemplateCollection & templates, const AnsiString & project, const int & iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "NAME,"
            "FIELDVALUE,"
            "TESTSCENARIO_NO "
         "FROM "
            "ITERATION_PARAMS "
         "WHERE "
            "PROJECT_CODE=\'%s\' AND "
            "ITERATION=%d ",
         project.c_str(),
         iteration );
      query->SQL->Text = sqlStatement;
      query->Open();

      AnsiString  fieldName;
      int         scenario = 0;
      AnsiString xpath;
      AnsiString value;
      while ( !query->Eof )
      {
         fieldName = query->FieldByName( "NAME" )->AsString;
         scenario = query->FieldByName( "TESTSCENARIO_NO" )->AsInteger;

         value = query->FieldByName( "FIELDVALUE" )->AsString;
         if ( !value.IsEmpty() )
         {
            if ( value[ 1 ] == '=' )
            {
               value.Delete( 1, 1 );
            }

            if ( !value.IsEmpty() )
            {
               switch ( value[ 1 ] )
               {
                  case '@':
                     value[ 1 ] = '=';
                     if ( FieldExpression::isFunctor(
                           value.c_str() + 1 ) )
                     {
                        value += "()";
                     }
                     break;
                  default:
                     break;
               }
            }
         }

         if ( !fieldName.IsEmpty() )
         {
            switch ( fieldName[ 1 ] )
            {
            case '$':
               xpath.sprintf(
                  ".*/%s",
                  fieldName.c_str() + 1 );

               templates.getTestScenario( scenario ).getField( xpath.c_str() ).
                  setValue( value.c_str() );
               break;
            case '@':   // We don't worry about variables here.
               break;
            default:
               break;
            }
         }
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionTemplates( TransactionTemplateCollection & templates, const AnsiString & project, const int & iteration )
{
   templates.clear();
   //loadLegacyHeaderValues( templates, project, iteration );
   loadLegacyParameters( templates, project, iteration );

   // Now apply our current templates, which override the legacy templates.
   /* KI note: it seems that the 'legacy' routines are in fact the real thing
      and the comment above is no longer appropriate.  Only guessing though at this stage.
      If it turns out to be the case then I'll rename the legacy routines accordingly 
   */
}

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

void __fastcall TMainForm::UseCaseDBGridEnter(TObject *Sender)
{
//   TestCasesTabSheet->TabVisible = true;
//   ScenarioStepsTabSheet->TabVisible = true;
   MainPageControl->ActivePage = ScenarioStepsTabSheet;
//   TestScenariosTabSheet->TabVisible = false;
//     TestScenariosTabSheet->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::IterationParamsQueryAfterInsert(
      TDataSet *DataSet)
{
   DataSet->FieldByName("PROJECT_CODE")->AsString  = m_currentproject;
   DataSet->FieldByName("ITERATION")->AsInteger    = m_currentiteration;
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::readTransactionSpecifications(
               TransactionSpecification & transaction,
               const int &             transactionSpecification )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "XPATH,"
            "FIELDVALUE,"
            "OBSOLETE "
         "FROM "
            "TXNSPEC_VALUES "
         "WHERE "
            "TXNSPEC_NO=%d",
         transactionSpecification );
      query->SQL->Text = sqlStatement;
      query->Open();

      while ( !query->Eof )
      {
         transaction.addValue(
            query->FieldByName( "XPATH" )->AsString.c_str(),
            query->FieldByName( "FIELDVALUE" )->AsString.c_str(),
            query->FieldByName( "OBSOLETE" )->AsBoolean );
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}

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

void __fastcall TMainForm::buildTransactionsForIteration(
               TransactionCache &   transactionCache,
               ProgressBar &     progressBar,
               const std::string &  schema,
               const std::string &  project,       
               const int &       iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "TXNSPEC_NO,"
            "NAME,"
            "TESTSCENARIO_NO "
         "FROM "
            "TRANSACTION_SPECIFICATION,"
            "MASS_TXNS "
         "WHERE "
            "TRANSACTION_SPECIFICATION.PROJECT_CODE=\'%s\' AND "
            "TRANSACTION_SPECIFICATION.ITERATION=%d AND "
            "TRANSACTION_SPECIFICATION.PROJECT_CODE = MASS_TXNS.PROJECTCODE AND "
            "TRANSACTION_SPECIFICATION.ITERATION = MASS_TXNS.ITERATION AND "
            "TRANSACTION_SPECIFICATION.UDTYPE = MASS_TXNS.UDTYPE AND "
            "TRANSACTION_SPECIFICATION.UDSUBTYPE = MASS_TXNS.UDSUBTYPE "
         "ORDER BY "
            "TESTSCENARIO_NO,"
            "TXNSPEC_NO",
         project.c_str(),
         iteration );
      query->SQL->Text = sqlStatement;
      query->Open();

      AnsiString xpath;
      AnsiString message;
      while ( !query->Eof )
      {
         if ( !m_transactionCache.isContained( query->FieldByName( "TXNSPEC_NO" )->AsInteger ) )
         {
            message.sprintf(
               " Building %s ...",
               query->FieldByName( "NAME" )->AsString.c_str() );
            MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
            Application->ProcessMessages();

            buildTransactionSpecificationValues(
               transactionCache,
               query->FieldByName( "TESTSCENARIO_NO" )->AsInteger,
               query->FieldByName( "TXNSPEC_NO" )->AsInteger,
               query->FieldByName( "NAME" )->AsString.c_str(),
               g_headerStructure,
               schema,
               iteration );
         }
         else
         {
            message.sprintf(
               " Using cached %s ...",
               query->FieldByName( "NAME" )->AsString.c_str() );
            MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
            Application->ProcessMessages();
         }

         progressBar.increment();
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;

      MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "";
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionsForScenario(
               TransactionCache &   transactionCache,
               ProgressBar &     progressBar,
               const int &       scenario,
               const std::string &  schema,
               const int &       iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "TXNSPEC_NO,"
            "NAME "
         "FROM "
            "TRANSACTION_SPECIFICATION,"
            "MASS_TXNS "
         "WHERE "
            "TRANSACTION_SPECIFICATION.TESTSCENARIO_NO=%d AND "
            "TRANSACTION_SPECIFICATION.PROJECT_CODE = MASS_TXNS.PROJECTCODE AND "
            "TRANSACTION_SPECIFICATION.ITERATION = MASS_TXNS.ITERATION AND "
            "TRANSACTION_SPECIFICATION.UDTYPE = MASS_TXNS.UDTYPE AND "
            "TRANSACTION_SPECIFICATION.UDSUBTYPE = MASS_TXNS.UDSUBTYPE "
         "ORDER BY "
            "TXNSPEC_NO",
         scenario );
      query->SQL->Text = sqlStatement;
      query->Open();

      AnsiString xpath;
      AnsiString message;
      while ( !query->Eof )
      {
         if ( !m_transactionCache.isContained( query->FieldByName( "TXNSPEC_NO" )->AsInteger ) )
         {
            message.sprintf(
               " Building %s ...",
               query->FieldByName( "NAME" )->AsString.c_str() );

            buildTransactionSpecificationValues(
               transactionCache,
               scenario,
               query->FieldByName( "TXNSPEC_NO" )->AsInteger,
               query->FieldByName( "NAME" )->AsString.c_str(),
               g_headerStructure,
               schema,
               iteration );
         }
         else
         {
            message.sprintf(
               " Using cached %s ...",
               query->FieldByName( "NAME" )->AsString.c_str() );
         }

         MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
         Application->ProcessMessages();

         progressBar.increment();
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;

      MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "";
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionSpecificationValues(
               TransactionCache &   transactionCache,
               const int &       testScenario,
               const int &       transactionSpecification,
               const std::string &  transactionStructureName,
               const std::string &  headerStructureName,
               const std::string &  schema,
               const int &       iteration )
{
   /**
    * Ensure that for each transactionSpecification and iteration we do this 
    * only on startup and whenever we import a schema.
    */

   int ordinal = 0;
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      std::string structureHandle;
      std::string headerHandle;
      try
      {
         if ( XMLSchema->Create(
               schema.c_str(),
               transactionStructureName.c_str(),
               iteration,
               structureHandle,
               0 ) )
         {
            if ( XMLSchema->Create(
                  schema.c_str(),
                  headerStructureName.c_str(),
                  iteration,
                  headerHandle,
                  0 ) )
            {
               try
               {
                  // KI note. this txn had to be lost as there was an overlapping txn in progress
                  // Data_Module->IntegrationDBConnection->BeginTrans();

                  TransactionSpecification & transaction = transactionCache.getTransactionSpecification( transactionSpecification );
                  readTransactionSpecifications( transaction, transactionSpecification );

                  buildTransactionSpecificationValues(
                     *query,
                     transactionStructureName,
                     testScenario,
                     transactionSpecification,
                     structureHandle,
                     ordinal = 0,
                     transaction );
                  buildTransactionSpecificationValues(
                     *query,
                     headerStructureName,
                     testScenario,
                     transactionSpecification,
                     headerHandle,
                     ordinal = 0,
                     transaction );


                    // Data_Module->IntegrationDBConnection->CommitTrans(); 
               }
               catch ( const std::exception & exception )
               {
                  std::stringstream stream;
                  stream
                     << "Cannot build transaction specification values for \"" \
                     << transactionStructureName \
                     << "\".  " \
                     << exception.what();
                  MessageDlg(
                     stream.str().c_str(),
                     mtError, TMsgDlgButtons() << mbOK, 0 );

                  transactionCache.deleteTransactionSpecification( transactionSpecification );
                  // Data_Module->IntegrationDBConnection->RollbackTrans();  // see comment above
               }
               catch ( ... )
               {
                  std::stringstream stream;
                  stream
                     << "Cannot build transaction specification values for \"" \
                     << transactionStructureName \
                     << "\".";
                  MessageDlg(
                     stream.str().c_str(),
                     mtError, TMsgDlgButtons() << mbOK, 0 );

                  transactionCache.deleteTransactionSpecification( transactionSpecification );
                  // Data_Module->IntegrationDBConnection->RollbackTrans(); // see comment above
                  throw;
               }
            }
            else
            {
               std::stringstream stream;
               stream
                  << "Cannot create structure \""
                  << headerStructureName
                  << "\" for iteration "
                  << iteration << ".  Is \""
                  << XMLSchema->Profile.c_str() << "\" configured correctly?";
               MessageDlg(
                  stream.str().c_str(),
                  mtError, TMsgDlgButtons() << mbOK, 0 );
            }
         }
         else
         {
            std::stringstream stream;
            stream
               << "Cannot create structure \""
               << transactionStructureName
               << "\" for iteration "
               << iteration << ".  Is \""
               << XMLSchema->Profile.c_str() << "\" configured correctly?";
            MessageDlg(
               stream.str().c_str(),
               mtError, TMsgDlgButtons() << mbOK, 0 );
         }
      }
      __finally
      {
         XMLSchema->Destroy( headerHandle );
         XMLSchema->Destroy( structureHandle );
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionSpecificationFieldValue(
               TADOQuery &             query,
               const std::string &        rootStructure,
               const std::string &        fieldHandle,
               const int &             testScenario,
               const int &             transactionSpecification,
               int &                ordinal,
               const &                 childCount,
               TransactionSpecification & transactions,
               const int &             subscript )
{
   std::string tagValue;

   // If we get a tag, then use it.  Otherwise, tough luck.
   if ( !XMLSchema->GetAttributeProperty( fieldHandle, "tag", tagValue ) ||
       tagValue.length() > 0 )
   {
      std::string fieldName;
      std::string xPath;

      if ( XMLSchema->GetAttributeProperty( fieldHandle, "name", fieldName ) &&
          XMLSchema->GetAttributeProperty( fieldHandle, "xpath", xPath ) )
      {
         /**
          * Build the full xpath as the schema reports only the path
          * relative to the root structure.
          */
         const std::string fullXPath = "/" + rootStructure + xPath;

         AnsiString displayName;
         if ( !subscript )
         {
            displayName = fieldName.c_str();
         }
         else
         {
#if TDBADVGRID_FIXED
            displayName.sprintf( "[%d]", subscript );
#else
            displayName.sprintf( "%s[%d]", fieldName.c_str(), subscript );
#endif
         }

         /**
          * Work out whether we have to insert or update, and whether we
          * have to migrate or not.
          */
         bool insert    = false;
         bool migrate   = false;
         if ( transactions.isContained( fullXPath ) )
         {
            insert = false;
            migrate = false;
         }
         else
         {
            if ( transactions.isContained( xPath ) )
            {
               insert = false;
               migrate = true;
            }
            else
            {
               insert = true;
               migrate = false;
            }
         }

         /**
          * We now assert this value into the database.
          */
         std::stringstream stream;
         if ( !insert )
         {
            if ( !migrate )
            {
               stream << "UPDATE TXNSPEC_VALUES SET "
                     << "CHILD_COUNT=" << childCount << ','
                     << "DISPLAY_FIELDNAME=\'" << Utilities::EscapeString( displayName ).c_str() << "\',"
                     << "FIELDNAME=\'" << Utilities::EscapeString( fieldName ) << "\',"
                     << "FIELDTAG=" << atoi( tagValue.c_str() ) << ','
                     << "ORDINAL=" << ++ordinal << ','
                     << "SUBSCRIPT=" << subscript << ','
                     << "TESTSCENARIO_NO=" << testScenario
                  << " WHERE "
                     << "TXNSPEC_NO=\'" << transactionSpecification << "\' AND "
                     << "XPATH=\'" << fullXPath << '\'';
               transactions.markValue( fullXPath );
            }
            else
            {
               stream << "UPDATE TXNSPEC_VALUES SET "
                     << "CHILD_COUNT=" << childCount << ','
                     << "DISPLAY_FIELDNAME=\'" << Utilities::EscapeString( displayName ).c_str() << "\',"
                     << "FIELDNAME=\'" << Utilities::EscapeString( fieldName ) << "\',"
                     << "FIELDTAG=" << atoi( tagValue.c_str() ) << ','
                     << "ORDINAL=" << ++ordinal << ','
                     << "SUBSCRIPT=" << subscript << ','
                     << "TESTSCENARIO_NO=" << testScenario << ','
                     << "XPATH=\'" << fullXPath << '\''
                  << " WHERE "
                     << "TXNSPEC_NO=\'" << transactionSpecification << "\' AND "
                     << "XPATH=\'" << xPath << '\'';
               transactions.markValue( xPath );
            }
         }
         else
         {
            stream << "INSERT INTO TXNSPEC_VALUES ( "
                  "TXNSPEC_NO,"
                  "XPATH,"
                  "CHILD_COUNT,"
                  "DISPLAY_FIELDNAME,"
                  "FIELDNAME,"
                  "FIELDTAG,"
                  "OBSOLETE,"
                  "ORDINAL,"
                  "SUBSCRIPT,"
                  "TESTSCENARIO_NO,"
                  "USER_SUPPLIED,"
                  "DISPLAYABLE"
               " ) VALUES ( "
                  << transactionSpecification << ",\'"
                  << fullXPath << "\',"
                  << childCount << ",\'"
                  << Utilities::EscapeString( displayName ).c_str() << "\',\'"
                  << Utilities::EscapeString( fieldName ).c_str() << "\',"
                  << atoi( tagValue.c_str() ) << ','
                  << "\'N\'" << ','
                  << ++ordinal << ','
                  << subscript << ','
                  << testScenario << ','
                  << "\'N\'" << ','
            << "\'N\'"
               << " )";
         }

         query.SQL->Text = stream.str().c_str();
         if ( query.ExecSQL() != 1 )
         {
            MTHROW( std::runtime_error, \
               "Cannot update field \"" \
               << fullXPath \
               << "\" of transaction specification " \
               << transactionSpecification \
               << '.' );
         }
      }
      else
      {
         MTHROW( std::runtime_error, \
            "Cannot get name and xpath for schema element \"" \
            << fieldHandle \
            << "\"." );
      }
   }
   else
   {
      MTHROW( std::runtime_error, \
         "Cannot get tag value for schema element \"" \
         << fieldHandle \
         << "\".  The tag is present but has a zero-length value." );
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionSpecificationRepeatValue(
               TADOQuery &             query,
               const std::string &        rootStructure,
               const std::string &        attribute,
               const int &             testScenario,
               const int &             transactionSpecification,
               const std::string &        transactionStructureHandle,
               int &                ordinal,
               TransactionSpecification & transactions,
               const int &             repeatLimit )
{
   std::string refcountField;
   std::string repeatSize;

   /**
    * Find the upper bound of the repeat by looking for the "max" property
    * of the "refcountfield" (possibly an xPath), and then for our
    * "maxOccurs" property.
    */
   XMLSchema->GetAttributeProperty( attribute, "refcountfield", refcountField );
   if ( refcountField.length() )
   {
      XMLSchema->GetAttributeProperty(
         transactionStructureHandle + "." + refcountField,
         "max",
         repeatSize );
   }

   if ( !repeatSize.length() )
   {
      XMLSchema->GetAttributeProperty(
         attribute,
         "maxOccurs",
         repeatSize );
   }

   if ( repeatSize.length() )
   {
      /**
       * Now instantiate the array so that we may traverse it, but limit it to
       * repeatLimit elements.
       */
      const int   size = std::min< int >( atoi( repeatSize.c_str() ), repeatLimit );
      std::string    repeatName;

      if ( ( refcountField.length() == 0 ) ||
          XMLSchema->SetAttributeValue( transactionStructureHandle, refcountField, size ) )
      {
         if ( XMLSchema->GetAttributeProperty( attribute, "name", repeatName ) )
         {
            AnsiString  repeatElement;
            std::string    datatype;
            repeatElement.sprintf( "%s.1.%s",
               attribute.c_str(),
               repeatName.c_str() );
            if ( XMLSchema->GetAttributeProperty(
                  repeatElement.c_str(),
                  "datatype",
                  datatype ) )
            {
               const bool isStruct = ( datatype == "Struct" );
               buildTransactionSpecificationFieldValue(
                  query,
                  rootStructure,
                  attribute,
                  testScenario,
                  transactionSpecification,
                  ordinal,
                  countChildren( attribute, isStruct ),
                  transactions );
               if ( size >= 1 )
               {
                  std::string repeatHandle;
                  for ( int where = 1; where <= size; ++where )
                  {
                     repeatElement.sprintf( "%s.%d.%s",
                        attribute.c_str(),
                        where,
                        repeatName.c_str() );
                     repeatHandle = repeatElement.c_str();
                     if ( isStruct )
                     {
                        buildTransactionSpecificationFieldValue(
                           query,
                           rootStructure,
                           repeatHandle,
                           testScenario,
                           transactionSpecification,
                           ordinal,
                           countChildren( repeatHandle, isStruct ),
                           transactions,
                           where );
                        buildTransactionSpecificationValues(
                           query,
                           rootStructure,
                           testScenario,
                           transactionSpecification,
                           repeatHandle,
                           ordinal,
                           transactions );
                     }
                     else
                     {
                        buildTransactionSpecificationFieldValue(
                           query,
                           rootStructure,
                           repeatHandle,
                           testScenario,
                           transactionSpecification,
                           ordinal,
                           0,
                           transactions,
                           where );
                     }
                  }
               }
            }
            else
            {
               MTHROW( std::runtime_error, \
                  "Cannot get datatype for schema element \"" \
                  << repeatElement.c_str() \
                  << "\"." );
            }
         }
         else
         {
            MTHROW( std::runtime_error, \
               "Cannot get name for schema element \"" \
               << attribute \
               << "\"." );
         }
      }
      else
      {
         MTHROW( std::runtime_error, \
            "Cannot set size for schema element \"" \
            << transactionStructureHandle + "." + refcountField \
            << "\"." );
      }
   }
   else
   {
      MTHROW( std::runtime_error, \
         "Cannot get repeat size for schema element \"" \
         << attribute \
         << "\"." );
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionSpecificationValues(
               TADOQuery &             query,
               const std::string &        rootStructure,
               const int &             testScenario,
               const int &             transactionSpecification,
               const std::string &        transactionStructureHandle,
               int &                ordinal,
               TransactionSpecification & transactions )
{
   std::vector< std::string > attributes;

   if ( XMLSchema->GetAttributes( transactionStructureHandle, attributes ) )
   {
      std::string elementType;

      for ( std::vector< std::string >::iterator
            where = attributes.begin();
           where != attributes.end();
           ++where )
      {
         if ( XMLSchema->GetAttributeProperty( *where, "type", elementType ) )
         {
            std::string elementDatatype;

            if ( elementType == "field" )
            {
               if ( XMLSchema->GetAttributeProperty( *where, "datatype", elementDatatype ) )
               {
                  const isStruct = ( elementDatatype == "Struct" );

                  buildTransactionSpecificationFieldValue(
                     query,
                     rootStructure,
                     *where,
                     testScenario,
                     transactionSpecification,
                     ordinal,
                     ( isStruct ? countChildren( *where, false ) : 0 ),
                     transactions );
                  if ( isStruct )
                  {
                     buildTransactionSpecificationValues(
                        query,
                        rootStructure,
                        testScenario,
                        transactionSpecification,
                        *where,
                        ordinal,
                        transactions );
                  }
               }
               else
               {
                  MTHROW( std::runtime_error, \
                     "Cannot get datatype for schema element \"" \
                     << *where \
                     << "\"." );
               }
            }
            else if ( elementType == "repeat" )
            {
               buildTransactionSpecificationRepeatValue(
                  query,
                  rootStructure,
                  *where,
                  testScenario,
                  transactionSpecification,
                  transactionStructureHandle,
                  ordinal,
                  transactions );
            }
         }
         else
         {
            MTHROW( std::runtime_error, \
               "Cannot get type for schema element \"" \
               << *where \
               << "\"." );
         }
      }
   }
   else
   {
      MTHROW( std::runtime_error, \
         "Cannot get attributes for schema element \"" \
         << transactionStructureHandle \
         << "\"." );
   }
}
//---------------------------------------------------------------------------

const unsigned __fastcall TMainForm::countChildren( const std::string & transactionStructureHandle, const bool & isStructureRepeat )
{
   unsigned             childCount = 0;
   std::vector< std::string > attributes;

   if ( XMLSchema->GetAttributes( transactionStructureHandle, attributes ) )
   {
      std::string elementType;
      std::string elementDatatype;

      for ( std::vector< std::string >::iterator
            where = attributes.begin();
           where != attributes.end();
           ++where )
      {
         if ( XMLSchema->GetAttributeProperty( *where, "type", elementType ) )
         {
//          if ( !isStructureRepeat )
//          {
               ++childCount;
//          }
            if ( elementType == "field" )
            {
               if ( XMLSchema->GetAttributeProperty( *where, "datatype", elementDatatype ) )
               {
                  if ( elementDatatype == "Struct" )
                  {
                     childCount += countChildren( *where, false );
                  }
               }
               else
               {
                  MTHROW( std::runtime_error, \
                     "Cannot get datatype for schema element \"" \
                     << *where \
                     << "\"." );
               }
            }
            else if ( elementType == "repeat" )
            {
               childCount += countChildren( *where, transactionStructureHandle );
            }
         }
         else
         {
            MTHROW( std::runtime_error, \
               "Cannot get type for schema element \"" \
               << *where \
               << "\"." );
         }
      }
   }
   else
   {
      MTHROW( std::runtime_error, \
         "Cannot get attributes for schema element \"" \
         << transactionStructureHandle \
         << "\"." );
   }

   return ( childCount );
}
//---------------------------------------------------------------------------

const unsigned __fastcall TMainForm::countChildren(
               const std::string &  attribute,
               const std::string &     transactionStructureHandle,
               const int &       repeatLimit )
{
   unsigned childCount = 0;
   std::string refcountField;
   std::string repeatSize;

   /**
    * Find the upper bound of the repeat by looking for the "max" property
    * of the "refcountfield" (possibly an xPath), and then for our
    * "maxOccurs" property.
    */
   XMLSchema->GetAttributeProperty( attribute, "refcountfield", refcountField );
   if ( refcountField.length() )
   {
      XMLSchema->GetAttributeProperty(
         transactionStructureHandle + "." + refcountField,
         "max",
         repeatSize );
   }

   if ( !repeatSize.length() )
   {
      XMLSchema->GetAttributeProperty(
         attribute,
         "maxOccurs",
         repeatSize );
   }

   if ( repeatSize.length() )
   {
      /**
       * Now instantiate the array so that we may traverse it, but limit it to
       * repeatLimit elements.
       */
      const int   size = std::min< int >( atoi( repeatSize.c_str() ), repeatLimit );
      std::string    repeatName;

      if ( ( refcountField.length() == 0 ) ||
          XMLSchema->SetAttributeValue( transactionStructureHandle, refcountField, size ) )
      {
         if ( XMLSchema->GetAttributeProperty( attribute, "name", repeatName ) )
         {
            if ( size >= 1 )
            {
               AnsiString  repeatElement;
               std::string    datatype;
               repeatElement.sprintf( "%s.1.%s",
                  attribute.c_str(),
                  repeatName.c_str() );
               if ( XMLSchema->GetAttributeProperty(
                     repeatElement.c_str(),
                     "datatype",
                     datatype ) )
               {
                  const isStruct = ( datatype == "Struct" );
                  for ( int where = 1; where <= size; ++where )
                  {
                     repeatElement.sprintf( "%s.%d.%s",
                        attribute.c_str(),
                        where,
                        repeatName.c_str() );
                     if ( !isStruct )
                     {
                        ++childCount;
                     }
                     else
                     {
                        childCount += countChildren( repeatElement.c_str(), false ) + 1;
                     }
                  }
               }
               else
               {
                  MTHROW( std::runtime_error, \
                     "Cannot get datatype for schema element \"" \
                     << repeatElement.c_str() \
                     << "\"." );
               }
            }
         }
         else
         {
            MTHROW( std::runtime_error, \
               "Cannot get name for schema element \"" \
               << attribute \
               << "\"." );
         }
      }
      else
      {
         MTHROW( std::runtime_error, \
            "Cannot set size for schema element \"" \
            << transactionStructureHandle + "." + refcountField \
            << "\"." );
      }
   }
   else
   {
      MTHROW( std::runtime_error, \
         "Cannot get repeat size for schema element \"" \
         << attribute \
         << "\"." );
   }
   return ( childCount );
   
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::clearTransactionSpecificationValueTree( TDBAdvGrid & grid )
{
#if TDBADVGRID_FIXED
   grid.RemoveAllNodes();
#endif
}
//---------------------------------------------------------------------------

const int TMainForm::countChildNodes( TDBAdvGrid & grid, TADOQuery & query, const int & row, const int & rows )
{
   query.RecNo = row;   // Move the cursor to the row we're looking at.

   int               count    = 0;
   const AnsiString  parentPath  = query.FieldByName( "XPATH" )->AsString;

   for ( int where = row + 1; where <= rows; ++where )
   {
      query.RecNo = where;

      if ( parentPath == query.FieldByName( "XPATH" )
                        ->AsString.SubString( 1, parentPath.Length() ) )
      {
         ++count;
      }
      else
      {
         break;
      }
        
   }

   return ( count );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildTransactionSpecificationValueTree( TDBAdvGrid & grid, TADOQuery & query )
{
#if TDBADVGRID_FIXED
   grid.BeginUpdate();
   const int currentRow = query.RecNo;
   try
   {
      int children   = 0;
      const int rows = query.RecordCount;
      for ( int where = 1; where <= rows; ++where )
      {
         if ( ( children = countChildNodes( grid, query, where, rows ) ) > 0 )
         {
            grid.AddNode( where, 1 + children );
         }
      }
   }
   __finally
   {
      grid.ContractAll();
      query.RecNo = currentRow;
      grid.EndUpdate();
   }
#endif
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::getParentOrdinals( std::vector< int > & parents )
{
   TADOQuery * query = 0;
   try
   {
      parents.clear();

      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString  sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "ORDINAL "
         "FROM "
            "TXNSPEC_VALUES "
         "WHERE "
            "TESTSCENARIO_NO=%d AND "
            "TXNSPEC_NO=%d AND "
            "CHILD_COUNT > 0",
         m_testscenario_no,
         m_txnspec_no );
      query->SQL->Text = sqlStatement;
      query->Open();
      while ( !query->Eof )
      {
         parents.push_back( query->FieldByName( "ORDINAL" )->AsInteger );
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::populatePayloadStructureTab( const AnsiString & structure )
{
   AnsiString  sqlStatement;

   PayloadStructureTabSheet->TabVisible = true;
   PayloadStructureTabSheet->Caption = structure;
   
   TxnValuesQuery->Close();
#if TDBADVGRID_FIXED
   clearTransactionSpecificationValueTree( *NewPayloadStructureGrid );
#endif
   sqlStatement.sprintf(
      "SELECT "
         "* "
      "FROM "
         "TXNSPEC_VALUES "
      "WHERE "
         "TESTSCENARIO_NO=%d AND "
         "TXNSPEC_NO=%d AND "
         "XPATH LIKE \'/%s/%%\' AND "
         "DISPLAYABLE = \'Y\' AND "       
         "OBSOLETE=\'N\' "
#if !INCLUDE_PARENTS
         "AND CHILD_COUNT=0 "
#endif
      "ORDER BY "
         "ORDINAL,"
         "FIELDNAME,"
         "SUBSCRIPT",
      m_testscenario_no,
      m_txnspec_no,
      structure.c_str() );

   TxnValuesQuery->SQL->Text = sqlStatement;
   TxnValuesQuery->Open();

#if TDBADVGRID_FIXED
   buildTransactionSpecificationValueTree( *NewPayloadStructureGrid, *TxnValuesQuery );
#endif
#if INCLUDE_PARENTS
   getParentOrdinals( m_parents );
#endif
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::populateHeaderStructureTab( const AnsiString & structure )
{
   AnsiString sqlStatement;

   HeaderStructureTabSheet->TabVisible = false;
   HeaderStructureTabSheet->Caption = structure;

   TxnHeaderValuesQuery->Close();

   sqlStatement.sprintf(
      "SELECT "
         "* "
      "FROM "
         "TXNSPEC_VALUES "
      "WHERE "
         "TESTSCENARIO_NO=%d AND "
         "TXNSPEC_NO=%d AND "
         "XPATH LIKE \'/%s/%%\' AND "
         "OBSOLETE=\'N\' "
      "ORDER BY "
         "ORDINAL,"
         "FIELDNAME,"
         "SUBSCRIPT",
      m_testscenario_no,
      m_txnspec_no,
      structure.c_str() );

   TxnHeaderValuesQuery->SQL->Text = sqlStatement;
   TxnHeaderValuesQuery->Open();
}

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

void __fastcall TMainForm::TestCaseTreeViewChange(TObject *Sender,
     TTreeNode *Node)
{
   TestCaseTreeViewEnter(Sender);

   AnsiString  sql_statement;

    // Only update when TestCase nodes
    if (Node->Level == 0)
    {
      // ----------------- TEST CASE -----------------
      TestCasePanel->Caption = Node->Text;
      MainPageControl->ActivePage = ScenarioStepsTabSheet;

      m_testscenario_no = (int)(Node->Data);
      m_txnspec_no = 0;
      m_structure_name="";

      TxnValuesQuery->Close();
      TxnHeaderValuesQuery->Close();


      //TransactionStructurePageControl->ActivePage = PayloadStructureTabSheet;
      //PayloadStructureTabSheet->Caption = "Payload Structure";
      //HeaderStructureTabSheet->Caption = "Header Structure";
      //HeaderStructureTabSheet->TabVisible = false;


      m_parents.clear();

/*    
      TxnStepsQuery->Close();
      sql_statement="";
      sql_statement.sprintf("SELECT TESTCASE_SEQNO, NAME, REPEAT_COUNT, DESCRIPTION "
                            "FROM TEST_SCENARIOS "
                       "WHERE TESTCASE_ID = \'%s\' "
                       "ORDER BY TESTCASE_SEQNO",
                       m_currenttestcaseid);
                       
      TxnStepsQuery->SQL->Text = sql_statement;
      TxnStepsQuery->Open();
      TxnStepsQuery->Edit();
*/ 
      // ---------------------------------------------
   }
   else
   if (Node->Level == 1)
   {
      // ---------------- TRANSACTION ----------------

      TestCasePanel->Caption = Node->Parent->Text;
      MainPageControl->ActivePage = TestScenariosTabSheet;
        
      m_testscenario_no    = (int)(Node->Parent->Data);
      m_txnspec_no      = (int)(Node->Data);
      m_structure_name  = Node->Text.c_str();

      TransactionStructurePageControl->ActivePage = PayloadStructureTabSheet;
      if ( !m_transactionCache.isContained( m_txnspec_no ) )
      {
         const TCursor Save_Cursor = Screen->Cursor;
         try
         {
            Screen->Cursor = crHourGlass;

            AnsiString message;
            message.sprintf(
               " Building %s ...",
               Node->Text.c_str() );
            MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
            Application->ProcessMessages();

                
            buildTransactionSpecificationValues(
               m_transactionCache,
               m_testscenario_no,
               m_txnspec_no,
               Node->Text.c_str(),
               g_headerStructure,
               m_schema_handle,
               m_currentiteration );
         }
         __finally
         {
            Screen->Cursor = Save_Cursor;
         }
      }
      MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "";
      
      populateHeaderStructureTab( g_headerStructure );
      populatePayloadStructureTab( Node->Text );


//    if (TxnStepsQuery->State == dsEdit) TxnStepsQuery->Post();
//    TxnStepsQuery->Close();
/*    sql_statement="";
      sql_statement.sprintf("SELECT TESTCASE_SEQNO, NAME, REPEAT_COUNT, DESCRIPTION FROM TEST_SCENARIOS "
                       "WHERE TESTCASE_ID = \'%s\' "
                       "ORDER BY TESTCASE_SEQNO",
                       m_currenttestcaseid);
      TxnStepsQuery->SQL->Text = sql_statement;
*/    
//    if(!TxnStepsQuery->Active)
//    {
//       TxnStepsQuery->Open();
//       TxnStepsQuery->Edit();
//    }
      // ---------------------------------------------
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::NewTransactionActionExecute(TObject *Sender)
{
   TTreeNode   *current_node = TestCaseTreeView->Selected;

    if (current_node != NULL)
    {
      if (current_node->Level == 0) // Add Txn
      {
         AnsiString  testcase_text = current_node->Text;

         int   testscenario_no = (int)(current_node->Data);

         if ( TxnConfig->ShowForm(m_currentproject, m_currentiteration, testcase_text) == true)
            {
                TxnSpecQuery->Close();

                const TCursor Save_Cursor = Screen->Cursor;

                TADOQuery *   query = new TADOQuery(this);
                AnsiString sql_statement;
                query->Connection = Data_Module->IntegrationDBConnection;
                
                /* prepare to apply templates to new transaction(s) */
                TestScenarioTemplate * all   = m_transactionTemplates.findTestScenarioTemplate( 0 );
                TADOQuery *   txn_query = new TADOQuery(this);
                txn_query->Connection = Data_Module->IntegrationDBConnection;

                try
                {
                   /* could not make atomic as buildtxnspecvalues has a transaction */
                   //Data_Module->IntegrationDBConnection->BeginTrans(); 

                    sql_statement="";
                    sql_statement.sprintf("SELECT MAX(SEQ_NO) AS MAXSEQ_NO "
                                   "FROM TRANSACTION_SPECIFICATION "
                                          "WHERE PROJECT_CODE='%s' AND ITERATION=%d AND TESTSCENARIO_NO=%d",
                                          m_currentproject.c_str(),
                                m_currentiteration,
                                          testscenario_no);

                    query->SQL->Text = sql_statement;
                    query->Open();

                    int seq_no = query->FieldByName("MAXSEQ_NO")->AsInteger;
                    seq_no++;

                    vector<unsigned int>       selected_txns = TxnConfig->getSelectedTxns();
                    vector<unsigned int>::iterator selected_txn_itr = selected_txns.begin();
                    const unsigned count = selected_txns.end() - selected_txns.begin() + 1;
                    m_progressBar->open( count * 2 ); 

                    Screen->Cursor = crHourGlass;
                    AnsiString message;
                    message.sprintf(" Building %d new transactions ...", count );
                    MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                    Application->ProcessMessages();

                    while (selected_txn_itr != selected_txns.end())
                    {
                        unsigned int   txnindex = (*selected_txn_itr);
                        unsigned short udtype    = txnindex >> 16;
                        unsigned short udsubtype = txnindex & 0xffff;
                        AnsiString txnname = "";
                        
                        sql_statement="";
                        sql_statement.sprintf("INSERT INTO TRANSACTION_SPECIFICATION "
                                      "(PROJECT_CODE,ITERATION,TESTSCENARIO_NO,UDTYPE,UDSUBTYPE,SEQ_NO) "
                                      "VALUES ('%s',%d,%d,%d,%d,%d) ",
                                      m_currentproject.c_str(),
                                      m_currentiteration,
                                      testscenario_no,
                                      udtype,
                                      udsubtype,
                                      seq_no);

                        query->SQL->Text = sql_statement;
                        query->ExecSQL();
                        
                        // now we have created the new transaction we can get its primary key ansd apply the template
                        sql_statement="";                    
                        
                        sql_statement.sprintf("SELECT MASS_TXNS.NAME,TRANSACTION_SPECIFICATION.TXNSPEC_NO "
                          "FROM MASS_TXNS,TRANSACTION_SPECIFICATION "
                          "WHERE TRANSACTION_SPECIFICATION.TESTSCENARIO_NO = %d "
                          "AND   TRANSACTION_SPECIFICATION.ITERATION = %d"
                          "AND   MASS_TXNS.PROJECTCODE=TRANSACTION_SPECIFICATION.PROJECT_CODE "
                          "AND   MASS_TXNS.ITERATION=TRANSACTION_SPECIFICATION.ITERATION "
                          "AND   MASS_TXNS.UDTYPE=TRANSACTION_SPECIFICATION.UDTYPE "
                          "AND   MASS_TXNS.UDSUBTYPE=TRANSACTION_SPECIFICATION.UDSUBTYPE "
                          "AND   TRANSACTION_SPECIFICATION.UDTYPE = %d "
                          "AND   TRANSACTION_SPECIFICATION.UDSUBTYPE = %d "
                          "AND   TRANSACTION_SPECIFICATION.SEQ_NO = %d ",
                            testscenario_no,
                            m_currentiteration,
                            udtype,
                            udsubtype,
                            seq_no);
                            
                        txn_query->SQL->Text = sql_statement;
                        txn_query->Open();                                               

                        txnname = txn_query->FieldByName( "NAME" )->AsString;
                        m_txnspec_no = txn_query->FieldByName( "TXNSPEC_NO" )->AsInteger;
                        
                        // create txn spec values
                     
                        buildTransactionSpecificationValues(
                            m_transactionCache,
                            m_testscenario_no,
                            m_txnspec_no,
                            txnname.c_str(),
                            g_headerStructure,
                            m_schema_handle,
                            m_currentiteration );
           
 
                         // now apply template

                        applyTemplatesToNewTransaction( m_txnspec_no, all);
                        txn_query->Close();
                        
                        m_progressBar->increment();

                        seq_no++;

                        selected_txn_itr++;
                    }

                    //Data_Module->IntegrationDBConnection->CommitTrans(); //see comment above
                }
                catch(...)
                {
                    //Data_Module->IntegrationDBConnection->RollbackTrans(); //see comment above
                }
                
                MainStatusBar->Panels->Items[ g_messagePanel ]->Text = ""; 
                Screen->Cursor = Save_Cursor;
                delete query;

                TxnSpecQuery->Open();

                LoadTestCaseNodes(current_node);
                current_node->Expand(true);
            }
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::DeleteTransactionActionExecute(TObject *Sender)
{
   bool     refresh_testcases = false;

   for (unsigned selected_item=0; selected_item<TestCaseTreeView->SelectionCount; selected_item++)
   {
      TTreeNode   *current_node = TestCaseTreeView->Selections[selected_item];

      if (current_node!= NULL)
      {
         if (current_node->Level == 1) // Remove Test Case Transaction
         {
            // Confirm deletion
            AnsiString  message;
            message.sprintf( "Are you sure you want to delete transaction '%s'?", current_node->Text );

            if ( MessageDlg( message, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0 ) == mrYes )
            {
               int   testscenario_no = (int)(current_node->Parent->Data);
               int   txnspec_no = (int)(current_node->Data);

               TADOQuery   *query = new TADOQuery(this);
               AnsiString  sql_statement;
               query->Connection = Data_Module->IntegrationDBConnection;

               try
               {
                  Data_Module->IntegrationDBConnection->BeginTrans();

                  sql_statement.sprintf("DELETE FROM TXNSPEC_VALUES "
                                   "WHERE TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d",
                                   testscenario_no,
                                   txnspec_no);

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  sql_statement="";
                  sql_statement.sprintf("DELETE FROM TRANSACTION_SPECIFICATION "
                                   "WHERE PROJECT_CODE='%s' AND ITERATION=%d "
                                   "AND   TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d ",
                                   m_currentproject.c_str(),
                                   m_currentiteration,
                                   testscenario_no,
                                   txnspec_no);

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  Data_Module->IntegrationDBConnection->CommitTrans();

                  refresh_testcases = true;

                  ResequenceTransactions(current_node->Parent);
               }
               catch(...)
               {
                  Data_Module->IntegrationDBConnection->RollbackTrans();
               }

               delete query;
            }
         }
      }
   }

   if (refresh_testcases)
   {
      bool allow;
      TestCaseGridRowChanging(Sender, 0, 1, allow = true);
   }
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::TestCaseZoomInClick(TObject *Sender)
{
   TestCaseTreeView->FullExpand();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseZoomOutClick(TObject *Sender)
{
   TestCaseTreeView->FullCollapse();   
}
//---------------------------------------------------------------------------

AnsiString & TMainForm::getNameFromNode( AnsiString & name, const AnsiString & string )
{
    char const *p = string.c_str();

    name = string;
    if ( *p && *p == '(' )
    {
        ++p;
        while ( *p && isdigit( *p ) )
        {
            ++p;
        }
        if ( *p && *p == ')' )
        {
            ++p;
            while ( *p && isspace( *p ) )
            {
                ++p;
            }
            if ( *p )
            {
                name = p;
            }
        }
    }

   return ( name );
}


// delete a step via navigator button
void __fastcall TMainForm::ScenarioStepsNavigatorBefore(TObject *Sender, TAdvNavigateBtn Button)
{ 
    AnsiString BtnName;
    switch (Button)
    {
        case Dbctrls::nbFirst:  BtnName = "First Record"; break;
        case Dbctrls::nbPrior:  BtnName = "Prior Record"; break;
        case Dbctrls::nbNext:   BtnName = "Next Record"; break;
        case Dbctrls::nbLast:   BtnName = "Last Record"; break;
        case Dbctrls::nbInsert: 
        {  
             BtnName = "Insert Record";
             AddTestCaseNodeClick(Sender);            
             TTreeNode*    dummyNode;
             ResequenceTestCases(dummyNode);
             //TxnStepsQuery->Edit();             
             break;
        }
        case Dbctrls::nbDelete: BtnName = "Delete Record"; 
        {  
            //BtnName = "Delete Record";
            //AnsiString  message;
            //int myRow = StepsGrid->GetRealRow();
        // message.sprintf(
                            //"Are you sure you want to delete all transactions from test step ('%s') %s? ",
                             //StepsGrid->Cells[1][myRow],
                             //StepsGrid->Cells[2][myRow] );

         //if ( MessageDlg( message, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0 ) == mrYes )
        // {
                int scenario = TxnStepsQuery->FieldByName( "TESTSCENARIO_NO" )->AsInteger;
                DeleteScenarioChildren(scenario); 
           // }     
            break;
        }        
        case Dbctrls::nbEdit:   BtnName = "Edit"; break;

        case Dbctrls::nbCancel: BtnName = "Cancel Edits"; break;
        case Dbctrls::nbRefresh: BtnName = "Refresh Data"; break;
        default: BtnName = "Other"; break;
    }
    
}

// add a new step via navigator button
void __fastcall TMainForm::ScenarioStepsNavigatorClick(TObject *Sender, TAdvNavigateBtn Button)
{ 
    AnsiString BtnName;
   bool     refresh_testcases = false;
    switch (Button)
    {
        case Dbctrls::nbFirst:  BtnName = "First Record"; break;
        case Dbctrls::nbPrior:  BtnName = "Prior Record"; break;
        case Dbctrls::nbNext:   BtnName = "Next Record"; break;
        case Dbctrls::nbLast:   BtnName = "Last Record"; break;
        case Dbctrls::nbInsert: 
        {  
             BtnName = "Insert Record";
             //refresh_testcases = false;
             //AddTestCaseNodeClick(Sender);            
             //TTreeNode*    dummyNode;
             //ResequenceTestCases(dummyNode);
            // TxnStepsQuery->Edit();
            
             break;
        }
        case Dbctrls::nbDelete: BtnName = "Delete Record"; 
        {  
             BtnName = "Delete Record";
             refresh_testcases = true; 
             break;
        }        
        case Dbctrls::nbEdit:   BtnName = "Edit"; break;

        case Dbctrls::nbCancel: BtnName = "Cancel Edits"; break;
        case Dbctrls::nbRefresh: BtnName = "Refresh Data"; break;
        default: BtnName = "Other"; break;
    }

 
    //for (int J = 0; J < StepsGrid->RowCount; J++)
    //    StepsGrid->Cells[0][J] = IntToStr(J+1);
    

      
    //BtnName = BtnName + " button clicked.";
    //Application->MessageBox(BtnName.c_str() , "Navigator", MB_OK);
      
   if (refresh_testcases)
   {
      bool allow;
      TestCaseGridRowChanging(Sender, 0, 1, allow = true);
   }
}

// Add a New Use Case

void __fastcall TMainForm::AddTestCaseNodeClick(TObject *Sender)
{
    TADOQuery  *query = new TADOQuery(this);
    AnsiString sql_statement;
    query->Connection = Data_Module->IntegrationDBConnection;

    try
    {
        Data_Module->IntegrationDBConnection->BeginTrans();

        sql_statement="";
        sql_statement.sprintf("SELECT MAX(TESTCASE_SEQNO) MAX_SEQNO FROM TEST_SCENARIOS "
                       "WHERE PROJECT_CODE='%s' AND ITERATION=%d "
                              "AND TESTCASE_ID='%s'",
                              m_currentproject.c_str(),
                              m_currentiteration,
                              m_currenttestcaseid.c_str());

        query->SQL->Text = sql_statement;
        query->Open();
        int max_testcase_seqno = query->FieldByName("MAX_SEQNO")->AsInteger;

        sql_statement="";
        sql_statement.sprintf("INSERT INTO TEST_SCENARIOS (PROJECT_CODE,ITERATION,USECASE,TESTCASE_ID,TESTCASE_SEQNO,REPEAT_COUNT) "
                              "VALUES ('%s',%d,'%s','%s',%d,%d) ",
                              m_currentproject.c_str(),
                              m_currentiteration,
                              m_currenttestcaseid.c_str(),
                              m_currenttestcaseid.c_str(),
                              max_testcase_seqno+1,
                              1);

        query->SQL->Text = sql_statement;
        query->ExecSQL();

        Data_Module->IntegrationDBConnection->CommitTrans();
    }
    catch(...)
    {
        Data_Module->IntegrationDBConnection->RollbackTrans();
    }

    delete query;

   //refresh query and the tree view
   TxnStepsQuery->Refresh();   
   bool allow;
   TestCaseGridRowChanging(Sender, 0, 1, allow = true);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewEndDrag(TObject *Sender,
      TObject *Target, int X, int Y)
{
    TTreeNode* target_node = TestCaseTreeView->GetNodeAt(X, Y);
    if ((target_node != NULL) && (target_node != m_startnode))
    {
        TTreeNode *new_node         = NULL;
        TTreeNode *target_case_node = NULL;
        TTreeNode *start_case_node  = NULL;
        bool isStartTestCase        = (m_startnode->Level == 0);
        bool isTargetTestCase       = (target_node->Level == 0);

        // Move the selected transaction

        start_case_node = isStartTestCase ? m_startnode : m_startnode->Parent;
        target_case_node = isTargetTestCase ? target_node : target_node->Parent;

        TestCaseTreeView->Items->BeginUpdate();

        new_node = (isStartTestCase) ?
                    TestCaseTreeView->Items->Insert(target_case_node, m_startnode->Text) :
                    TestCaseTreeView->Items->AddChild(target_case_node, m_startnode->Text);

        new_node->Data = m_startnode->Data;
        TestCaseTreeView->Items->Delete(m_startnode);
        m_startnode = NULL;

        TestCaseTreeView->Items->EndUpdate();

        // Refresh the tree, resequencing affected cases/transactions

      if (isStartTestCase)
        {
            bool allow;
            ResequenceTestCases(target_case_node);
            TestCaseGridRowChanging(Sender, 0, 1, allow = true);
        }
        else
        {
            ResequenceTransactions(target_case_node);
            LoadTestCaseNodes(target_case_node);
            if( start_case_node != target_case_node )
            {
                ResequenceTransactions(start_case_node);
                LoadTestCaseNodes(start_case_node);
            }
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ResequenceTestCases(TTreeNode *testcase_node)
{
    // Resequence Subtree nodes
    TADOQuery  *query = new TADOQuery(this);
    AnsiString sql_statement;
    query->Connection = Data_Module->IntegrationDBConnection;

    try
    {
        Data_Module->IntegrationDBConnection->BeginTrans();

        int testcaseseqno = 1;
        for (int i=0; i<TestCaseTreeView->Items->Count; i++)
        {
            TTreeNode*  childnode = TestCaseTreeView->Items->Item[i];

            if (childnode->Level == 0) // Only consider TestCase Nodes
            {
                int        testscenario_no = (int)(childnode->Data);

                sql_statement="";
                sql_statement.sprintf("UPDATE TEST_SCENARIOS SET TESTCASE_SEQNO=%d "
                                      "WHERE TESTSCENARIO_NO=%d",
                                      testcaseseqno,
                                      testscenario_no);

                query->SQL->Text = sql_statement;
                query->ExecSQL();

                testcaseseqno++;
            }
        }

      Data_Module->IntegrationDBConnection->CommitTrans();
    }
    catch(...)
    {
        Data_Module->IntegrationDBConnection->RollbackTrans();
    }

    delete query;
}

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

void __fastcall TMainForm::ResequenceTransactions(TTreeNode *testcase_node)
{
    // Resequence Subtree nodes
    TADOQuery  *query = new TADOQuery(this);
    AnsiString sql_statement;
    query->Connection = Data_Module->IntegrationDBConnection;

    try
    {
        Data_Module->IntegrationDBConnection->BeginTrans();

        int testscenario_no = (int)(testcase_node->Data);

        for (int i=0; i<testcase_node->Count; i++)
        {
            sql_statement="";
            sql_statement.sprintf("UPDATE TRANSACTION_SPECIFICATION SET SEQ_NO=%d, TESTSCENARIO_NO=%d"
                                  "WHERE PROJECT_CODE='%s' AND ITERATION=%d "
                                  "AND TXNSPEC_NO=%d",
                                  i+1,
                                  testscenario_no,                                  
                                  m_currentproject.c_str(),
                                  m_currentiteration,
                                  testcase_node->Item[i]->Data);

            query->SQL->Text = sql_statement;
            query->ExecSQL();
        }

        Data_Module->IntegrationDBConnection->CommitTrans();
    }
    catch(...)
    {
        Data_Module->IntegrationDBConnection->RollbackTrans();
    }

    delete query;
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::TestCaseTreeViewStartDrag(TObject *Sender,
      TDragObject *&DragObject)
{
   m_startnode = TestCaseTreeView->Selected;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewDragOver(TObject *Sender,
      TObject *Source, int X, int Y, TDragState State, bool &Accept)
{
    Accept = false;
    
    TTreeView * tree_view = dynamic_cast<TTreeView *>(Source);
    if ( (tree_view != NULL) &&
         (tree_view == TestCaseTreeView) )
    {
        TTreeNode * source_node = TestCaseTreeView->GetNodeAt(X, Y);
        if( source_node != NULL )
        {
            // Source and destination cannot be the same
            if( m_startnode == source_node )
                return;

            // Test scenarios cannot be dropped on test cases
            if( (m_startnode->Level == 0) &&
                (source_node->Level == 1) )
                return;

            // Otherwise we can drop here
            Accept = true;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ApplyTemplatesClick(TObject *Sender)
{
   const TCursor Save_Cursor = Screen->Cursor;
   try
   {
      Screen->Cursor = crHourGlass;
      try
      {
         TADOQuery * query = 0;
         try
         {
            const unsigned count = countTransactionsInIteration(
               m_currentproject.c_str(),
               m_currentiteration );
            m_progressBar->open( count * 2 + 1 );

            // Rebuild the transaction templates, they may have changed.
            buildTransactionTemplates(
               m_transactionTemplates,
               m_currentproject,
               m_currentiteration );
            m_progressBar->increment();

            buildTransactionsForIteration(
               m_transactionCache,
               *m_progressBar,
               m_schema_handle,
               m_currentproject.c_str(),
               m_currentiteration );

            query = new TADOQuery( this );
            query->Connection = Data_Module->IntegrationDBConnection;

            AnsiString sqlStatement;
            sqlStatement.sprintf(
               "SELECT "
                  "TESTSCENARIO_NO "
                  ""
               "FROM "
                  "TEST_SCENARIOS "
               "WHERE "
                  "PROJECT_CODE=\'%s\' AND "
                  "ITERATION=%d",
               m_currentproject.c_str(),
               m_currentiteration );
            query->SQL->Text = sqlStatement;
            query->Open();

            try
            {
               Data_Module->IntegrationDBConnection->BeginTrans();
               while ( !query->Eof )
               {
                  applyTemplatesToScenario(
                     *m_progressBar,
                     query->FieldByName( "TESTSCENARIO_NO" )->AsInteger );
                  query->Next();
               }
               Data_Module->IntegrationDBConnection->CommitTrans();

               if ( TxnValuesQuery->State != dsInactive )
               {
                  TxnValuesQuery->Refresh();
                  HeaderStructureGrid->Invalidate();
               }
               if ( TxnHeaderValuesQuery->State != dsInactive )
               {
                  TxnHeaderValuesQuery->Refresh();
                  TransactionValueGrid->Invalidate();
               }

            }
            catch ( ... )
            {
               Data_Module->IntegrationDBConnection->RollbackTrans();
               throw;
            }
         }
         __finally
         {
            delete query;
            query = 0;

            m_progressBar->close();
         }
      }
      catch ( const std::exception & exception )
      {
         MessageDlg(
            exception.what(),
            mtError, TMsgDlgButtons() << mbOK, 0 );
      }
      catch ( ... )
      {
         MessageDlg(
            "Unknown exception applying templates to this scenario.",
            mtError, TMsgDlgButtons() << mbOK, 0 );
      }
   }
   __finally
   {
      Screen->Cursor = Save_Cursor;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::InitialiseMASSTxns()
{
   AnsiString  sql_statement;

   TADOQuery   *query = new TADOQuery(this);
    query->Connection = Data_Module->IntegrationDBConnection;

   m_mass_txns.clear();

   try
    {
        sql_statement="";
        sql_statement.sprintf("SELECT NAME,UDTYPE,UDSUBTYPE "
                              "FROM MASS_TXNS "
                              "WHERE PROJECTCODE='%s' "
                              "AND   ITERATION=%d "
                       "AND   ENABLED = 'Y' ",
                              m_currentproject.c_str(),
                              m_currentiteration);

        query->SQL->Text = sql_statement;
        query->Open();
        while (!query->Eof)
        {
            unsigned short udtype      = query->FieldByName("UDTYPE")->AsInteger;
            unsigned short udsubtype   = query->FieldByName("UDSUBTYPE")->AsInteger;
            unsigned int   udindex  = (udtype << 16) + udsubtype;

            TXNIndexPair   pair(udindex, query->FieldByName("NAME")->AsString);

            m_mass_txns.insert(pair);

            query->Next();
        }
    }
    __finally
    {
      delete query;
    }
}

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

void __fastcall TMainForm::InitialiseTxnParams(unsigned int schema_format_version, IterationParams &iteration_params, IterationSequences &iteration_sequences)
{
   AnsiString  sql_statement;

    // Format Version only encodes Major/Minor numbers, and not Patch Level
   AnsiString  formatversion;
    formatversion.sprintf("0x%08X", schema_format_version);

    IterationParamsPair    pair("#0_@FORMATVERSION", formatversion.c_str());
    iteration_params.insert(pair);

    TADOQuery  *query = new TADOQuery(this);
    query->Connection = Data_Module->IntegrationDBConnection;

    TADOQuery  *seqquery = new TADOQuery(this);
    seqquery->Connection = Data_Module->IntegrationDBConnection;

    try
    {
        sql_statement="";
        sql_statement.sprintf("SELECT * FROM ITERATION_PARAMS "
                              "WHERE PROJECT_CODE='%s' AND ITERATION=%d AND SUPPORTED <> 0 " ,
                              m_currentproject.c_str(), m_currentiteration);

        query->SQL->Text = sql_statement;
        query->Open();
        while (!query->Eof)
        {
            int         testscenario_no = 0;

            string      fieldvalue  = query->FieldByName("FIELDVALUE")->AsString.c_str();

            if ( !query->FieldByName("TESTSCENARIO_NO")->IsNull )
            {
                testscenario_no = query->FieldByName("TESTSCENARIO_NO")->AsInteger;
            }

            // Format is: @SEQ(<name>,<start>,<inc>,<limit>)
            if (fieldvalue.substr(0,4) == "@SEQ")
            {
                int lpos = fieldvalue.find("(")+1;
                int rpos = fieldvalue.rfind(")");

                string  seqargs = fieldvalue.substr( lpos, rpos );
                string  seqname;
                string  seqstart;
                string  seqinc;
                string  seqlimit;

                const char *p = seqargs.c_str();
                while ( (*p != '\0') && (*p == ' ') ) p++;     // Skip Whitespace

                while ( (*p != '\0') && (*p != ',') && (*p != ' ') )
                {
                    seqname += *p;
                    p++;
                }
                if (*p != '\0') p++;

                while ( (*p != '\0') && (*p == ' ') )
                {
                    p++;      // Skip Whitespace
                }
                while ( (*p != '\0') && (*p != ',') && (*p != ' ') )
                {
                    seqstart += *p;
                    p++;
                }
                if (*p != '\0') p++;

                while ( (*p != '\0') && (*p == ' ') )
                {
                    p++;      // Skip Whitespace
                }

                while ( (*p != '\0') && (*p != ',') && (*p != ' ') )
                {
                    seqinc += *p;
                    p++;
                }
                if (*p != '\0') p++;

                while ( (*p != '\0') && (*p == ' ') )
                {
                    p++;      // Skip Whitespace
                }

                while (*p != '\0')
                {
                    seqlimit += *p;
                    p++;
                }

                IterationSequence   sequence;
                sequence.name    = seqname;

                if (seqstart.length() > 0)
                {
                    sequence.initial_value = atoi(seqstart.c_str());
                }
                else
                {
                    sequence.initial_value = 0;
                }

                if (seqname[0] == '#')
                {
                    string seqgenname = seqname.substr(1,seqname.length()-1);

                    sql_statement="";
                    sql_statement.sprintf("SELECT SEQVALUE FROM SEQGEN WHERE PROJECT_CODE='%s' AND ITERATION=%d AND SEQNAME='%s'",
                                          m_currentproject.c_str(),
                                          m_currentiteration,
                                          seqgenname.c_str()
                                          );
                    seqquery->SQL->Text = sql_statement;
                    seqquery->Open();
                    if (seqquery->RecordCount == 0)
                    {
                        sql_statement="";
                        sql_statement.sprintf("INSERT INTO SEQGEN (PROJECT_CODE,ITERATION,SEQNAME,SEQVALUE) VALUES ('%s',%d,'%s',%d)",
                                              m_currentproject.c_str(),
                                              m_currentiteration,
                                              seqgenname.c_str(),
                                              sequence.initial_value
                                              );
                        seqquery->SQL->Text = sql_statement;
                        seqquery->ExecSQL();
                    }
                    else
                    {
                        sequence.initial_value = seqquery->FieldByName("SEQVALUE")->AsInteger;
                    }
                }

                sequence.value = sequence.initial_value;

                if (seqinc.length() > 0)
                {
                    sequence.increment    = atoi(seqinc.c_str());
                }
                else
                {
                    sequence.increment    = 1;
                }

                if (seqlimit.length() > 0)
                {
                    sequence.reset_at  = atoi(seqlimit.c_str());
                }
                else
                {
                    sequence.reset_at  = 0;
                }

                sequence.reset_at = 0;

                IterationSequencesPair seqpair(sequence.name, sequence);
                iteration_sequences.insert(seqpair);
            }

            AnsiString  param_name;
            param_name.sprintf("#%d_%s", testscenario_no, query->FieldByName("NAME")->AsString.c_str());

            IterationParamsPair  pair2(param_name.c_str(), fieldvalue.c_str());
            iteration_params.insert(pair2);

            query->Next();
        }
    }
    __finally
    {
        delete query;
        delete seqquery;
    }
}

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

void __fastcall TMainForm::InitialiseTestScenario(unsigned int testscenario_no, TxnSpecValueMap &txnSpecValueMap, FoundTxnSpecValueMap &foundTxnSpecValueMap, IterationSequences &iteration_sequences, IterationParams &iteration_params)
{
   AnsiString  sql_statement;
   TADOQuery  *query = new TADOQuery(this);
   query->Connection = Data_Module->IntegrationDBConnection;

   TADOQuery  *values_query = new TADOQuery(this);
   values_query->Connection = Data_Module->IntegrationDBConnection;

   try
   {
      sql_statement="";
      sql_statement.sprintf("select txnspec_no,udtype,udsubtype "
                       "from transaction_specification "
                       "where testscenario_no=%d order by seq_no",
                              testscenario_no);
      query->SQL->Text = sql_statement;
      query->Open();
      while (!query->Eof)
      {
          // For each transaction
          unsigned int   txnspec_no  = query->FieldByName("TXNSPEC_NO")->AsInteger;
          unsigned short  udtype     = query->FieldByName("UDTYPE")->AsInteger;
          unsigned short  udsubtype  = query->FieldByName("UDSUBTYPE")->AsInteger;
          unsigned int   udindex  = (udtype << 16) + udsubtype;

          TXNIndexMap::iterator   txn_itr = m_mass_txns.find(udindex);

          if (txn_itr != m_mass_txns.end())
          {
             string   structure_name;
             string   structure_handle;

             structure_name = (*txn_itr).second.c_str();

             // Create a Transaction Instance
             if (XMLSchema->Create(m_schema_handle.c_str(), structure_name.c_str(), m_currentiteration, structure_handle, NULL))
             {
                ProcessTxnStructure(structure_handle, udtype, udsubtype, testscenario_no, txnspec_no, values_query, txnSpecValueMap, foundTxnSpecValueMap, iteration_params, iteration_sequences, 0);
                XMLSchema->Destroy(structure_handle);
             }
             else
             {
                AnsiString  msg;
                msg.sprintf("Failed to create schema object for Schema: '%s' Structure: '%s'",
                        m_schema_handle.c_str(),
                        structure_name.c_str());
                MessageDlg(msg,
                        mtError, TMsgDlgButtons() << mbOK, 0);
             }

          } // Found Transaction declaration in MASS TXNS

          query->Next();
      }
   }
   __finally
   {
      delete query;
      delete values_query;
   }
}

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

void __fastcall TMainForm::ProcessTxnStructure(string structure_handle, unsigned short udtype, unsigned short udsubtype, int testscenario_no, int txnspec_no, TADOQuery *query, TxnSpecValueMap &txnSpecValueMap, FoundTxnSpecValueMap &foundTxnSpecValueMap, IterationParams &iteration_params, IterationSequences &iteration_sequences, unsigned int nested_subscript)
{
   vector<string>          structure_attributes;
    vector<string>::iterator  s_itr;
    AnsiString             sql_statement;

    XMLSchema->GetAttributes(structure_handle, structure_attributes);

    s_itr = structure_attributes.begin();
    while (s_itr != structure_attributes.end())
    {
      string   attribute_handle = (*s_itr);

      string   elementtype;

        XMLSchema->GetAttributeProperty(attribute_handle, "type", elementtype);

        if (elementtype == "field")
        {
            string   datatype;

            XMLSchema->GetAttributeProperty(attribute_handle, "datatype", datatype);

            if (datatype == "Struct")
            {
                ProcessTxnStructure(attribute_handle, udtype, udsubtype, testscenario_no, txnspec_no, query, txnSpecValueMap, foundTxnSpecValueMap, iteration_params, iteration_sequences, 0);
            }
            else
            {
               string   fieldname;
                string  tagvalue;
                string  xpath;

                XMLSchema->GetAttributeProperty(attribute_handle, "tag", tagvalue);

                if (tagvalue.length() > 0)
                {
                    XMLSchema->GetAttributeProperty(attribute_handle, "name", fieldname);
                    XMLSchema->GetAttributeProperty(attribute_handle, "xpath", xpath);

                    AnsiString   lookup_fieldname;
                    AnsiString   display_fieldname;

                    if (nested_subscript == 0)
                    {
                       lookup_fieldname.sprintf("$%s", fieldname.c_str());
                       display_fieldname = fieldname.c_str();
                    }
                    else
                    {
                      lookup_fieldname.sprintf("$%s#%d", fieldname.c_str(), nested_subscript);
                      display_fieldname.sprintf("%s#%d", fieldname.c_str(), nested_subscript);
                    }

                    AnsiString   field_value = LookupParameter(iteration_params, iteration_sequences, query, testscenario_no, lookup_fieldname.c_str(), udtype, udsubtype);

                    AnsiString   key;

                    if (nested_subscript == 0)
                    {
                        key.sprintf("%d_%d_%s",
                                    testscenario_no,
                                    txnspec_no,
                                    fieldname.c_str());
                    }
                    else
                    {
                        key.sprintf("%d_%d_%s#%d",
                                    testscenario_no,
                                    txnspec_no,
                                    fieldname.c_str(),
                                    nested_subscript);
                    }

                    FoundTxnSpecValuePair   foundpair(key, 0);
                    foundTxnSpecValueMap.insert(foundpair);

                    TxnSpecValueIterator  txnspec_value_itr = txnSpecValueMap.find(key);
                    TxnSpecValue       &existing_value = (*txnspec_value_itr).second;

                    // Either no existing entry OR the current entry is NOT User supplied
                    // (ie. Ignore field values for existing user supplied items)
                    if ( (txnspec_value_itr == txnSpecValueMap.end()) ||
                      (existing_value.user_supplied == 'N') )
                    {
                       if ( (existing_value.fieldtag  != atoi(tagvalue.c_str()) ||
                         (existing_value.fieldvalue   != field_value) ||
                         (existing_value.xpath     != AnsiString(xpath.c_str()))) )
                       {
                           // Remove the existing value
                           if (txnspec_value_itr != txnSpecValueMap.end())
                           {
                              sql_statement="";
                                sql_statement.sprintf("DELETE FROM TXNSPEC_VALUES WHERE "
                                                      "TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d AND FIELDNAME='%s'",
                                                      testscenario_no,
                                         txnspec_no,
                                                      fieldname.c_str() );
                                query->SQL->Text = sql_statement;
                                query->ExecSQL();
                           }

                           // Add the new value
                           sql_statement="";
                           if (field_value.Length() > 0)
                           {
                              sql_statement.sprintf("INSERT INTO TXNSPEC_VALUES(FIELDTAG, FIELDVALUE, TESTSCENARIO_NO, TXNSPEC_NO, FIELDNAME, DISPLAY_FIELDNAME, XPATH, SUBSCRIPT, USER_SUPPLIED) "
                                                      "VALUES (%s,'%s',%d,%d,'%s','%s','%s',%d,'N')",
                                                      tagvalue.c_str(),
                                                      field_value.c_str(),
                                                      testscenario_no,
                                                      txnspec_no,
                                                      fieldname.c_str(),
                                                      display_fieldname.c_str(),
                                                      xpath.c_str(),
                                                      nested_subscript);
                           }
                           else
                           {
                              sql_statement.sprintf("INSERT INTO TXNSPEC_VALUES(FIELDTAG, TESTSCENARIO_NO, TXNSPEC_NO, FIELDNAME, DISPLAY_FIELDNAME, XPATH, SUBSCRIPT, USER_SUPPLIED) "
                                                      "VALUES (%s,%d,%d,'%s','%s','%s',%d,'N')",
                                                      tagvalue.c_str(),
                                                      testscenario_no,
                                                      txnspec_no,
                                                      fieldname.c_str(),
                                                      display_fieldname.c_str(),
                                                      xpath.c_str(),
                                                      nested_subscript);
                           }

                           query->SQL->Text = sql_statement;
                           query->ExecSQL();
                        }
                    }
                }
           }
      }
      else
      if (elementtype == "repeat")
      {
         string refcountfield;
         string   maxOccursStr;
         string   refcountAttribute;

         XMLSchema->GetAttributeProperty(attribute_handle, "refcountfield", refcountfield);

         if (!refcountfield.empty())
         {
             string      refcountAttribute = structure_handle+"."+refcountfield;

             XMLSchema->GetAttributeProperty(refcountAttribute, "max", maxOccursStr);
         }

         if (maxOccursStr.empty())
         {
             XMLSchema->GetAttributeProperty(attribute_handle, "maxOccurs", maxOccursStr);
         }

         int maxOccurs = atoi(maxOccursStr.c_str());

         // Limit to 100 elements
         if (maxOccurs > 100)
         {
             maxOccurs = 100;
         }

        string   repeat_name;
        XMLSchema->GetAttributeProperty(attribute_handle, "name", repeat_name);

        XMLSchema->SetAttributeValue(structure_handle, refcountfield, maxOccurs);

        for (int occurrence=1; occurrence<=maxOccurs; occurrence++)
        {
            string      repeat_attribute_handle;
            AnsiString temp;

            temp.sprintf("%s.%d.%s",attribute_handle.c_str(),occurrence,repeat_name.c_str());

            repeat_attribute_handle = temp.c_str();

            string  repeat_attribute_datatype;
            XMLSchema->GetAttributeProperty(repeat_attribute_handle, "datatype", repeat_attribute_datatype);

            if (repeat_attribute_datatype != "Struct")
            {
                string fieldname;
                string xpath;
                string tagvalue;

                XMLSchema->GetAttributeProperty(repeat_attribute_handle, "tag", tagvalue);

                if (tagvalue.length() > 0)
                {
                     XMLSchema->GetAttributeProperty(repeat_attribute_handle, "name", fieldname);
                     XMLSchema->GetAttributeProperty(repeat_attribute_handle, "xpath", xpath);
   
                     string   lookup_fieldname = "$"+fieldname;
                     AnsiString  field_value = LookupParameter(iteration_params, iteration_sequences, query, testscenario_no, lookup_fieldname, udtype, udsubtype);
   
                     AnsiString  key;
   
                     key.sprintf("%d_%d_%s.%d",
                                 testscenario_no,
                                 txnspec_no,
                                 fieldname.c_str(),
                                 occurrence);

                     FoundTxnSpecValuePair   foundpair(key, 0);
                     foundTxnSpecValueMap.insert(foundpair);

                     TxnSpecValueIterator txnspec_value_itr = txnSpecValueMap.find(key);
                     TxnSpecValue         &existing_value = (*txnspec_value_itr).second;

                     // Either no existing entry OR the current entry is NOT User supplied
                     // (ie. Ignore field values for existing user supplied items)
                     if ( (txnspec_value_itr == txnSpecValueMap.end()) ||
                          (existing_value.user_supplied == 'N') )
                     {
                         if ( (existing_value.fieldtag   != atoi(tagvalue.c_str()) ||
                              (existing_value.fieldvalue != field_value) ||
                              (existing_value.xpath      != AnsiString(xpath.c_str()))) )
                         {
                             // Remove the existing value
                             if (txnspec_value_itr != txnSpecValueMap.end())
                             {
                                 sql_statement="";
                                 sql_statement.sprintf("DELETE FROM TXNSPEC_VALUES WHERE "
                                         "TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d AND FIELDNAME='%s' AND SUBSCRIPT=%d",
                                                       testscenario_no,
                                                       txnspec_no,
                                                       fieldname.c_str(),
                                                       occurrence );
                                 query->SQL->Text = sql_statement;
                                 query->ExecSQL();
                             }

                             AnsiString   subscripted_fieldname;
                             subscripted_fieldname.sprintf("%s#%d", fieldname.c_str(), occurrence);

                             // Add the new value
                             sql_statement="";
                             if (field_value.Length() > 0)
                             {
                                 sql_statement.sprintf("INSERT INTO TXNSPEC_VALUES(FIELDTAG, FIELDVALUE, TESTSCENARIO_NO, TXNSPEC_NO, FIELDNAME, DISPLAY_FIELDNAME, SUBSCRIPT, XPATH, USER_SUPPLIED) "
                                                       "VALUES (%s,'%s',%d,%d,'%s','%s',%d,'%s','N')",
                                                       tagvalue.c_str(),
                                                       field_value.c_str(),
                                                       testscenario_no,
                                                       txnspec_no,
                                                       fieldname.c_str(),
                                                       subscripted_fieldname.c_str(),
                                                       occurrence,
                                                       xpath.c_str());
                             }
                             else
                             {
                                 sql_statement.sprintf("INSERT INTO TXNSPEC_VALUES(FIELDTAG, TESTSCENARIO_NO, TXNSPEC_NO, FIELDNAME, DISPLAY_FIELDNAME, SUBSCRIPT, XPATH, USER_SUPPLIED) "
                                                       "VALUES (%s,%d,%d,'%s','%s',%d,'%s','N')",
                                                       tagvalue.c_str(),
                                                       testscenario_no,
                                                       txnspec_no,
                                                       fieldname.c_str(),
                                                       subscripted_fieldname.c_str(),
                                                       occurrence,
                                         xpath.c_str());
                             }

                             query->SQL->Text = sql_statement;
                             query->ExecSQL();
                            }
                        }
                    } // if (tagvalue.length() > 0)
                } // if (repeat_attribute_datatype != "Struct")
                else
                {
                  ProcessTxnStructure(repeat_attribute_handle, udtype, udsubtype, testscenario_no, txnspec_no, query, txnSpecValueMap, foundTxnSpecValueMap, iteration_params, iteration_sequences, occurrence);
                }
            } // for (int i=1; i<=occurrence; i++)
        }

        s_itr++;
    } // while
}

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

AnsiString TMainForm::LookupParameter(IterationParams &iteration_params, IterationSequences &iteration_sequences, TADOQuery *query, int testscenario_no, const string &param, unsigned short udtype, unsigned short udsubtype)
{
   AnsiString  field_value;
   AnsiString  param_lookup;

    param_lookup.sprintf("#%d_%s", testscenario_no, param.c_str());

    IterationParams::iterator  param_itr = iteration_params.find(param_lookup.c_str());

    if (param_itr == iteration_params.end())
    {
      param_lookup="";
       param_lookup.sprintf("#%d_%s", 0, param.c_str());
       param_itr = iteration_params.find(param_lookup.c_str());
    }

    if (param_itr != iteration_params.end())
    {
        string param_value = (*param_itr).second;

        if (param_value == "@FORMATVERSION")
        {
            field_value = LookupParameter(iteration_params, iteration_sequences, query, testscenario_no, param_value, udtype, udsubtype);
        }
        else
        if (param_value == "@NOW")
        {
            TDateTime   current_time = TDateTime::CurrentDateTime();

            field_value.sprintf("%s", current_time.FormatString("dd-mm-yyyy hh:nn:ss").c_str());
        }
        else
        if (param_value == "@UTCNOW")
        {
            TDateTime   current_time = TDateTime::CurrentDateTime() + ((_timezone/3600.0)/24.0);

            field_value.sprintf("%s", current_time.FormatString("dd-mm-yyyy hh:nn:ss").c_str());
        }
        else
        if (param_value == "@TODAY")
        {
            TDateTime   current_time = TDateTime::CurrentDateTime();

            field_value.sprintf("%s", current_time.FormatString("dd-mm-yyyy").c_str());
        }
        else
        if (param_value == "@YESTERDAY")
        {
            TDateTime   current_time = TDateTime::CurrentDateTime() - 1;

            field_value.sprintf("%s", current_time.FormatString("dd-mm-yyyy").c_str());
        }
        else
        if (param_value.substr(0,5) == "@RAND")
        {
         int   lpos = param_value.find("(")+1;

            string   rand_args = param_value.substr(lpos, param_value.rfind(")")-1);
         string   lower_bound;
         string   upper_bound;

            const char *p = rand_args.c_str();
            while ( (*p != '\0') && (*p != ',') )
            {
               lower_bound += *p;
                
               p++;
            }
            if ( *p == ',' )
            {
               p++;
            }
            while ( (*p != '\0') && (*p != ')') )
            {
               upper_bound += *p;

               p++;
            }

            int      lower_int = atoi(lower_bound.c_str());
            int      upper_int = atoi(upper_bound.c_str());
            double  rand_key = (double)rand() / (double)RAND_MAX;

            int   rand_value = (rand_key * (upper_int - lower_int)) + lower_int;

            field_value.sprintf("%d", rand_value);
        }
        else
        if (param_value == "@UDTYPE")
        {
            field_value.sprintf("%d", udtype);
        }
      else
        if (param_value == "@UDSUBTYPE")
        {
            field_value.sprintf("%d", udsubtype);
        }
        else
        if (param_value == "@ACCOUNTTYPE")
        {
         int   account_format = 0;
         switch(udtype)
            {
            case 1:  // Card
               account_format = 2;
                break;
            case 2:  // Application
               account_format = 1;
                break;
            case 3:  // Product
               account_format = 3;
                break;
            case 4:  // Other
               account_format = 4;
                break;
            case 5:  // Audit
               account_format = 4;
                break;
            case 6:  // Event
               account_format = 4;
                break;
            case 7:  // Project
               account_format = 4;
                break;
            } // switch

            field_value.sprintf("%d", account_format);
        }
        else
        if (param_value.substr(0,4) == "@SEQ")
        {
            int   lpos = param_value.find("(")+1;
            int   comma_pos = param_value.find(",");
            string   seqname = param_value.substr( lpos, comma_pos-lpos );

            IterationSequences::iterator s_itr = iteration_sequences.find( seqname );
            if (s_itr != iteration_sequences.end())
            {
               IterationSequence &sequence = (*s_itr).second;

                field_value.sprintf("%d", sequence.value);
                sequence.value += sequence.increment;

                if (sequence.reset_at != 0)
                {
                    if (sequence.value >= sequence.reset_at)
                    {
                        sequence.value = sequence.initial_value;
                    }
                }

                if (seqname[0] == '#')
                {
                    AnsiString   sql_statement;
                    string    seqgenname = seqname.substr(1,seqname.length()-1);

                    sql_statement.sprintf("UPDATE SEQGEN SET SEQVALUE=%d where PROJECT_CODE='%s' AND ITERATION=%d AND SEQNAME='%s'",
                                   sequence.value,
                                          m_currentproject.c_str(),
                                          m_currentiteration,
                                          seqgenname.c_str()
                                          );
                    query->SQL->Text = sql_statement;
                    query->ExecSQL();
                }
            }
        }
        else
        if (param_value[0] == '@')
        {
            field_value = LookupParameter(iteration_params, iteration_sequences, query, testscenario_no, param_value, udtype, udsubtype);
        }
        else
        {
            field_value.sprintf("%s", param_value.c_str());
        }
    }
    return field_value;
}

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

void __fastcall TMainForm::TxnHdrValuesQueryAfterInsert(TDataSet *DataSet)
{
   DataSet->FieldByName("PROJECT_CODE")->AsString  = m_currentproject;
   DataSet->FieldByName("ITERATION")->AsInteger    = m_currentiteration;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ScenarioParametersClick(TObject *Sender)
{
   ScenarioParamsForm->ShowForm(m_currentproject, m_currentiteration, m_testscenario_no);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
   if (Button == mbRight)
   {
       TTreeNode* target_node = TestCaseTreeView->GetNodeAt(X, Y);
       if (target_node != NULL)
       {
          target_node->Selected = true;
       }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TxnValuesQueryBeforePost(TDataSet *DataSet)
{
// DataSet->FieldByName( "USER_SUPPLIED" )->AsString = "Y";
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::RemoveUserSuppliedValueClick(TObject *Sender)
{
   if (TxnValuesQuery->FieldByName("USER_SUPPLIED")->AsString == "Y")
    {
       Data_Module->IntegrationDBConnection->BeginTrans();

      TxnValuesQuery->Delete();

        Data_Module->IntegrationDBConnection->CommitTrans();
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::CopyValuesToClipboardBtnClick(TObject *Sender)
{
    AnsiString clipboard_text;

    Clipboard()->Clear();

    AnsiString sql_statement;
    TADOQuery  *query = new TADOQuery(this);
    query->Connection = Data_Module->IntegrationDBConnection;

    sql_statement.sprintf("SELECT * FROM TXNSPEC_VALUES "
                          "WHERE TESTSCENARIO_NO=%d AND TXNSPEC_NO=%d "
                    "AND (FIELDVALUE IS NOT NULL OR FIELDVALUE<>'') "
                          "ORDER BY FIELDNAME",
                          m_testscenario_no, m_txnspec_no);

    query->SQL->Text = sql_statement;
    query->Open();

    while (!query->Eof)
    {
        AnsiString  clipboard_line;

        clipboard_line.sprintf("%-30.30s\t%s\r\n",
                        query->FieldByName("FIELDNAME")->AsString.c_str(),
                        query->FieldByName("FIELDVALUE")->AsString.c_str()
                               );

        clipboard_text += clipboard_line;

        query->Next();
    }

   query->Close();

   Clipboard()->SetTextBuf( clipboard_text.c_str() );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::loadLegacyVariables( DefinedVariableTable & variables, const AnsiString & project, Iteration & iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "NAME,"
            "FIELDVALUE,"
            "TESTSCENARIO_NO "
         "FROM "
            "ITERATION_PARAMS "
         "WHERE "
            "PROJECT_CODE=\'%s\' AND "
            "ITERATION=%d",
         project.c_str(),
         iteration.getIterationId() );
      query->SQL->Text = sqlStatement;
      query->Open();

      AnsiString        fieldName;
      AnsiString        xpath;
      AnsiString        value;
      bool           qualified;
      DefinedVariable * variable;
      while ( !query->Eof )
      {
         fieldName   = query->FieldByName( "NAME" )->AsString;
         value    = query->FieldByName( "FIELDVALUE" )->AsString;

         if ( !value.IsEmpty() )
         {
            if ( value[ 1 ] == '=' )
            {
               value.Delete( 1, 1 );
            }

            if ( !value.IsEmpty() )
            {
               switch ( value[ 1 ] )
               {
               case '@':
                  value[ 1 ] = '=';
                  if ( FieldExpression::isFunctor(
                        value.c_str() + 1 ) )
                  {
                     value += "()";
                  }
                  break;
               default:
                  break;
               }
            }
         }

         if ( !fieldName.IsEmpty() )
         {
            qualified = !query->FieldByName( "TESTSCENARIO_NO" )->IsNull;

            switch ( fieldName[ 1 ] )
            {
            case '$':   // We don't worry about fields here.
               break;
            case '@':
               if ( qualified )
               {
                  variable = &variables.defineVariable(
                     fieldName.c_str() + 1,
                     iteration.getTestScenario(
                        query->FieldByName( "TESTSCENARIO_NO" )
                           ->AsInteger ) );
               }
               else
               {
                  variable = &variables.defineVariable(
                     fieldName.c_str() + 1 );
               }
               variable->setExpression( value.c_str() );
               break;
            default:
               break;
            }
         }
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::readSequences( SequenceCollection & sequences, const std::string & project, const int & iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "SEQNAME,"
            "SEQVALUE "
         "FROM "
            "SEQGEN "
         "WHERE "
            "PROJECT_CODE=\'%s\' AND "
            "ITERATION=%d",
         Utilities::EscapeString( project ).c_str(),
         iteration );
      query->SQL->Text = sqlStatement;
      query->Open();

      std::string sequenceName;
      int         value;
      Sequence *  sequence;
      while ( !query->Eof )
      {
         sequenceName   = query->FieldByName( "SEQNAME" )->AsString.c_str();
         value       = query->FieldByName( "SEQVALUE" )->AsInteger;

         sequence = &sequences.getSequence( sequenceName, true, 0 );
         sequence->setValue( value );
         sequence->setUpdate( true );
         sequence->setDirty( false );

         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::writeSequences( const SequenceCollection & sequences, const std::string & project, const int & iteration )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      for ( std::map< std::string, Sequence * >::const_iterator
            sequence = sequences.getCollection().begin();
            sequence != sequences.getCollection().end();
            ++sequence )
      {
         std::stringstream stream;
         if ( sequence->second->isPersisted() && sequence->second->isDirty() )
         {
            if ( sequence->second->isUpdate() )
            {
               stream
                  << "UPDATE SEQGEN SET "
                     << "SEQVALUE=" << sequence->second->getValue()
                  << " WHERE "
                     << "PROJECT_CODE=\'" << Utilities::EscapeString( project ) << "\' AND "
                     << "ITERATION=" << iteration << " AND "
                     << "SEQNAME=\'" << Utilities::EscapeString( sequence->second->getName() ) << '\'';
            }
            else
            {
               stream
                  << "INSERT INTO SEQGEN ( "
                     "PROJECT_CODE,"
                     "ITERATION,"
                     "SEQNAME,"
                     "SEQVALUE "
                  " ) VALUES ( "
                     << '\'' << Utilities::EscapeString( project ) << "\',"
                     << iteration << ",\'"
                     << Utilities::EscapeString( sequence->second->getName() ) << "\',"
                     << sequence->second->getValue()
                  << " )";
            }
            
            query->SQL->Text = stream.str().c_str();
            if ( query->ExecSQL() != 1 )
            {
               MTHROW( std::runtime_error, \
                  "Cannot " \
                  << ( sequence->second->isUpdate() ? "update" : "insert" ) \
                  << " sequence \"" \
                  << sequence->second->getName() \
                  << "\"." );
            }
         }
      }
      SequenceGeneratorQuery->Refresh();     
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::GenerateTestTestCaseBtnClick(TObject *Sender)
{
   std::vector< int > scenarios;
   
   generateTransaction( scenarios );
}
//---------------------------------------------------------------------------

const unsigned __fastcall TMainForm::countTransactionsInIteration( const char * project, const int & iteration )
{
   unsigned count = 0;

   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "COUNT(*) AS COUNT "
         "FROM "
            "TRANSACTION_SPECIFICATION "
         "WHERE "
            "PROJECT_CODE=\'%s\' AND "
            "ITERATION=%d",
         project,
         iteration );
      query->SQL->Text = sqlStatement;
      query->Open();

      count = ( !query->Eof ? query->FieldByName( "COUNT" )->AsInteger : 0 );
   }
   __finally
   {
      delete query;
      query = 0;
   }

   return ( count );
}
//---------------------------------------------------------------------------

const unsigned __fastcall TMainForm::countTransactionsInScenario( const int & scenario )
{
   unsigned count = 0;

   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "COUNT(*) AS COUNT "
         "FROM "
            "TRANSACTION_SPECIFICATION "
         "WHERE "
            "TESTSCENARIO_NO=%d",
         scenario );
      query->SQL->Text = sqlStatement;
      query->Open();

      count = ( !query->Eof ? query->FieldByName( "COUNT" )->AsInteger : 0 );
   }
   __finally
   {
      delete query;
      query = 0;
   }

   return ( count );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::applyTemplatesToNewTransaction(
                                const int &                 transaction,
                        const TestScenarioTemplate *  all )
{
   TADOQuery * query = 0;
   AnsiString sqlStatement;
    try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;


      sqlStatement.sprintf(
         "SELECT "
            "XPATH,"
            "FIELDVALUE, "
            "DISPLAYABLE "
         "FROM "
            "TXNSPEC_VALUES "
         "WHERE "
            "TXNSPEC_NO=%d ",
         transaction );
      query->SQL->Text = sqlStatement;
      query->Open();    
        std::string  xpath;
      std::string value;
      unsigned matchCount = 0;

      AnsiString fieldValue;
      while ( !query->Eof )
      {
         xpath = query->FieldByName( "XPATH" )->AsString.c_str();
         fieldValue = query->FieldByName( "FIELDVALUE" )->AsString;

         matchCount = ( all ? all->findMatch( value, xpath ) : 0 );
         if ( matchCount == 1 )
         {
            query->Edit();
            query->FieldByName( "FIELDVALUE" )->AsString = value.c_str();
             query->FieldByName( "DISPLAYABLE" )->AsString = "Y";
            query->Post();
         }
         else if ( matchCount > 1 )
         {
            MTHROW( std::runtime_error, \
               "Ambigious transaction template.  " \
               << matchCount \
               << " matches found for \"" \
               << xpath \
               << "\"." );
         }
         
         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }

   try
   {    
        // hack to remove payment methods and payment values parents as they cause a generation problem.
        query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;
        sqlStatement.sprintf(
        "DELETE FROM "
            "TXNSPEC_VALUES "
        "WHERE "
            "TXNSPEC_NO=%d "
        "AND "
            "DISPLAY_FIELDNAME IN (\'paymentMethod\',\'paymentValue\') ",
        transaction );
        query->SQL->Text = sqlStatement;
        query->ExecSQL();
   }
   __finally
   {
       delete query;
       query = 0;
   }
 
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::applyTemplatesToTransaction(
                        ProgressBar &              progressBar,
                        const int &                transaction,
                        const TestScenarioTemplate *  testScenario,
                        const TestScenarioTemplate *  all )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "XPATH,"
            "FIELDVALUE, "
            "DISPLAYABLE "
         "FROM "
            "TXNSPEC_VALUES "
         "WHERE "
            "TXNSPEC_NO=%d AND "
            "USER_SUPPLIED=\'N\' AND "
            "CHILD_COUNT=0",
         transaction );
      query->SQL->Text = sqlStatement;
      query->Open();

      std::string xpath;
      std::string value;
      unsigned matchCount = 0;

      AnsiString fieldValue;
      while ( !query->Eof )
      {
         xpath = query->FieldByName( "XPATH" )->AsString.c_str();
         fieldValue = query->FieldByName( "FIELDVALUE" )->AsString;
         matchCount = ( testScenario ? testScenario->findMatch( value, xpath ) : 0 );

         if ( matchCount == 1 )
         {
            query->Edit();
            query->FieldByName( "FIELDVALUE" )->AsString = value.c_str();
            query->FieldByName( "DISPLAYABLE" )->AsString = "Y";
            query->Post();
         }
         else if ( matchCount > 1 )
         {
            MTHROW( std::runtime_error, \
               "Ambigious scenario transaction template.  " \
               << matchCount \
               << " matches found for \"" \
               << xpath \
               << "\"." );
         }
         else
         {
            matchCount = ( all ? all->findMatch( value, xpath ) : 0 );
            if ( matchCount == 1 )
            {
               query->Edit();
               query->FieldByName( "FIELDVALUE" )->AsString = value.c_str();
                query->FieldByName( "DISPLAYABLE" )->AsString = "Y";
               query->Post();
            }
            else if ( matchCount > 1 )
            {
               MTHROW( std::runtime_error, \
                  "Ambigious transaction template.  " \
                  << matchCount \
                  << " matches found for \"" \
                  << xpath \
                  << "\"." );
            }
         }

         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}

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

void __fastcall TMainForm::applyTemplatesToScenario( ProgressBar & progressBar, const int & scenario )
{
   /**
    * Iterate through the collection of transactions defined for this scenario
    * and for each field attempt to apply every field template defined.  When
    * multiple fields match, raise an exception and roll any template
    * applications back.
    */
   TestScenarioTemplate *  testScenario   = m_transactionTemplates.findTestScenarioTemplate( scenario );
   TestScenarioTemplate *  all            = m_transactionTemplates.findTestScenarioTemplate( 0 );

   if ( testScenario || all )
   {
      TADOQuery * query = 0;
      try
      {
         query = new TADOQuery( this );
         query->Connection = Data_Module->IntegrationDBConnection;

         AnsiString sqlStatement;
         sqlStatement.sprintf(
            "SELECT "
               "TXNSPEC_NO,"
               "NAME "
            "FROM "
               "TRANSACTION_SPECIFICATION,"
               "MASS_TXNS "
            "WHERE "
               "TESTSCENARIO_NO=%d AND "
               "TRANSACTION_SPECIFICATION.PROJECT_CODE = MASS_TXNS.PROJECTCODE AND "
               "TRANSACTION_SPECIFICATION.ITERATION = MASS_TXNS.ITERATION AND "
               "TRANSACTION_SPECIFICATION.UDTYPE = MASS_TXNS.UDTYPE AND "
               "TRANSACTION_SPECIFICATION.UDSUBTYPE = MASS_TXNS.UDSUBTYPE "
            "ORDER BY "
               "TESTSCENARIO_NO,"
               "TXNSPEC_NO",
            scenario );
         query->SQL->Text = sqlStatement;
         query->Open();

         AnsiString message;
         while ( !query->Eof )
         {
            message.sprintf(
               " Applying template to %s ...",
               query->FieldByName( "NAME" )->AsString.c_str() );
            MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
            Application->ProcessMessages();

            applyTemplatesToTransaction(
               progressBar,
               query->FieldByName( "TXNSPEC_NO" )->AsInteger,
               testScenario,
               all );
            progressBar.increment();
            query->Next();
         }
      }
      __finally
      {
         delete query;
         query = 0;

         MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "";
      }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ApplyTemplatesToScenarioClick(TObject *Sender)
{
   // The scenario, our context, is kept in the tag of our parent menu.
   TPopupMenu * menu
      = dynamic_cast< TPopupMenu * >(
         dynamic_cast< TMenuItem * >( Sender )->GetParentMenu() );
   if ( menu )
   {
      const int scenario = menu->Tag;
      try
      {
         const TCursor Save_Cursor = Screen->Cursor;
         try
         {
            Screen->Cursor = crHourGlass;

            const unsigned count = countTransactionsInScenario( scenario );
            m_progressBar->open( count * 2 );
            buildTransactionsForScenario(
               m_transactionCache,
               *m_progressBar,
               scenario,
               m_schema_handle,
               m_currentiteration );

            try
            {
               Data_Module->IntegrationDBConnection->BeginTrans();
               applyTemplatesToScenario( *m_progressBar, scenario );
               Data_Module->IntegrationDBConnection->CommitTrans();
            }
            catch ( ... )
            {
               Data_Module->IntegrationDBConnection->RollbackTrans();
               throw;
            }
            m_progressBar->update( count );
         }
         __finally
         {
            m_progressBar->close();
            Screen->Cursor = Save_Cursor;
         }
      }
      catch ( const std::exception & exception )
      {
         MessageDlg(
            exception.what(),
            mtError, TMsgDlgButtons() << mbOK, 0 );
      }
      catch ( ... )
      {
         MessageDlg(
            "Unknown exception applying templates to this scenario.",
            mtError, TMsgDlgButtons() << mbOK, 0 );
      }
   }
}



string __fastcall TMainForm::FindField(const string &structure_handle, int fieldtag)
{
   string                  field_path;
   vector<string>          structure_attributes;
   vector<string>::iterator   s_itr;

   XMLSchema->GetAttributes(structure_handle, structure_attributes);

    s_itr = structure_attributes.begin();
    while (s_itr != structure_attributes.end())
    {
        string   elementtype;
        string datatype;

        XMLSchema->GetAttributeProperty((*s_itr), "type", elementtype);

        if (elementtype == "field")
        {
            XMLSchema->GetAttributeProperty((*s_itr), "datatype", datatype);

            if (datatype == "Struct")
            {
               field_path = FindField((*s_itr), fieldtag);

                if (!field_path.empty())
                {
                  break;
                }
            }
            else
            {
                string  xml_fieldtag;
                XMLSchema->GetAttributeProperty((*s_itr), "tag", xml_fieldtag);

                if ( fieldtag == atoi(xml_fieldtag.c_str()) )
                {
                    field_path = (*s_itr);
                    break;
                }
            }
        }
        else
        if (elementtype == "repeat")
        {
            string   repeatname;
            XMLSchema->GetAttributeProperty((*s_itr), "name", repeatname);

            string      repeatAttribute = (*s_itr)+".1";

            field_path = FindField(repeatAttribute, fieldtag);

            if (!field_path.empty())
            {
                break;
            }
        }

        s_itr++;
    }

    return field_path;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FieldEnumValuesDblClick(TObject *Sender)
{
   TADOQuery * query = 0;

   if ( TransactionStructurePageControl->ActivePage == PayloadStructureTabSheet )
   {
      query = TxnValuesQuery;
   }
   else if ( TransactionStructurePageControl->ActivePage == HeaderStructureTabSheet )
   {
      query = TxnHeaderValuesQuery;
   }


   if ( query )
   {
      if ( query->State != dsEdit )
      {
         query->Edit();
      }

      query->FieldByName( "FIELDVALUE" )->AsString = FieldEnumValues->Items->Strings[ FieldEnumValues->ItemIndex ];
   }
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action)
{
   XMLSchema->Active = false;

   if( m_Registry != 0 ) m_Registry->CloseKey();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::SetGenerationDirectoryClick(TObject *Sender)
{
   AnsiString  directory;

   if ( SelectDirectory("Select Generation Directory", "c:\\", directory) )
    {
        if (m_Registry != NULL)
        {
            m_Registry->WriteString("MRUGenerationDir", directory);
        }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseGridRowChanging(TObject *Sender,
     int OldRow, int NewRow, bool &Allow)
{
   TCursor Save_Cursor = Screen->Cursor;
   Screen->Cursor = crHourGlass;    // Show hourglass cursor

   try
   {
   
      TxnStepsQuery->Close(); 

      if ( (m_currentproject.Length() > 0) && (m_currentiteration != 0) )
      {
         TestCaseTreeView->Items->BeginUpdate();

         TestCaseTreeView->Items->Clear();


         TADOQuery   *query = new TADOQuery(this);
         query->Connection = Data_Module->IntegrationDBConnection;

         m_currenttestcaseid = TestCaseQuery->FieldByName("TESTCASE_ID")->AsString;            
         m_currentcaserepeat = TestCaseQuery->FieldByName("CASE_REPEAT")->AsInteger;
         m_currentcasedelay = TestCaseQuery->FieldByName("REPEAT_DELAY")->AsInteger;
         
         AnsiString  sql_statement;          
         sql_statement.sprintf("SELECT * FROM TEST_SCENARIOS "
                               "WHERE PROJECT_CODE='%s' AND ITERATION=%d "
                               "AND   TESTCASE_ID='%s' "
                               "ORDER BY TESTCASE_SEQNO",
                               m_currentproject.c_str(),
                               m_currentiteration,
                               m_currenttestcaseid.c_str());

         query->SQL->Text = sql_statement;
         query->Open();

         int count = 0;
         while (!query->Eof)
         {
            AnsiString  testcase_desc;

            testcase_desc.sprintf("(%d) %s",
                             query->FieldByName("TESTCASE_SEQNO")->AsInteger,
                             query->FieldByName("NAME")->AsString.c_str()
                             );

            int   testscenario_no = query->FieldByName("TESTSCENARIO_NO")->AsInteger;

            TTreeNode *testcase_node = TestCaseTreeView->Items->AddObject(NULL, testcase_desc, (void *)testscenario_no);
            LoadTestCaseNodes(testcase_node);

            ++count;
            query->Next();
         }
         
         GenerateTestTestCaseBtn->Caption = "Generate Test Case: " + m_currenttestcaseid;
         GenerateTestTestCaseBtn->Enabled = ( count > 0 );

         delete query;

         TestCaseTreeView->Items->EndUpdate();
         TestCaseTreeView->FullExpand();
         
         /* also refresh the Test Steps tab */
         TxnStepsQuery->SQL->Text = sql_statement;
         TxnStepsQuery->Open();

        }
    }
   __finally
    {
       Screen->Cursor = Save_Cursor;
    }

    Allow = true;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseQueryAfterClose(TDataSet *DataSet)
{
   TestScenarioToolBar->Enabled = false;
    AddTestCaseNode->Enabled = false;
// InitTxnBtn->Enabled = false;
// GenerateAllTxnsBtn->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseQueryAfterOpen(TDataSet *DataSet)
{
   TestScenarioToolBar->Enabled = true;

   AddTestCaseNode->Enabled = true;
// InitTxnBtn->Enabled = true;
// GenerateAllTxnsBtn->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::SequenceGeneratorQueryAfterInsert(
      TDataSet *DataSet)
{
    DataSet->FieldByName("PROJECT_CODE")->AsString = m_currentproject;
    DataSet->FieldByName("ITERATION")->AsInteger = m_currentiteration;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseQueryBeforePost(TDataSet *DataSet)
{
   DataSet->FieldByName("USECASE_ID")->AsString = DataSet->FieldByName("TESTCASE_ID")->AsString;
   if( DataSet->FieldByName("CASE_REPEAT")->AsInteger < 1) DataSet->FieldByName("CASE_REPEAT")->AsInteger = 1;
   if( DataSet->FieldByName("REPEAT_DELAY")->AsInteger > 3600) DataSet->FieldByName("REPEAT_DELAY")->AsInteger = 3600;
   if( DataSet->FieldByName("BATCH_SIZE")->AsInteger < 1) DataSet->FieldByName("BATCH_SIZE")->AsInteger = 99;
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::TxnStepsQueryBeforeClose(TDataSet *DataSet)
{
    if (DataSet->State == dsEdit )
   {
       DataSet->FieldByName("TESTCASE_ID")->AsString = m_currenttestcaseid;
       //DataSet->FieldByName("USECASE")->AsString = m_currenttestcaseid;
       //DataSet->FieldByName("PROJECT_CODE")->AsString = m_currentproject;
       //DataSet->FieldByName("ITERATION")->AsInteger = m_currentiteration;
       if( DataSet->FieldByName("REPEAT_COUNT")->AsInteger < 1) DataSet->FieldByName("REPEAT_COUNT")->AsInteger = 1;
       DataSet->Post();
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewEditing(TObject *Sender,
      TTreeNode *Node, bool &AllowEdit)
{
    if (Node->Level == 0)
    {
      AllowEdit = true;
    }
    else
    {
        AllowEdit = false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewEdited(TObject *Sender,
     TTreeNode *Node, AnsiString &S)
{
   // We've enable editing of the root level only, but we'll check anyway.
   if (Node->Level == 0)
   {
      const int   testscenario_no = (int)(Node->Data);
      TADOQuery * query           = 0;

      try
        {
            query = new TADOQuery( this );
         query->Connection = Data_Module->IntegrationDBConnection;

            AnsiString  sql_statement;
            AnsiString  name;
            sql_statement.sprintf(
                "UPDATE TEST_SCENARIOS SET NAME='%s' WHERE TESTSCENARIO_NO=%d",
            Utilities::EscapeString( getNameFromNode( name, S ) ).c_str(),
                testscenario_no );
            query->SQL->Text = sql_statement;

            Data_Module->IntegrationDBConnection->BeginTrans();
            try
            {
                query->ExecSQL();
                Data_Module->IntegrationDBConnection->CommitTrans();
            }
            catch ( ... )
            {
                Data_Module->IntegrationDBConnection->RollbackTrans();
            }
        }
        __finally
        {
            delete query;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestScenarioPropertiesClick(TObject *Sender)
{
   TestScenarioPropertiesForm->ShowForm( m_testscenario_no );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TestCaseTreeViewContextPopup(TObject *Sender,
     TPoint &MousePos, bool &Handled)
{
   TTreeView * view = dynamic_cast< TTreeView * >( Sender );
   if ( view )
   {
      TTreeNode *    Node  = view->GetNodeAt( MousePos.x, MousePos.y );
      const TPoint   screen   = TestCaseTreeView->ClientToScreen( MousePos );

      if ( Node )
      {
         switch ( Node->Level )
         {
         case 0:
            // Rebuild the transaction templates, they may have changed.
            buildTransactionTemplates(
               m_transactionTemplates,
               m_currentproject,
               m_currentiteration );

            ApplyTemplatesToScenario->Enabled = (
               m_transactionTemplates.haveTemplatesForScenario(
                  reinterpret_cast< int >( Node->Data ) ) );

            ScenarioPopupMenu->Tag = reinterpret_cast< int >( Node->Data );
            ScenarioPopupMenu->Popup( screen.x, screen.y );
            break;
         case 1:
            TransactionPopupMenu->Popup( screen.x, screen.y );
            break;
         }
      }
   }
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::DeleteScenarioChildren(int testscenario_no)
{
   bool refresh_testcases = false;
   TADOQuery   *query = new TADOQuery(this);
   AnsiString  sql_statement;
   query->Connection = Data_Module->IntegrationDBConnection;

   try
   {
      Data_Module->IntegrationDBConnection->BeginTrans();

      sql_statement.sprintf(
         "DELETE FROM TXNSPEC_VALUES WHERE TESTSCENARIO_NO=%d",
         testscenario_no );

      query->SQL->Text = sql_statement;
      query->ExecSQL();

      sql_statement="";
      sql_statement.sprintf(
         "DELETE FROM TRANSACTION_SPECIFICATION WHERE TESTSCENARIO_NO=%d",
         testscenario_no );

      query->SQL->Text = sql_statement;
      query->ExecSQL();

      sql_statement="";
      sql_statement.sprintf(
         "DELETE FROM ITERATION_PARAMS WHERE TESTSCENARIO_NO=%d",
         testscenario_no );

      query->SQL->Text = sql_statement;
      query->ExecSQL();

      //sql_statement="";
      //sql_statement.sprintf(
      // "DELETE FROM TEST_SCENARIOS WHERE TESTSCENARIO_NO=%d",
      // testscenario_no );

      //query->SQL->Text = sql_statement;
      //query->ExecSQL();

      Data_Module->IntegrationDBConnection->CommitTrans();

      //refresh_testcases = true;

      //ResequenceTestCases(current_node);
   }
   catch(...)
   {
      Data_Module->IntegrationDBConnection->RollbackTrans();
   }

   delete query;
 
/*
   if (refresh_testcases)
   {
      bool allow;
      TestCaseGridRowChanging(Sender, 0, 1, allow = true);
   }
*/
    }
//---------------------------------------------------------------------------


void __fastcall TMainForm::DeleteScenarioClick(TObject *Sender)
{
   bool refresh_testcases = false;

   for ( unsigned selected_item=0;
        selected_item<TestCaseTreeView->SelectionCount;
        selected_item++ )
   {
      TTreeNode * current_node = TestCaseTreeView->Selections[ selected_item ];
      if ( current_node != NULL )
      {
         if (current_node->Level == 0) // Remove Test Scenario
         {
            // Confirm deletion
            AnsiString  message;
            message.sprintf( "Are you sure you want to delete test scenario '%s'?", current_node->Text );

            if ( MessageDlg( message, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0 ) == mrYes )
            {
               int   testscenario_no = (int)(current_node->Data);

               TADOQuery   *query = new TADOQuery(this);
               AnsiString  sql_statement;
               query->Connection = Data_Module->IntegrationDBConnection;

               try
               {
                  Data_Module->IntegrationDBConnection->BeginTrans();

                  sql_statement.sprintf(
                     "DELETE FROM TXNSPEC_VALUES WHERE TESTSCENARIO_NO=%d",
                     testscenario_no );

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  sql_statement="";
                  sql_statement.sprintf(
                     "DELETE FROM TRANSACTION_SPECIFICATION WHERE TESTSCENARIO_NO=%d",
                     testscenario_no );

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  sql_statement="";
                  sql_statement.sprintf(
                     "DELETE FROM ITERATION_PARAMS WHERE TESTSCENARIO_NO=%d",
                     testscenario_no );

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  sql_statement="";
                  sql_statement.sprintf(
                     "DELETE FROM TEST_SCENARIOS WHERE TESTSCENARIO_NO=%d",
                     testscenario_no );

                  query->SQL->Text = sql_statement;
                  query->ExecSQL();

                  Data_Module->IntegrationDBConnection->CommitTrans();

                  refresh_testcases = true;

                  ResequenceTestCases(current_node);
               }
               catch(...)
               {
                  Data_Module->IntegrationDBConnection->RollbackTrans();
               }

               delete query;
            }
         }
      }
   }

   if (refresh_testcases)
   {
      bool allow;
      TestCaseGridRowChanging(Sender, 0, 1, allow = true);
   }
}

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

void __fastcall TMainForm::TransactionValueGrid1BeforeContractNode(
     TObject *Sender, int ARow, int ARowReal, bool &Allow)
{
   Allow = ( TransactionValueGrid->RealRow <= ARowReal );
}
//---------------------------------------------------------------------------

const bool __fastcall TMainForm::isParent( const int & ordinal )
{
   return ( std::find(
            m_parents.begin(),
            m_parents.end(),
            ordinal ) != m_parents.end() );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TransactionValueGridCanEditCell(TObject *Sender,
     int ARow, int ACol, bool &CanEdit)
{
#if INCLUDE_PARENTS
   /**
    *  Use the real row as the ordinal number into the dataset.  When the row
    *  has children, it cannot be edited, otherwise it can.
    */
   CanEdit = !isParent( TransactionValueGrid->RealRowIndex( ARow ) );
#endif
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TransactionValueGridGetDisplText(
     TObject *Sender, int ACol, int ARow, AnsiString &Value)
{
#if INCLUDE_PARENTS
   const int row = TransactionValueGrid->RealRowIndex( ARow );
   if ( row > 0 )
   {
      switch ( TransactionValueGrid->RealColIndex( ACol ) )
      {
      case 2:  // The value column.
         /**
          * Use the real row as the ordinal number into the dataset.  When
          * the row has children, it cannot be edited, otherwise it can.
          */
         if ( isParent( row ) )
         {
            Value = "{...}";
         }
         break;
      case 3:  // The checkbox column.
         if ( isParent( row ) )
         {
            Value = "";
         }
         break;
      }
   }
#endif
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TransactionGridRowChanging( TADOQuery & query, const char * structureName )
{
   TxnFieldComments->Lines->Clear();
   FieldEnumValues->Clear();
   FieldDatatype->Clear();
   DocDataType->Clear();
   IncludedInMac->Checked = false;

   if ( query.State != dsInactive && query.RecordCount )
   {
      if (!m_schema_handle.empty())
      {
         const int   fieldtag = query.FieldByName("FIELDTAG")->AsInteger;
         string      structure_handle;

         try
         {
            XMLSchema->Create(m_schema_handle.c_str(), structureName, m_currentiteration, structure_handle, NULL);

            string   field_path = FindField(structure_handle, fieldtag);

            if (!field_path.empty())
            {
               std::string fieldcomments;
               std::string datatype;
               std::string docdatatype;
               std::string includedInMac;

               XMLSchema->GetAttributeProperty(field_path, "comments", fieldcomments);
               TxnFieldComments->Lines->Add(fieldcomments.c_str());

               XMLSchema->GetAttributeProperty(field_path, "datatype", datatype);
               FieldDatatype->Text = datatype.c_str();

               XMLSchema->GetAttributeProperty(field_path, "docdatatype", docdatatype );
               DocDataType->Text = docdatatype.c_str();

               XMLSchema->GetAttributeProperty(field_path, "inMac", includedInMac );
               IncludedInMac->Checked = ( includedInMac == "true" );

               string valuemap;

               XMLSchema->GetAttributeProperty(field_path, "valuemap", valuemap);

               if (!valuemap.empty())
               {
                  vector<string>          enum_values;
                  if (XMLSchema->GetEnumerationValues(m_schema_handle, valuemap.c_str(), enum_values))
                  {
                     vector<string>::iterator   eitr = enum_values.begin();
                     while (eitr != enum_values.end())
                     {
                        FieldEnumValues->AddItem( (*eitr).c_str(), NULL);

                        ++eitr;
                     }
                  }
               }
            }
         }
         __finally
         {
            XMLSchema->Destroy( structure_handle );
         }
      }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TransactionValueGridRowChanging(TObject *Sender,
     int OldRow, int NewRow, bool &Allow)
{
   TransactionGridRowChanging( *TxnValuesQuery, m_structure_name.c_str() );
}

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

void __fastcall TMainForm::HeaderStructureGridRowChanging(TObject *Sender,
     int OldRow, int NewRow, bool &Allow)
{
   TransactionGridRowChanging( *TxnHeaderValuesQuery, g_headerStructure );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::HeaderStructureTabSheetShow(TObject *Sender)
{
   TransactionGridRowChanging( *TxnHeaderValuesQuery, g_headerStructure );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::PayloadStructureTabSheetShow(TObject *Sender)
{
   TransactionGridRowChanging( *TxnValuesQuery, m_structure_name.c_str() );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::MainStatusBarResize(TObject *Sender)
{
   if ( m_progressBar )
   {
      RECT Rect;
      MainStatusBar->Perform( SB_GETRECT, 0, (LPARAM)&Rect );

      const int progressPanel = 1;
      int offset = 0;
      for ( int i = 0; i < progressPanel; i++ )
      {
         offset += MainStatusBar->Panels->Items[ i ]->Width;
      }

      m_progressBar->resize(
         Rect.top,
         Rect.left + offset,
         MainStatusBar->Panels->Items[ progressPanel ]->Width,
         Rect.bottom - Rect.top );
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TransactionValueGridKeyDown(TObject *Sender,
      WORD &Key, TShiftState Shift)
{
   if ( Key == 'F' )
   {
      TShiftState mask;
      mask << ssCtrl;

      if ( Shift * mask == mask )
      {
         TransactionValueGridFindDialog->Execute();
      }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::HeaderStructureGridKeyDown(TObject *Sender,
      WORD &Key, TShiftState Shift)
{
   if ( Key == 'F' )
   {
      TShiftState mask;
      mask << ssCtrl;

      if ( Shift * mask == mask )
      {
         HeaderStructureGridFindDialog->Execute();
      }
   }
}

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

void __fastcall TMainForm::ImportTransactionActionExecute(TObject *Sender)
{
   TTreeNode * currentNode = TestCaseTreeView->Selected;

   if ( currentNode )
   {
      // Are we importing a scenario, or a single transaction?
      if ( currentNode->Level == 0 )
      {
         const int testScenarioNumber
            = reinterpret_cast< int >( currentNode->Data );
      }
   }
}
//---------------------------------------------------------------------------





void __fastcall TMainForm::buildExecutionSchedule( TransactionSpecification & transactionSpecification )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "XPATH,"
            "FIELDVALUE "
         "FROM "
            "TXNSPEC_VALUES "
         "WHERE "
            "TXNSPEC_NO=%d AND "
            "FIELDVALUE IS NOT NULL AND "
            "OBSOLETE=\'N\' "
         "ORDER BY "
            "ORDINAL",
         transactionSpecification.getTransactionSpecificationNumber() );
      query->SQL->Text = sqlStatement;
      query->Open();

      TransactionSpecificationValue * value = 0;
      while ( !query->Eof )
      {
         value = &transactionSpecification.getTransactionField(
            query->FieldByName( "XPATH" )->AsString.c_str() );

         value->setExpression( query->FieldByName( "FIELDVALUE" )->AsString.c_str() );

         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildExecutionSchedule( TestScenario & testScenario )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "TRANSACTION_SPECIFICATION.TXNSPEC_NO AS TXNSPEC_NO,"
            "TRANSACTION_SPECIFICATION.UDTYPE AS UDTYPE,"
            "TRANSACTION_SPECIFICATION.UDSUBTYPE AS UDSUBTYPE,"
            "MASS_TXNS.NAME AS NAME "
         "FROM "
            "TRANSACTION_SPECIFICATION,"
            "MASS_TXNS "
         "WHERE "
            "TESTSCENARIO_NO=%d AND "
            "TRANSACTION_SPECIFICATION.PROJECT_CODE = MASS_TXNS.PROJECTCODE AND "
            "TRANSACTION_SPECIFICATION.ITERATION = MASS_TXNS.ITERATION AND "
            "TRANSACTION_SPECIFICATION.UDTYPE = MASS_TXNS.UDTYPE AND "
            "TRANSACTION_SPECIFICATION.UDSUBTYPE = MASS_TXNS.UDSUBTYPE "
         "ORDER BY "
            "SEQ_NO",
         testScenario.getScenarioNumber() );
      query->SQL->Text = sqlStatement;
      query->Open();

      TransactionSpecification * transaction = 0;
      while ( !query->Eof )
      {
         transaction = &testScenario.getTransactionSpecification(
               query->FieldByName( "TXNSPEC_NO" )->AsInteger,
               query->FieldByName( "NAME" )->AsString.c_str() );
         transaction->setUdType(
            query->FieldByName( "UDTYPE" )->AsInteger );
         transaction->setUdSubtype(
            query->FieldByName( "UDSUBTYPE" )->AsInteger );

         buildExecutionSchedule( *transaction );

         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::buildExecutionSchedule(
               Iteration &       iteration,
               const std::string &  testcaseId )
{
   TADOQuery * query = 0;
   try
   {
      query = new TADOQuery( this );
      query->Connection = Data_Module->IntegrationDBConnection;

      AnsiString sqlStatement;
      sqlStatement.sprintf(
         "SELECT "
            "TESTSCENARIO_NO,"
            "REPEAT_COUNT,"
            "BATCH_SIZE,"
            "NAME "
         "FROM "
            "TEST_SCENARIOS "
         "WHERE "
            "TESTCASE_ID=\'%s\' AND "
            "PROJECT_CODE=\'%s\' AND "
            "ITERATION=%d "
         "ORDER BY "
            "TESTCASE_SEQNO",
         Utilities::EscapeString( testcaseId ).c_str(),
         Utilities::EscapeString( iteration.getProjectCode() ).c_str(),
         iteration.getIterationId() );
      query->SQL->Text = sqlStatement;
      query->Open();

      TestScenario * scenario = 0;
      while ( !query->Eof )
      {
         scenario = &iteration.getTestScenario(
            query->FieldByName( "TESTSCENARIO_NO" )->AsInteger );
         /*
         scenario->setBatchSize( 
            !query->FieldByName( "BATCH_SIZE" )->IsNull
               ? query->FieldByName( "BATCH_SIZE" )->AsInteger
               : 0 );
         */
         scenario->setBatchSize( 99 );
         scenario->setRepeatCount(
            !query->FieldByName( "REPEAT_COUNT" )->IsNull
               ? query->FieldByName( "REPEAT_COUNT" )->AsInteger
               : 1 );
         scenario->setScenarioName(
            query->FieldByName( "NAME" )->AsString.c_str() );

         buildExecutionSchedule( *scenario );

         query->Next();
      }
   }
   __finally
   {
      delete query;
      query = 0;
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::generateTransaction( std::vector< int > & scenarios )
{
//    GenerationPropertiesForm->Visible = true;
//    GenerationPropertiesForm->SendToBack();
   if ( GenerationPropertiesForm->ShowModal() == mrOk )
   {
      const bool           generateHeaders   = GenerationPropertiesForm->GenerateHeadersCheckBox->Checked;
      const std::string    folder         = GenerationPropertiesForm->GenerationFolderDirectoryEdit->Text.c_str();
      const std::string    batchPrefix    = GenerationPropertiesForm->DrainFilePrefixEdit->Text.c_str();
      const std::string    batchSuffix    = GenerationPropertiesForm->DrainFileSuffixEdit->Text.c_str();
      //const bool           buildManifest  = GenerationPropertiesForm->BuildManifestCheckBox->Checked;
      //const std::string    manifestPrefix = GenerationPropertiesForm->ManifestPrefixEdit->Text.c_str();
      //const std::string    manifestSuffix = GenerationPropertiesForm->ManifestSuffixEdit->Text.c_str();
      const std::string    securityServer = GenerationPropertiesForm->SecurityServerPipeEdit->Text.c_str();
      const unsigned short keyNumber      = GenerationPropertiesForm->KeyNumberEdit->Text.ToInt();
      const unsigned short keyVersion     = GenerationPropertiesForm->KeyVersionEdit->Text.ToInt();
      const std::string    pathmapTarget  = GenerationPropertiesForm->PathmapTargetEdit->Text.c_str();
      const int            macAlgorithm   = GenerationPropertiesForm->MacAlgorithmComboBox->ItemIndex;
         
      GenerationPropertiesForm->Visible = false;
      
      AnsiString testCase = TestCaseQuery->FieldByName( "TESTCASE_ID" )->AsString;
      const std::string    manifestPrefix =  testCase.c_str(); 
      const std::string    manifestSuffix = ".txt";
      const bool           buildManifest = true;  
           
        
      /**
         Create a transaction stream into our generation folder, and generate
         the transactions into it.  We need to know whether we have to prepend
         header (i.e., whether it is a .xdr which has a header, or a .devud which
         doesn't).
       */

      const TCursor           Save_Cursor             = Screen->Cursor;
      bool                 transactionOpen            = false;
      ICryptographicServerProxy *   cryptographicServerProxy   = 0;
      IMessageDigest *        messageDigest           = 0;
      IHash *                 hash                 = 0;

      AnsiString message;
      
      try
      {
         // firstly prepare for crypto MAC
         if ( m_securityWrapperFactory )
         {
            cryptographicServerProxy = m_securityWrapperFactory
               ->createCryptographicServerProxy( securityServer.c_str() );
            if ( cryptographicServerProxy )
            {
               if ( cryptographicServerProxy->getModuleCount() )
               {
                  /**
                   * We don't know which module will be used to compute the
                   * MAC (security doesn't tell us), so until they do we
                   * assume its the first module.
                   */
                  const unsigned int serialNumber =
                  cryptographicServerProxy->getSerialNumber( 0 );

                  /**
                     We now need to turn the 4-byte serial number into an
                     8-byte diversifier.  Apparently, we must do this by
                     writing the serial number into the lower 4-bytes in big
                     endian.  An API is being added to crypto to do this:
                     until it is there we need to do it ourselves.
                   */
                  unsigned char buffer[ 8 ];

                  buffer[ 0 ] = 0;
                  buffer[ 1 ] = 0;
                  buffer[ 2 ] = 0;
                  buffer[ 3 ] = 0;
                  buffer[ 4 ] = ( serialNumber >> 24 ) & 0xFF;
                  buffer[ 5 ] = ( serialNumber >> 16 ) & 0xFF;
                  buffer[ 6 ] = ( serialNumber >>  8 ) & 0xFF;
                  buffer[ 7 ] = ( serialNumber       ) & 0xFF;

                  messageDigest = m_securityWrapperFactory
                     ->createMessageDigest(
                        *cryptographicServerProxy,
                        keyNumber,
                        keyVersion,
                        buffer,
                        sizeof( buffer ) );
                  /**
                   * If we need to compute the MAC by computing the MAC
                   * of the SHA-1 hash, then we create the hash object
                   * here.
                   */
                  if ( macAlgorithm == 1 )
                  {
                     hash = m_securityWrapperFactory->createHash();
                  }
               }
               else
               {
                  MWARNING( "Cryptographic server has no modules." );
               }
            }
         }

         Screen->Cursor = crHourGlass;
         Data_Module->IntegrationDBConnection->BeginTrans();
         transactionOpen = true;

         TransactionStream stream(folder, batchPrefix, batchSuffix, buildManifest,
                                  manifestPrefix, manifestSuffix, pathmapTarget );
         Iteration iteration( m_currentproject.c_str(), m_currentiteration,
                             *XMLSchema->GetSchemaWrapperFactory(),
                             *XMLSchema->GetSchema(), m_schema_handle );
         DefinedVariableTable definedVariableTable;
         SequenceCollection      sequences;
         TimeEstimate         timeEstimate( *MainStatusBar->Panels->Items[ 0 ] );
         EvaluationContext    context(definedVariableTable, sequences, *m_progressBar,
                                      messageDigest, hash, cryptographicServerProxy, timeEstimate );
         buildExecutionSchedule( iteration, testCase.c_str() );
         loadLegacyVariables( definedVariableTable, m_currentproject.c_str(), iteration );
         readSequences( sequences, m_currentproject.c_str(), m_currentiteration );
         iteration.setBatchSize (TestCaseQuery->FieldByName( "BATCH_SIZE" )->Text.ToInt());

         try
         {
            int      count    = 0;
            bool     generated   = false;
            time_t   startTime;

            if ( scenarios.empty() )
            {
               // generate for an entire test case
               // first setup the environment
               count = iteration.getTransactionCount();
               iteration.setTestCaseName (m_currenttestcaseid.c_str());
               iteration.setCaseRepeat (m_currentcaserepeat);
               iteration.setRepeatDelay (m_currentcasedelay);

               if (count > 0)
               {
                  // now preapre the log file   and progress bars
                  message = DateToStr(Date());
                  stream.logToManifest (message.c_str(), false);
                  message = "Generating for Test Case " + testCase
                                        + ". " +  TestCaseQuery->FieldByName( "NAME" )->AsString ;
                  stream.logToManifest (message.c_str(), false);
                  message.sprintf("Each run will create %d transactions with batch size of %d",count,iteration.getBatchSize());
                  stream.logToManifest (message.c_str(), false);
                  m_progressBar->open( count );
                  timeEstimate.start( count  );
   
                  // now run the testcase multiple times
                  generated = true;
                  for ( int repeat = 1; repeat <= m_currentcaserepeat && generated; ++repeat )
                  {
                     // first more logging and status bar info
                     stream.logToManifest (" ", false);
                     message.sprintf("run %d of %d started.",repeat,m_currentcaserepeat);
                     stream.logToManifest (message.c_str(), true);
                     message.sprintf("%s: run %d of %d in progress.  %d transactions with batch size of %d",
                                     m_currenttestcaseid.c_str(),repeat,m_currentcaserepeat,count, iteration.getBatchSize());
                     MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;  
                     Application->ProcessMessages();
                      
                     // now the real thing:  generate the test case 
                     startTime = time(NULL);                              
                     if (!iteration.generate( stream, generateHeaders, context ) )
                     {  
                        generated = false;
                        break;
                     }   
   
                     timeEstimate.stop();
                     m_progressBar->close();       
                     
                                
                     if (!generated)
                     {
                         // problems with the generation  ..  best we can do for now is report it in status bar and log
                         message.sprintf("run %d encountered a problem." ,repeat);
                         stream.logToManifest (message.c_str(), true);
                         message.sprintf("%s: run %d of %d encountered a problem." ,
                                             m_currenttestcaseid.c_str(),repeat, m_currentcaserepeat);
                         MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                         Application->ProcessMessages();
                     }
                     else
                     {  
                        // last run was good so check if we have to do it again
                        // but first update log
                        message.sprintf("run %d completed. Elapsed time for run was %d seconds" ,
                                        repeat, time(NULL) - startTime);
                        stream.logToManifest (message.c_str(), true);
   
                        if ( repeat < m_currentcaserepeat )
                        {
                           // do it again but possibly wait here before starting next session
                           for (int delayRepeat = m_currentcasedelay - (time(NULL) - startTime); delayRepeat > 0 ; --delayRepeat)
                           {                     
                              message.sprintf("%s: run %d of %d completed.  Pausing generation for %d seconds" ,
                                             m_currenttestcaseid.c_str(),repeat, m_currentcaserepeat, delayRepeat);
                              MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                              Application->ProcessMessages();
                              Sleep (1000);
                           } 
                        }
                        else
                        {
                              // all done
                              message.sprintf("%s: run %d of %d completed. " ,
                                             m_currenttestcaseid.c_str(),repeat, m_currentcaserepeat);
                              MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                              Application->ProcessMessages();               
                        }
   
                     } 
                  }                     
               }
               else
               {
                  MessageDlg( "No transactions to generate", mtWarning, TMsgDlgButtons() << mbOK, 0 );
               }                    
            } // end of test case generation
            else
            {
               // single test step generation
               // note code caters for a list of scenarios but the GUI should only deliver a list of 1
               std::string batchName;
               TestScenario * scenario = 0;

               std::vector< int >::const_iterator where = scenarios.begin();
               for ( where = scenarios.begin(); where != scenarios.end(); ++where )
               {
                  scenario = &iteration.findTestScenario( *where );
                  count += scenario->getTransactionCount();
               }
               if (count > 0)
               {
                  // now preapre the log file   and progress bars
                  message = DateToStr(Date());
                  stream.logToManifest (message.c_str(), false);
                  message = "Generating for a single Test Step " ;
                  stream.logToManifest (message.c_str(), false);
                  message.sprintf("The step will create %d transactions with batch size of %d",count,iteration.getBatchSize());
                  stream.logToManifest (message.c_str(), false);
                  m_progressBar->open( count );
                  timeEstimate.start( count );
   
                  generated = true;
                  for ( where = scenarios.begin(); where != scenarios.end(); ++where )
                  {
                    // first more logging and status bar info
                     stream.logToManifest (" ", false);
                     message.sprintf("test step started.");
                     stream.logToManifest (message.c_str(), true);
                     message.sprintf("test step generation in progress.  %d transactions with batch size of %d",
                                     count, iteration.getBatchSize());
                     MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                     Application->ProcessMessages();
   
                     // for test step we setup the filename here not in the iteration class which caters for test cases
                     scenario = &iteration.findTestScenario( *where );
                     batchName =  scenario->buildBatchName
                                         (batchName, scenario->getScenarioName() );
                     stream.newBatch(iteration.getBatchSize(),batchName);
   
                     // now the real thing:  generate the test step
                     startTime = time(NULL);
                     if ( !scenario->generate(
                           stream,
                           generateHeaders,
                           context ) )
                     {
                        generated = false;
                        // problems with the generation  ..  best we can do for now is report it in status bar and log
                        message.sprintf("test step encountered a problem.");
                        stream.logToManifest (message.c_str(), true);
                        message.sprintf("generation for test step encountered a problem." );
                        MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                        Application->ProcessMessages();
                        break;
                     }
                     else
                     {
                        // all done
                        message.sprintf("test step completed.  Elapsed time for run was %d seconds",time(NULL) - startTime);
                        stream.logToManifest (message.c_str(), true);
                        message.sprintf("generation for test step completed." );
                        MainStatusBar->Panels->Items[ g_messagePanel ]->Text = message;
                        Application->ProcessMessages();
                     }
                  }
               }
               else
               {
                  MessageDlg( "No transactions to generate", mtWarning, TMsgDlgButtons() << mbOK, 0 );
               }
            }

            // generation complete so just finish off and tidy up
            if ( generated )
            {
               writeSequences(
                  sequences,
                  m_currentproject.c_str(),
                  m_currentiteration );

               Data_Module->IntegrationDBConnection->CommitTrans();
               transactionOpen = false;
            }
         }
         __finally
         {
            timeEstimate.stop();
            m_progressBar->close();
         }
      }
      __finally
      {
         if ( hash )
         {
            m_securityWrapperFactory->destroyHash( *hash );
            hash = 0;
         }
         if ( messageDigest )
         {
            m_securityWrapperFactory
               ->destroyMessageDigest( *messageDigest );
            messageDigest = 0;
         }
         if ( cryptographicServerProxy )
         {
            m_securityWrapperFactory
               ->destroyCryptographicServerProxy( *cryptographicServerProxy );
            cryptographicServerProxy = 0;
         }

         if ( transactionOpen )
         {
            Data_Module->IntegrationDBConnection->RollbackTrans();
         }
         Screen->Cursor = Save_Cursor;
      }
   }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::GenerateActionExecute(TObject *Sender)
{
   TTreeNode *       currentNode = 0;
   std::vector< int >   scenarios;

   for ( unsigned selection=0;
        selection<TestCaseTreeView->SelectionCount;
        selection++ )
   {
      currentNode = TestCaseTreeView->Selections[ selection ];
      if ( currentNode )
      {
         scenarios.push_back( reinterpret_cast< int >( currentNode->Data ) );
      }
   }
   generateTransaction( scenarios );
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::UdTransferBtnClick(TObject *Sender)
{
    //UdTransferHistoryForm->Show();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FormCloseQuery(TObject *Sender, bool &CanClose)
{
    CanClose = true;

    // Warn if there are transfer tasks currently running

    /*if( (m_transferManager != NULL) &&
        (m_transferManager->IsTaskRunning()) )
    {
        AnsiString msg = "There are UD transfers currently in progress. Quitting now will abort these tasks.";
        msg += "\nAre you sure you want to continue?";
        if( MessageDlg( msg, mtWarning, TMsgDlgButtons() << mbYes << mbNo, 0 ) == mrNo )
        {
            CanClose = false;
        }
    }
    */
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::TestCaseTreeViewKeyUp(TObject *Sender,
      WORD &Key, TShiftState Shift)
{
    if( Key == VK_DELETE )
    {
        bool deleteScenario = false;    
        bool deleteTransaction = false;

        for( unsigned selected_item=0; selected_item<TestCaseTreeView->SelectionCount; selected_item++)
        {
            TTreeNode * current_node = TestCaseTreeView->Selections[selected_item];
            if( current_node != NULL )
            {
                if( current_node->Level == 0 )
                {
                    deleteScenario = true;
                }
                else if( current_node->Level == 1 )
                {
                    deleteTransaction = true;
                }
            }
        }
        if( deleteScenario )
        {
            DeleteScenarioClick( Sender );
        }
        if( deleteTransaction )
        {
            DeleteTransactionActionExecute( Sender );
        }
    }
}

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

void __fastcall TMainForm::ValidateOldTestCaseCell(TObject *Sender, int OldRow,
      int OldCol, int NewRow, int NewCol, bool &Allow)
{
      switch (OldCol)
      {
      case 3:  // Repeats
      MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "repeats finished";
                  Application->ProcessMessages();
      break;

      case 4: // period
       MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "period finished" + DBAdvStringGrid2->Cells[OldCol][OldRow];
                  Application->ProcessMessages();
      if (StrToInt(DBAdvStringGrid2->Cells[OldCol][OldRow]) > 360)  DBAdvStringGrid2->Cells[OldCol][OldRow] = "360";
      DBAdvStringGrid2->Cells[OldCol][OldRow] = "33"  ;

 //        TestCaseQuery->Post();
      break;

      case 5: // batch
      MainStatusBar->Panels->Items[ g_messagePanel ]->Text = "batch finished";  
                  Application->ProcessMessages();
      break;
      }


}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

void __fastcall TMainForm::ExitClick(TObject *Sender)
{

    Close();
}


void __fastcall TMainForm::AboutClick(TObject *Sender)
{
     AboutForm->Show();        
}
//---------------------------------------------------------------------------