// =====================================================================
//  $Id: TRunManager.cc,v 1.19 2006/02/15 05:41:59 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TRunManager.cc,v $
//  Revision 1.19  2006/02/15 05:41:59  goiwai
//  さっきの修正ちょっと間違ってたので再度修正しました。
//
//  Revision 1.18  2006/02/15 05:38:18  goiwai
//  Suspend()が呼ばれないバグの修正。
//  thread_join()のあとSuspendRun()を実行する。
//  EventLoopでいきなりIdleになるのをやめた。
//
//  Revision 1.17  2004/09/01 08:08:36  goiwai
//  ロゴを子プロセスからcloseするようにした。
//
//  Revision 1.16  2004/06/24 15:15:25  goiwai
//  たくさんの変更
//  Tcout,Tcerr,Tlogをバッファ経由にした。
//  何個かexternした。Tlog,Tcout,Tcerr,Tinfo...Tcritなど出力関係。
//
//  Revision 1.15  2004/03/26 19:48:25  goiwai
//  /run/shutdown を廃止して /system/shutdown にしました。
//
//  Revision 1.14  2004/03/07 10:30:34  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.13  2004/03/04 14:53:05  goiwai
//  BeginOfRunAction -> Start
//  EndOfRunAction -> Stop
//  Resume,Suspend を追加
//
//  Revision 1.12  2003/12/23 19:13:24  goiwai
//  PrintAuthoInformation()をちょっと修正
//
//  Revision 1.11  2003/12/08 07:06:28  goiwai
//  著作権情報の表示を行なうようにしました.
//  完全には理解していないにせよなるべくGPLに準拠しようと思いまして.
//
//  Revision 1.10  2003/11/25 13:43:40  goiwai
//  /system/waitコマンドを追加しました.
//
//  Revision 1.9  2003/10/06 17:02:45  goiwai
//  *** empty log message ***
//
//  Revision 1.8  2003/08/08 17:59:28  goiwai
//  イベント数やアラームによってランが自動的に終了した際に表示されるメッセー
//  ジの出力をちょっとまともにしました.
//
//  Revision 1.7  2003/08/08 16:29:45  goiwai
//  ラン終了時に出力されるメッセージを元に戻しました.
//
//  Revision 1.6  2003/08/06 12:46:43  goiwai
//  ラン終了時に出力するメッセージの出力形式を変更しました.
//
//  Revision 1.5  2003/07/30 18:16:36  goiwai
//  /run/setid コマンドを追加しました.
//
//  Revision 1.4  2003/07/30 16:20:31  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TRunManager.hh"
#include "TEventManager.hh"
#include "TAnalysisManager.hh"
#include "TSystemAction.hh"
#include "TStringStreamBuffer.hh"
#include "TRunAction.hh"
#include "TEventAction.hh"
#include "TUserInterface.hh"
#include "TTerminalUserInterface.hh"
#include "TReadoutBookDefinition.hh"
#include "TReadoutBook.hh"
#include "TCrateDefinition.hh"
#include "TCrate.hh"
#include "TCommand.hh"
#include "TExitCommand.hh"
#include "TQuitCommand.hh"
#include "TListCommand.hh"
#include "TChangeDirectoryCommand.hh"
#include "TPrintCurrentWorkingDirectoryCommand.hh"
#include "TDateCommand.hh"
#include "TShowNetworkStatusCommand.hh"
#include "TReadFileCommand.hh"
#include "TShellCommand.hh"
#include "TExecuteCommand.hh"
#include "TRunStartCommand.hh"
#include "TRunStopCommand.hh"
#include "TRunSuspendCommand.hh"
#include "TRunResumeCommand.hh"
#include "TSystemShutdownCommand.hh"
#include "TShowRunManagerCommand.hh"
#include "TSetRunIdCommand.hh"
#include "TAnalysisStartCommand.hh"
#include "TAnalysisStopCommand.hh"
#include "TAnalysisSuspendCommand.hh"
#include "TAnalysisResumeCommand.hh"
#include "TShowAnalysisManagerCommand.hh"
#include "TSetStackSizeCommand.hh"
#include "TShowEventManagerCommand.hh"
#include "TSetRunInformationModuleCommand.hh"
#include "TAddRunInformationModuleCommand.hh"
#include "TClearRunInformationModuleCommand.hh"
#include "TInitializeRunInformationModuleCommand.hh"
#include "TShowRunInformationModuleCommand.hh"
#include "TSoftwareRunInformationModule.hh"
#include "THelpCommand.hh"
#include "TPopupLogoCommand.hh"
#include "TPopdownLogoCommand.hh"
#include "TPrintAuthorInformationCommand.hh"
#include "TPrintWarrantyCommand.hh"
#include "TSleepCommand.hh"
#include "TWaitCommand.hh"
#include "TRunTimeLimitCommand.hh"
#include "TRunEventLimitCommand.hh"
#include "TSetEnvironmentVariableCommand.hh"
#include "TUnsetEnvironmentVariableCommand.hh"
#include "TPrintEnvironmentVariableCommand.hh"
#include "TSourceCommand.hh"
#include "TPrintAllEnvironmentVariablesCommand.hh"
#include "TAliasCommand.hh"
#include "TUnaliasCommand.hh"
#include "Tsplash.h"

