// =====================================================================
//  $Id: TAnalysisManager.cc,v 1.4 2004/03/07 10:30:27 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: TAnalysisManager.cc,v $
//  Revision 1.4  2004/03/07 10:30:27  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.3  2003/10/06 17:02:36  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:17:10  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TAnalysisManager.hh"
#include "TDataElement.hh"
#include "TMatrixElement.hh"
#include "TExtractor.hh"

TAnalysisManager* TAnalysisManager::theAnalysisManager = 0;

TAnalysisManager::TAnalysisManager( TAnalyser* analyser )
  : theStatusTable(), theAnalyser( analyser ), theAnalysisAction( 0 )
{
  theAnalysisManager = this;
}

TAnalysisManager::~TAnalysisManager()
{
  Tstring head = "TAnalysisManager::~TAnalysisManager: ";
  if ( theAnalyser ) {
    Tstring id = theAnalyser -> GetAnalyserID();
    delete theAnalyser;
    Tcout << head << "Analyser " << id << " was deleted." << Tendl;
    theAnalyser = 0;
  }
  if ( theAnalysisAction ) {
    delete theAnalysisAction;
    Tcout << head << "AnalysisAction was deleted." << Tendl;
    theAnalysisAction = 0;
  }
  Tcout << head << "AnalysisManager was deleted." << Tendl;
  theAnalysisManager = 0;
}

Tvoid TAnalysisManager::ShowStatus() const
{
  Tcout << theStatusTable << Tendl;
  return;
}

Tvoid TAnalysisManager::StartAnalysis( const Tstring& id )
{
  if ( theStatusTable.GetStatus( id ) != tStatusStandby ) {
    ShowStatus();
    return;
  }
  if ( theAnalysisAction ) {
    theAnalysisAction -> BeginOfAnalysisAction( theAnalyser, id );
  }
  theStatusTable.SetStatus( id, tStatusReady );

  //
  // 状態テーブル見て解析ループに入る
  // doAnalysisLoop( id );
  //
  GoAnalysisLoop( id );

  return;
}

Tvoid TAnalysisManager::GoAnalysisLoop( const Tstring& id )
{
  pthread_t* thread = theStatusTable.GetThreadID( id );
  if ( thread != 0 ) {
    pthread_create( thread, 0, TAnalysisManager::doAnalysisLoop, (Tvoid*)(&id) );
  } else {
    Tstring head = "TAnalysisManager::GoAnalysisLoop: ";
    Tcerr << head << "can not find status information in table." << Tendl;
  }
  return;
}

Tvoid* TAnalysisManager::doAnalysisLoop( Tvoid* id )
{
  Tstring strid = *( (Tstring*)id );
  TAnalysisManager* manager = TAnalysisManager::GetAnalysisManager();
  TAnalysisStatusTable& table = manager -> GetStatusTable();

  if ( table.GetStatus( strid ) != tStatusReady ) {
    manager -> ShowStatus();
    return 0;
  }

  while ( table.GetStatus( strid ) != tStatusIdle ) {
    if ( table.GetStatus( strid ) == tStatusWaitingReady ) {
      table.SetStatus( strid, tStatusIdle );
      break;
    } else {
      table.SetStatus( strid, tStatusBusy );
    }

    manager -> UpdateAnalysis( strid );

    if ( table.GetStatus( strid ) == tStatusWaitingReady ) {
      table.SetStatus( strid, tStatusIdle );
      break;
    } else {
      table.SetStatus( strid, tStatusReady );
    }
  }

  return 0;
}

Tvoid TAnalysisManager::UpdateAnalysis( const Tstring& id )
{
  Tstring head = "TAnalysisManager::UpdateAnalysis: ";
  if ( theAnalyser == 0 ) {
    Tcerr << head << "Analyser doesn't exist." << Tendl;
    return;
  }
  TExtractor* ext = 0;
  ext = theAnalyser -> FindExtractor( id );
  if ( ext == 0 ) {
    theAnalyser -> NotFoundExtractor();
    return;
  } else {
    ext -> Extract();
    if ( ext -> DoesExtractSuccess() && theAnalysisAction ) {
      TMatrixElement& matrix = ext -> GetMatrixElement();
      theAnalysisAction -> UpdateOfAnalysisAction( theAnalyser, matrix );
      Tint usec = ext -> GetSamplingRate();
      if ( usec > 0 ) {
	Tstatus_t statbuf = theStatusTable.GetStatus( id );
	theStatusTable.SetStatus( id, tStatusSleep );
	usleep( (TUlong)usec );
	if ( theStatusTable.GetStatus( id ) != tStatusWaitingReady ) {
	  theStatusTable.SetStatus( id, statbuf );
	}
      }
    }
  }
  return;
}