TRunManager* TRunManager::theRunManager = 0;

static Display* _logoDisplay = 0;
static Window _logoWindow = 0;
static Pixmap _logoPixmap = 0;
static const Tint _showTime = 4;

TRunManager::TRunManager( TUserInterface* ui )
  : theStatus( tStatusDead ),
    theRun(), theSystemAction( 0 ), theRunAction( 0 ), theEventManager( 0 ), 
    theUserInterface( ui ), theThreadOfEventLoop( 0 ),
    theRunInformationModule( 0 ), 
    theAnalysisManager( 0 ),
    theRunTimer(),
    theReadoutBookDefinition( 0 ), theReadoutBook( 0 ),
    theCrateDefinition( 0 ), theCrate( 0 ),
    theEnvironmentVariableTable(), theEventLimit( 0 )
{
  PopupLogo();

  if ( theRunManager ) {
    Tcerr << "TRunManager::TRunManager: RunManager constructed twice." << Tendl;
    exit( -EFAULT );
  }
  theRunManager = this;
  theEventManager = new TEventManager();

  if ( theUserInterface ) {
    installDefaultCommand();
  } else {
    theUserInterface = new TTerminalUserInterface();
    installDefaultCommand();
  }

  PrintAuthorInformation();
  signal( SIGALRM, TRunManager::catchAlarmSignal );
  theStatus = tStatusStandby;

  if ( fork() == 0 ) {
    sleep( _showTime );
    PopdownLogo();
    exit( EXIT_SUCCESS );
  }
}

TRunManager::~TRunManager()
{
  Tstring head = "TRunManager::~TRunManager: ";
  delete theEventManager;
  theEventManager = 0;
  Tcout << head << "EventManager was deleted." << Tendl;
  if ( theUserInterface ) {
    delete theUserInterface;
    theUserInterface = 0;
    Tcout << head << "UserInterface was deleted." << Tendl;
  }
  if ( theRunAction ) {
    delete theRunAction;
    theRunAction = 0;
    Tcout << head << "RunAction was deleted." << Tendl;
  }
  if ( theAnalysisManager ) {
    delete theAnalysisManager;
    theAnalysisManager = 0;
    Tcout << head << "AnalysisManager was deleted." << Tendl;
  }
  if ( theReadoutBookDefinition ) {
    delete theReadoutBookDefinition;
    theReadoutBookDefinition = 0;
    Tcout << head << "ReadoutBookDefinition was deleted." << Tendl;
  }
  if ( theReadoutBook ) {
    delete theReadoutBook;
    theReadoutBook = 0;
    Tcout << head << "ReadoutBook was deleted." << Tendl;
  }
  if ( theCrateDefinition ) {
    delete theCrateDefinition;
    theCrateDefinition = 0;
    Tcout << head << "CrateDefinition was deleted." << Tendl;
  }
  if ( theCrate ) {
    delete theCrate;
    theCrate = 0;
    Tcout << head << "Crate was deleted." << Tendl;
  }
  if ( theSystemAction ) {
    delete theSystemAction;
    theSystemAction = 0;
    coutbuf.SetSystemAction( 0 );
    cerrbuf.SetSystemAction( 0 );
    clogbuf.SetSystemAction( 0 );

    // using std::cout with default buffer following line.
    Tcout << head << "SystemAction was deleted." << Tendl;
  }
  theStatus = tStatusDead;
  Tcout << head << "RunManager was deleted." << Tendl;
  theRunManager = 0;
}

Tvoid TRunManager::SessionStart()
{
  if ( !theUserInterface ) {
    return;
  }

  while ( theUserInterface -> AcceptCommand() ) {

    Tstring input = theUserInterface -> GetInputCommand();
    if ( input.empty() ) {
      continue;
    }


    // 入力をヒストリに保存
    TCommandHistory& commandhistory = theUserInterface -> GetCommandHistory();
    Tofstream& of = theUserInterface -> GetHistoryFileStream();
    of << input << Tendl;
    commandhistory.push_back( input );


    // 入力の解釈
    TstringList args = divide( input );
    Tstring comname = args[ 0 ];
    args.erase( args.begin() );


    Tstring abspath = theUserInterface -> ModifyPath( comname );
    TCommand* command = 0;
    if ( ( command = theUserInterface -> FindCommand( abspath ) ) ) {

      command -> Execute( args );

      // status check after execution
      if ( theStatus == tStatusDead ) {
	break;
      } else if ( theStatus == tStatusReady ) {
	GoEventLoop();
      } else if ( theStatus == tStatusWaitingReady ) {
	WaitReturnFromEventLoop();
      } else if ( theStatus == tStatusIdle ) {
	;// nothing to do
      } else if ( theStatus == tStatusStandby ) {
	;// nothing to do
      } else if ( theStatus == tStatusBusy ) {
	;// nothing to do
      } else {
	break;
      }


    } else if ( !( comname.empty() ) ) {
      theUserInterface -> NotFoundCommand( comname );
    } else {
      continue;
    }
  }

  return;
}

Tint TRunManager::SetUserCommand( TCommand* command )
{
  if ( theUserInterface == 0 ) {
    Tcerr << "TRunManager::SetUserCommand: unset user interface." << Tendl;
    return -EFAULT;
  }
  if ( command -> GetRunManager() == 0 ) {
    command -> SetRunManager( this );
  }
  return theUserInterface -> AddCommand( command );
}