Tvoid TAnalysisManager::StopAnalysis( const Tstring& id )
{
  if ( theStatusTable.GetStatus( id ) != tStatusIdle ) {
    ShowStatus();
    return;
  }
  if ( theAnalyser == 0 ) {
    Tstring head = "TAnalysisManager::StopAnalysis: ";
    Tcerr << head << "Analyser doesn't exist." << Tendl;
    theStatusTable.SetStatus( id, tStatusStandby );
    return;
  }
  if ( theAnalysisAction ) {
    theAnalysisAction -> EndOfAnalysisAction( theAnalyser, id );
  }
  theStatusTable.SetStatus( id, tStatusStandby );
  return;
}

Tvoid TAnalysisManager::SuspendAnalysis( const Tstring& id )
{
  Tstatus_t status = theStatusTable.GetStatus( id );
  if ( status == tStatusBusy || status == tStatusSleep ) {
    theStatusTable.SetStatus( id, tStatusWaitingReady );
    return;
  } else if ( status != tStatusReady ) {
    ShowStatus();
    return;
  }
  theStatusTable.SetStatus( id, tStatusIdle );
  return;
}

Tvoid TAnalysisManager::WaitReturnFromAnalysisLoop( const Tstring& id )
{
  Tthread_t* thread = theStatusTable.GetThreadID( id );
  if ( thread ) {
    pthread_join( *thread, 0 );
    pthread_detach( *thread );
    *thread = 0;
  }
  return;
}

Tvoid TAnalysisManager::ResumeAnalysis( const Tstring& id )
{
  if ( theStatusTable.GetStatus( id ) != tStatusIdle ) {
    ShowStatus();
    return;
  }
  theStatusTable.SetStatus( id, tStatusReady );
  return;
}

Tvoid TAnalysisManager::StartAnalysis()
{
  theAnalyser -> SetExtractorIndex( 0 );
  TExtractor* ext = 0;
  while ( ( ext = theAnalyser -> NextExtractor() ) )
    StartAnalysis( ext -> GetExtractorID() );
  return;
}

Tvoid TAnalysisManager::UpdateAnalysis()
{
  theAnalyser -> SetExtractorIndex( 0 );
  TExtractor* ext = 0;
  while ( ( ext = theAnalyser -> NextExtractor() ) )
    UpdateAnalysis( ext -> GetExtractorID() );
  return;
}

Tvoid TAnalysisManager::StopAnalysis()
{
  theAnalyser -> SetExtractorIndex( 0 );
  TExtractor* ext = 0;
  while ( ( ext = theAnalyser -> NextExtractor() ) )
    StopAnalysis( ext -> GetExtractorID() );
  return;
}

Tvoid TAnalysisManager::SuspendAnalysis()
{
  theAnalyser -> SetExtractorIndex( 0 );
  TExtractor* ext = 0;
  while ( ( ext = theAnalyser -> NextExtractor() ) )
    SuspendAnalysis( ext -> GetExtractorID() );
  return;
}

Tvoid TAnalysisManager::ResumeAnalysis()
{
  theAnalyser -> SetExtractorIndex( 0 );
  TExtractor* ext = 0;
  while ( ( ext = theAnalyser -> NextExtractor() ) )
    ResumeAnalysis( ext -> GetExtractorID() );
  return;
}

Tvoid TAnalysisManager::SetAnalyser( TAnalyser* analyser )
{
  if ( theAnalyser ) {
    Tstring head = "TAnalysisManager::SetAnalyser: ";
    Tstring id = theAnalyser -> GetAnalyserID();
    delete theAnalyser;
    Tcout << head << "Analyser " << id << " was deleted." << Tendl;
    theAnalyser = 0;
  }
  theAnalyser = analyser;
  return;
}

Tvoid TAnalysisManager::SetAnalysisAction( TAnalysisAction* action )
{
  if ( theAnalysisAction ) {
    Tstring head = "TAnalysisManager::SetAnalysisAction: ";
    delete theAnalysisAction;
    Tcout << head << "AnalysisAction was deleted." << Tendl;
    theAnalysisAction = 0;
  }
  theAnalysisAction = action;
  return;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TAnalysisManager)
#endif