Tvoid TRunManager::ShowStatus() const
{
  switch ( theStatus ) {
    case tStatusStandby:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Standby(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Prepare for next run or quit the session." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "/run/start, /system/shutdown" << Tendl;
      break;
    case tStatusReady:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Ready(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Waiting for event notification(TRIGER)." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "/run/suspend" << Tendl;
      break;
    case tStatusBusy:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Busy(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Just Taking data from hardware/software." << Tendl;
      Tcout << Ttab << "Suspend command is notify to the RunManager after transition of status to ready." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "/run/suspend" << Tendl;
      break;
    case tStatusIdle:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Idle(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Just waiting for command, never be taken events." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "/run/resume or /run/stop" << Tendl;
      break;
    case tStatusWaitingReady:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "WaitingReady(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Process does not return yet. Keeping this status while one trigger." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "Any commands disable." << Tendl;
      break;
    case tStatusDead:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Dead(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Serious trouble." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "Kill me by force." << Tendl;
      break;
    case tStatusUnknown:
    default:
      Tcout << "STATUS" << Tendl;
      Tcout << Ttab << "Unknown(" << theStatus << ")" << Tendl;
      Tcout << "DESCRIPTION" << Tendl;
      Tcout << Ttab << "Can not resolve status paramter." << Tendl;
      Tcout << "ACCEPTABLE" << Tendl;
      Tcout << Ttab << "Kill me by force." << Tendl;
      break;
  }

  Tcout << "ID" << Tendl;
  Tcout << Ttab << theRun.GetRunID() << Tendl;

  Tcout << "TIMER" << Tendl;
  Tcout << Ttab << theRunTimer << Tendl;

  Tcout << "CLOCK" << Tendl;
  Tcout << Ttab << theRunClock << Tendl;

  if ( theReadoutBook != 0 ) {
    Tcout << "BOOK" << Tendl;
    TReadoutIndex& index = theReadoutBook -> GetReadoutIndex();
    for ( Tint i = 0; i < index.GetSize(); i ++ ) {
      //どのモジュールから,とかゆう情報が欲しい,面倒だ,あとまわし
      Tcout << Ttab << i + 1 << "/" << index.GetSize() << Ttab << index[ i ] << Tendl;
    }
  }

  if ( theCrate != 0 ) {
    Tcout << "CRATE" << Tendl;
    TModuleTable& table = theCrate -> GetModuleTable();
    for ( Tint i = 0; i < table.GetSize(); i ++ ) {
      Tcout << Ttab << i + 1 << "/" << table.GetSize() << Ttab << table[ i ] << Tendl;
    }
  }

  TUint rest = alarm( alarm( 0 ) );
  if ( theEventLimit > 0 || rest != 0 ) {
    Tcout << "SCHEDULE" << Tendl;
  }
  if ( theEventLimit > 0 ) {
    Tint rest = theEventLimit - theEventManager -> GetNumberOfEvents();
    Tcout << Ttab << "Scheduled by number of events, " << theEventLimit << "." << Tendl;
    Tcout << Ttab << "This run is going to be terminated automatically after " << rest << " events." << Tendl;
  }
  if ( rest != 0 ) {
    Tcout << Ttab << "Scheduled by alarm, rest " << rest << " seconds." << Tendl;
    Tcout << Ttab << "This run is going to be terminated automatically after " << rest << " seconds." << Tendl;
  }

  if ( theRunAction != 0 ) {
    Tcout << "ACTION" << Tendl;
    Tcout << Ttab << typeid( *theRunAction ).name() << Tendl;
  }

  return;
}

Tvoid TRunManager::ShutdownRun()
{
  if ( theStatus != tStatusStandby ) {
    ShowStatus();
    return;
  }
  if ( theSystemAction ) {
    theSystemAction -> Shutdown( this );
  }
  theStatus = tStatusDead;
  return;
}

Tvoid TRunManager::StartRun()
{
  if ( theStatus != tStatusStandby ) {
    ShowStatus();
    return;
  }
  theRunTimer.Start();
  Tcout << "Run #" << theRun.GetRunID() << " start." << Tendl;
  theRun.Clear();
  if ( theRunAction ) {
    theRunAction -> Start( theRun );
  }
  theStatus = tStatusReady;
  return;
}

Tvoid TRunManager::StartRun( Tint runid )
{
  if ( theStatus != tStatusStandby ) {
    ShowStatus();
    return;
  }
  theRunTimer.Start();
  Tcout << "Run #" << runid << " start." << Tendl;
  theRun.Clear();
  theRun.SetRunID( runid );
  if ( theRunAction ) {
    theRunAction -> Start( theRun );
  }
  theStatus = tStatusReady;
  return;
}

Tvoid TRunManager::StopRun()
{
  if ( theStatus != tStatusIdle ) {
    ShowStatus();
    return;
  }
  if ( theRunAction ) {
    theRunAction -> Stop( theRun );
  }
  Tint runid = theRun.GetRunID();

  Tint neventsbuf = theEventManager -> GetNumberOfEvents();
  Tint runidbuf = runid;

  theRun.SetRunID( ++ runid );
  theEventManager -> Clear();
  theStatus = tStatusStandby;
  theRunTimer.Stop();

  Tcout << theRunClock << Tendl;
  Tcout << theRunTimer << Tendl;
  Tcout << "Run #" << runidbuf << ": ";
  Tcout << neventsbuf << " events have been producted." << Tendl;

  return;
}

Tvoid TRunManager::SuspendRun()
{
  if ( theStatus == tStatusBusy ) {
    theStatus = tStatusWaitingReady;
    return;
  } else if ( theStatus != tStatusReady ) {
    ShowStatus();
    return;
  }

  if ( theRunAction ) {
    theRunAction -> Suspend( theRun );
  }

  theRunTimer.Pause();
  theStatus = tStatusIdle;
  return;
}

Tvoid TRunManager::ResumeRun()
{
  if ( theStatus != tStatusIdle ) {
    ShowStatus();
    return;
  }

  if ( theRunAction ) {
    theRunAction -> Resume( theRun );
  }

  theRunTimer.Restart();
  theStatus = tStatusReady;
  return;
}

Tvoid* TRunManager::doEventLoop( Tvoid* arguments )
{
  TRunManager* runmanager = TRunManager::GetRunManager();
  TEventManager* evtmanager = runmanager -> GetEventManager();
  if ( runmanager -> GetStatus() != tStatusReady ) {
    runmanager -> ShowStatus();
    return 0;
  }

  while ( runmanager -> GetStatus() == tStatusReady ) {
    if ( runmanager -> GetStatus() == tStatusWaitingReady ) {
      runmanager -> GetRunTimer().Pause();
      runmanager -> SetStatus( tStatusIdle );
      break;
    } else {
      runmanager -> SetStatus( tStatusBusy );
    }
    evtmanager -> TakeEvent();
    evtmanager -> RecordEvent();

    Tint evtlimit = runmanager -> GetEventLimit();
    if ( evtlimit > 0 && evtmanager -> GetNumberOfEvents() == evtlimit ) {
      runmanager -> SetStatus( tStatusReady );
      runmanager -> SuspendRun();
      Tcout << Tendl;
      runmanager -> StopRun();
      break;
    }

    if ( runmanager -> GetStatus() == tStatusWaitingReady ) {
      runmanager -> SetStatus( tStatusReady );
      break;
    } else {
      runmanager -> SetStatus( tStatusReady );
    }
  }

  return 0;
}

Tvoid TRunManager::GoEventLoop()
{
  pthread_create( &theThreadOfEventLoop, 0, TRunManager::doEventLoop, 0 );
  return;
}

Tvoid TRunManager::WaitReturnFromEventLoop()
{
  pthread_join( theThreadOfEventLoop, 0 );
  pthread_detach( theThreadOfEventLoop );
  SuspendRun();
  return;
}

Tvoid TRunManager::PopupLogo() const
{
  if ( _logoPixmap ) {
    return;
  }

  _logoDisplay = XOpenDisplay( 0 );
  if ( !_logoDisplay ) {
    return;
  }

  Tint screen = DefaultScreen( _logoDisplay );
  TUlong back = WhitePixel( _logoDisplay, screen );
  TUlong fore = BlackPixel( _logoDisplay, screen );
  _logoWindow =
    XCreateSimpleWindow( _logoDisplay, DefaultRootWindow( _logoDisplay ),
			 -100, -100, 50, 50, 0, fore, back );
  Tint depth = PlanesOfScreen( XDefaultScreenOfDisplay( _logoDisplay ) );

  if ( depth > 1 ) {
    XWindowAttributes win_attr;
    XGetWindowAttributes( _logoDisplay, _logoWindow, &win_attr );

    XpmAttributes attr;
    attr.valuemask = XpmVisual | XpmColormap | XpmDepth;
    attr.visual = win_attr.visual;
    attr.colormap = win_attr.colormap;
    attr.depth = win_attr.depth;
    attr.valuemask |= XpmColorKey;

    if ( depth > 4 )
      attr.color_key = XPM_COLOR;
    else if ( depth > 2 )
      attr.color_key = XPM_GRAY4;
    else if ( depth > 1 )
      attr.color_key = XPM_GRAY;
    else if ( depth == 1 )
      attr.color_key = XPM_MONO;
    else
      attr.valuemask &= ~XpmColorKey;

    XpmCreatePixmapFromData( _logoDisplay, _logoWindow,
			     (char**)Tsplash, &_logoPixmap,
			     (Pixmap *)0, &attr );
    XpmFreeAttributes( &attr );
  }

  Window root;
  Tint x;
  Tint y;
  TUint w;
  TUint h;
  TUint bw;
  TUint dep;
  XGetGeometry( _logoDisplay, _logoPixmap, &root, &x, &y, &w, &h, &bw, &dep );
  Screen* xscreen = XDefaultScreenOfDisplay( _logoDisplay );
  x = ( WidthOfScreen( xscreen ) - w ) / 2;
  y = ( HeightOfScreen( xscreen ) - h ) / 2;
  XMoveResizeWindow( _logoDisplay, _logoWindow, x, y, w, h );
  XSync( _logoDisplay, False );

  TUlong valmask;
  XSetWindowAttributes xswa;
  valmask = CWBackPixmap | CWOverrideRedirect;
  xswa.background_pixmap = _logoPixmap;
  xswa.override_redirect = True;
  XChangeWindowAttributes( _logoDisplay, _logoWindow, valmask, &xswa );

  XMapRaised( _logoDisplay, _logoWindow );
  XSync( _logoDisplay, False );

  return;
}

Tvoid TRunManager::PopdownLogo() const
{
  if ( _logoWindow ) {
    XUnmapWindow( _logoDisplay, _logoWindow );
    XDestroyWindow( _logoDisplay, _logoWindow );
    _logoWindow = 0;
  }
  if ( _logoPixmap ) {
    XFreePixmap( _logoDisplay, _logoPixmap );
    _logoPixmap = 0;
  }
  if ( _logoDisplay ) {
    XSync( _logoDisplay, False );
    XCloseDisplay( _logoDisplay );
    _logoDisplay = 0;
  }
  return;
}

Tvoid TRunManager::PrintAuthorInformation( Tostream& tos ) const
{
  Tint ncol = theUserInterface -> GetNumberOfColumns();
  for ( Tint col = 0; col < ncol; col ++ ) {
    tos << "=";
  }
  tos << Tendl;
  // for GPL Version 2 or later
  tos << Tproject << " " << Tversion << " - a Class Library for Data AcQuisition" << Tendl;
  tos << "Copyright (C) 2000-2004 Go IWAI <goiwai@users.sourceforge.jp>" << Tendl;
  tos << "  This is free software with ABSOLUTELY NO WARRANTY." << Tendl;
  tos << "  For details type \"warranty\"." << Tendl;

  //昔はこうゆう出力だったけどくどいのでやめ
  //tos << "Project: " << Tproject << Tendl;
  //tos << "Version: " << Tversion << Tendl;
  //tos << "$Id: TRunManager.cc,v 1.19 2006/02/15 05:41:59 goiwai Exp $" << Tendl;
  //tos << "$Name: CLDAQ-1-14-06 $" << Tendl;
  //for ( Tint col = 0; col < ncol; col ++ ) {
  //tos << "-";
  //}
  //tos << Tendl;
  //tos << "8050 Ikarashi 2-no-chou, Niigata, 950-2181, Japan" << Tendl;
  //tos << "Phone: +81-25-262-6138" << Tendl;
  //tos << "Go IWAI <goiwai@users.sourceforge.jp>" << Tendl;
  for ( Tint col = 0; col < ncol; col ++ ) {
    tos << "=";
  }
  tos << Tendl;
  return;
}

Tvoid TRunManager::SetEventManager( TEventManager* manager )
{
  if ( theEventManager ) {
    Tstring head = "TRunManager::SetEventManager: ";
    delete theEventManager;
    Tcout << head << "EventManager was deleted." << Tendl;
    theEventManager = 0;
  }
  theEventManager = manager;
  return;
}

Tvoid TRunManager::SetUserInterface( TUserInterface* ui )
{
  if ( theUserInterface ) {
    Tstring head = "TRunManager::SetUserInterface: ";
    delete theUserInterface;
    Tcout << head << "UserInterface was deleted." << Tendl;
    theUserInterface = 0;
  }
  theUserInterface = ui;
  installDefaultCommand();
  return;
}

Tvoid TRunManager::SetSystemAction( TSystemAction* action )
{
  if ( theSystemAction ) {
    Tstring head = "TRunManager::SetSystemAction: ";
    delete theSystemAction;
    Tcout << head << "SystemAction was deleted." << Tendl;
    theSystemAction = 0;
    coutbuf.SetSystemAction( 0 );
    cerrbuf.SetSystemAction( 0 );
    clogbuf.SetSystemAction( 0 );
  }
  theSystemAction = action;
  coutbuf.SetSystemAction( theSystemAction );
  cerrbuf.SetSystemAction( theSystemAction );
  clogbuf.SetSystemAction( theSystemAction );
  action -> Boot( this );
  return;
}

Tvoid TRunManager::SetRunAction( TRunAction* action )
{
  if ( theRunAction ) {
    Tstring head = "TRunManager::SetRunAction: ";
    delete theRunAction;
    Tcout << head << "RunAction was deleted." << Tendl;
    theRunAction = 0;
  }
  theRunAction = action;
  action -> SetRunManager( this );
  action -> SetEventManager( theEventManager );
  action -> SetReadoutBook( theReadoutBook );
  action -> SetCrate( theCrate );
  return;
}

Tvoid TRunManager::SetEventAction( TEventAction* action )
{
  theEventManager -> SetEventAction( action );
  action -> SetRunManager( this );
  action -> SetEventManager( theEventManager );
  action -> SetReadoutBook( theReadoutBook );
  action -> SetCrate( theCrate );
  return;
}

Tvoid TRunManager::SetRunInformationModule( TSoftwareRunInformationModule* module )
{
  if ( theUserInterface ) {
    SetUserCommand( new TSetRunInformationModuleCommand( this, module ) );
    SetUserCommand( new TAddRunInformationModuleCommand( this, module ) );
    SetUserCommand( new TClearRunInformationModuleCommand( this, module ) );
    SetUserCommand( new TInitializeRunInformationModuleCommand( this, module ) );
    SetUserCommand( new TShowRunInformationModuleCommand( this, module ) );
  }
  theRunInformationModule = module;
  return;
}

Tvoid TRunManager::SetRunInformationModule( const Tstring& id )
{
  static const Tstring head = "TRunManager::SetRunInformationModule: ";
  if ( theCrate ) {
    TModule* module = theCrate -> FindModule( id );
    if ( module ) {
      SetRunInformationModule( (TSoftwareRunInformationModule*)module );
    } else {
      Tcerr << head << id << ": No such module in crate." << Tendl;;
    }
  }
  return;
}

Tvoid TRunManager::SetRunInformationModule( Tint slot )
{
  Tcout << "this function is under construction." << Tendl;
  return;
}

Tvoid TRunManager::SetAnalysisManager( TAnalysisManager* manager )
{
  if ( theUserInterface ) {
    SetUserCommand( new TAnalysisStartCommand( this, manager ) );
    SetUserCommand( new TAnalysisStopCommand( this, manager ) );
    SetUserCommand( new TAnalysisSuspendCommand( this, manager ) );
    SetUserCommand( new TAnalysisResumeCommand( this, manager ) );
    SetUserCommand( new TShowAnalysisManagerCommand( this, manager ) );
  }
  if ( theAnalysisManager ) {
    Tstring head = "TRunManager::SetAnalysisManager: ";
    delete theAnalysisManager;
    theAnalysisManager = 0;
    Tcout << head << "AnalysisManager was deleted." << Tendl;
  }
  theAnalysisManager = manager;
  return;
}

Tvoid TRunManager::SetReadoutBookDefinition( TReadoutBookDefinition* definition )
{
  static const Tstring head = "TRunManager::SetReadoutBookDefinition: ";

  if ( theReadoutBookDefinition ) {
    delete theReadoutBookDefinition;
    theReadoutBookDefinition = 0;
    Tcout << head << "ReadoutBookDefinition was deleted." << Tendl;
  }
  theReadoutBookDefinition = definition;
  theReadoutBookDefinition -> SetRunManager( this );
  theReadoutBookDefinition -> SetCrate( theCrate );

  if ( theReadoutBook ) {
    delete theReadoutBook;
    theReadoutBook = 0;
    Tcout << head << "ReadoutBook was deleted." << Tendl;
  }
  if ( theReadoutBookDefinition -> GetCrate() ) {
    theReadoutBook = theReadoutBookDefinition -> Define();
  } else {
    Tstring head = "TRunManager::SetReadoutBookDefinition: ";
    Tcerr << head << "crate is not defined." << Tendl;
    Tcerr << head << "you should NOTE that:" << Tendl;
    Tcerr << head << "readout-book should be defined after definition of crate." << Tendl;
    exit( -EFAULT );
  }


  if ( theRunAction ) {
    theRunAction -> SetReadoutBook( theReadoutBook );
  }

  if ( theEventManager -> GetEventAction() ) {
    theEventManager -> GetEventAction() -> SetReadoutBook( theReadoutBook );
  }

  return;
}

Tvoid TRunManager::SetCrateDefinition( TCrateDefinition* definition )
{
  static const Tstring head = "TRunManager::SetCrateDefinition: ";

  if ( theCrateDefinition ) {
    delete theCrateDefinition;
    theCrateDefinition = 0;
    Tcout << head << "CrateDefinition was deleted." << Tendl;
  }
  theCrateDefinition = definition;
  theCrateDefinition -> SetRunManager( this );

  if ( theCrate ) {
    delete theCrate;
    theCrate = 0;
    Tcout << head << "Crate was deleted." << Tendl;
  }
  theCrate = theCrateDefinition -> Define();

  if ( theRunAction ) {
    theRunAction -> SetCrate( theCrate );
  }

  if ( theEventManager -> GetEventAction() ) {
    theEventManager -> GetEventAction() -> SetCrate( theCrate );
  }

  return;
}

TstringList TRunManager::divide( const Tstring& input ) const
{
  TstringList divided;
  Tsize_t begin = 0;
  Tsize_t end = 0;
  Tsize_t inputlen = input.size();

  do {
    begin = input.find_first_not_of( ' ', end );
    end = input.find( ' ', begin );
    if ( begin < inputlen && end >= inputlen ) {
      divided.push_back( input.substr( begin, inputlen - begin ) );
    } else if ( begin >= inputlen && end >= inputlen ) {
      break;
    } else {
      divided.push_back( input.substr( begin, end - begin ) );
    }
  } while ( begin < inputlen && end < inputlen );

  return divided;
}

Tvoid TRunManager::installDefaultCommand()
{
  // built-in
  SetUserCommand( new TExitCommand( this ) );
  SetUserCommand( new TQuitCommand( this ) );
  SetUserCommand( new TListCommand( this ) );
  SetUserCommand( new TChangeDirectoryCommand( this ) );
  SetUserCommand( new TPrintCurrentWorkingDirectoryCommand( this ) );
  SetUserCommand( new THelpCommand( this ) );
  SetUserCommand( new TSetEnvironmentVariableCommand( this, &theEnvironmentVariableTable ) );
  SetUserCommand( new TUnsetEnvironmentVariableCommand( this, &theEnvironmentVariableTable ) );
  SetUserCommand( new TPrintEnvironmentVariableCommand( this, &theEnvironmentVariableTable ) );
  SetUserCommand( new TSourceCommand( this ) );
  SetUserCommand( new TPrintAllEnvironmentVariablesCommand( this ) );
  SetUserCommand( new TAliasCommand( this ) );
  SetUserCommand( new TUnaliasCommand( this ) );
  SetUserCommand( new TPrintWarrantyCommand( this ) );
  //system
  SetUserCommand( new TSystemShutdownCommand( this ) );
  SetUserCommand( new TDateCommand( this ) );
  SetUserCommand( new TShowNetworkStatusCommand( this ) );
  SetUserCommand( new TExecuteCommand( this ) );
  SetUserCommand( new TSleepCommand( this ) );
  SetUserCommand( new TWaitCommand( this ) );
  SetUserCommand( new TShellCommand( this ) );
  // option
  SetUserCommand( new TReadFileCommand( this ) );
  SetUserCommand( new TPopupLogoCommand( this ) );
  SetUserCommand( new TPopdownLogoCommand( this ) );
  SetUserCommand( new TPrintAuthorInformationCommand( this ) );
  // event
  SetUserCommand( new TSetStackSizeCommand( this ) );
  SetUserCommand( new TShowEventManagerCommand( this ) );
  // run
  SetUserCommand( new TRunStartCommand( this ) );
  SetUserCommand( new TRunStopCommand( this ) );
  SetUserCommand( new TRunSuspendCommand( this ) );
  SetUserCommand( new TRunResumeCommand( this ) );
  SetUserCommand( new TShowRunManagerCommand( this ) );
  SetUserCommand( new TRunTimeLimitCommand( this ) );
  SetUserCommand( new TRunEventLimitCommand( this ) );
  SetUserCommand( new TSetRunIdCommand( this ) );
  return;
}

Tvoid TRunManager::catchAlarmSignal( Tint sigid )
{
  TRunManager* manager = TRunManager::GetRunManager();
  Tstatus_t status = manager -> GetStatus();

  if ( status == tStatusReady ) {
    manager -> SuspendRun();
    Tcout << Tendl;
    manager -> StopRun();
  } else if ( status == tStatusWaitingReady ) {
    manager -> WaitReturnFromEventLoop();
    Tcout << Tendl;
    manager -> StopRun();
  } else if ( status == tStatusIdle ) {
    Tcout << Tendl;
    manager -> StopRun();
  } else if ( status == tStatusBusy ) {
    manager -> SuspendRun();
    manager -> WaitReturnFromEventLoop();
    Tcout << Tendl;
    manager -> StopRun();
  }

  return;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TRunManager)
#endif
