////////////////////////////////////////////////////////////////////////
// $Id: BandClusterListModule.cxx,v 1.5 2003/09/14 13:58:55 miyagawa Exp $
//
// BandClusterListModule
//
// Begin_Html<img src="../../pedestrians.gif" align=center>
// <a href="../source_warning.html">Warning for beginners</a>.<br>
//
// This module creates a list of clusters based on proximity of strip
// digit pairs in space, plane number, and coil hole crossings.
// This module was developed mainly for analyzing CalDet data and should
// not be used for Near Detector.  It can be used for Far Detector, but
// it will fail for multi-muon events.
//
// The Reco and Ana methods have been implemented.
//
// Author:  P.S. Miyagawa 2/2002
//
// Also see <a href="../../root_crib/index.html">The ROOT Crib</a> and
// <a href="../JOBC_Classes.html"> Job Control Classes</a> (part of
// <a href="../index.html">The MINOS Class User Guide</a>)End_Html
////////////////////////////////////////////////////////////////////////

#include "TString.h"

#include "Algorithm/AlgConfig.h"
#include "Algorithm/AlgFactory.h"
#include "Algorithm/AlgHandle.h"
#include "Candidate/CandContext.h"
#include "CandData/CandRecord.h"
#include "JobControl/JobCModuleRegistry.h"
#include "JobControl/JobCommand.h"
#include "MessageService/MsgService.h"
#include "MinosObjectMap/MomNavigator.h"
#include "RecoBase/CandSliceListHandle.h"
#include "BubbleSpeak/CandMSTClusterList.h"
#include "BubbleSpeak/CandMSTClusterListHandle.h"
#include "BubbleSpeak/BandClusterListModule.h"

//......................................................................

CVSID("$Id: BandClusterListModule.cxx,v 1.5 2003/09/14 13:58:55 miyagawa Exp $");

// Declare this module to JobControll. Arguments are:
//  (1) The class name 
//  (2) The human-readable name 
//  (3) A short, human-readable description of what the module does
JOBMODULE(BandClusterListModule, 
	  "BandClusterListModule",
          "Builds list of clusters from a CandDigiPairList");

//......................................................................

BandClusterListModule::BandClusterListModule()
//: fBandSpan(4.5)
: fListIn(""), fListOut("candbandclusterlist")
{
//
//  Purpose:    Default constructor.
//
//  Arguments:  n/a
//
//  Return:     n/a
//

  MSG("BubJobC",Msg::kDebug)
     << "BandClusterListModule::Constructor" << endl;

// Get Singleton instance of AlgFactory.
  AlgFactory &af = AlgFactory::GetInstance();

// Register (Algorithm, configset) as ("AlgMSTCluster", "default")
  af.Register("AlgMSTCluster", "default", "libBubbleSpeak.so");

// Register (Algorithm, configset) as ("AlgBandClusterList", "default")
  af.Register("AlgBandClusterList", "default", "libBubbleSpeak.so");

// Set AlgConfig parameters for ("AlgBandClusterList", "default")
  AlgHandle ah = af.GetAlgHandle("AlgBandClusterList", "default");
  AlgConfig &axbl = ah.GetAlgConfig();
  axbl.UnLockKeys();
  axbl.Set("BandSpan", 4.5);
  axbl.LockKeys();
}

//......................................................................

BandClusterListModule::~BandClusterListModule() 
{
//
//  Purpose:    Default destructor.
//
//  Arguments:  n/a
//
//  Return:     n/a
//

  MSG("BubJobC", Msg::kDebug)
     << "BandClusterListModule::Destructor" << endl;
}

//......................................................................

/*
void BandClusterListModule::BeginJob()
{
//
//  Purpose:    Method to register algorithms used by module.
//
//  Arguments:  n/a
//
//  Return:     n/a
//

  MSG("BubJobC", Msg::kVerbose)
     << "BandClusterListModule::BeginJob" << endl;

// Get Singleton instance of AlgFactory.
  AlgFactory &af = AlgFactory::GetInstance();

// Register (Algorithm, configset) as ("AlgMSTCluster", "default")
  af.Register("AlgMSTCluster", "default", "libBubbleSpeak.so");

// Register (Algorithm, configset) as ("AlgBandClusterList", "default")
  af.Register("AlgBandClusterList", "default", "libBubbleSpeak.so");

// Set AlgConfig parameters for ("AlgBandClusterList", "default")
  AlgHandle ah = af.GetAlgHandle("AlgBandClusterList", "default");
  AlgConfig &axbl = ah.GetAlgConfig();
  axbl.UnLockValues();
  axbl.Set("BandSpan", fBandSpan);
  axbl.LockValues();
  axbl.LockKeys();
  fBandSpan = 0;
}
*/

//......................................................................

JobCResult BandClusterListModule::Ana(const MomNavigator *mom)
{
//
//  Purpose:  Dummy method to analyze a reconstructed data fragment.
//
//  Arguments:
//    mom       in    MomNavigator from which to retrieve fragment.
//
//  Return:   No decision.
//
//  Note:     Prints result information for reconstructed cluster list.
//

  MSG("BubJobC", Msg::kDebug) << "BandClusterListModule::Ana" << endl;

// Find PrimaryCandidateRecord fragment in MOM.
  CandRecord *candrec = dynamic_cast<CandRecord *>
             (mom->GetFragment("CandRecord", "PrimaryCandidateRecord"));
  if (candrec == 0) {
    MSG("BubJobC", Msg::kWarning)
      << "No PrimaryCandidateRecord in MOM." << endl;
    return JobCResult::kError;                             // Fail event
  }

  CandMSTClusterListHandle *cblh=dynamic_cast<CandMSTClusterListHandle*>
 (candrec->FindCandHandle("CandMSTClusterListHandle", fListOut.Data()));
  if (!cblh) return JobCResult::kFailed;
  MSG("BubJobC", Msg::kInfo) << *cblh;
  return JobCResult::kAOK;
}

//......................................................................

JobCResult BandClusterListModule::Reco(MomNavigator *mom)
{
//
//  Purpose:  Reconstruct a list of CandMSTClusters using a
//            CandSliceList fragment.
//
//  Arguments:
//    mom       in    MomNavigator from which to retrieve fragment.
//
//  Return:   Pass if any clusters found.
//

   MSG("BubJobC", Msg::kDebug) << "BandClusterListModule::Reco" << endl;

// Find PrimaryCandidateRecord fragment in MOM.
   CandRecord *candrec = dynamic_cast<CandRecord *>
             (mom->GetFragment("CandRecord", "PrimaryCandidateRecord"));
   if (candrec == 0) {
      MSG("BubJobC", Msg::kWarning)
         << "No PrimaryCandidateRecord in MOM." << endl;
      return JobCResult::kError;                           // Fail event
   }

// Find CandSliceList fragment in PrimaryCandidateRecord.
   MSG("BubCand", Msg::kVerbose)
      << "CandSliceListHandle *cslh = (CandSliceListHandle *) "
      << "candrec->FindCandHandle(\"CandSliceListHandle\", "
      << "fListIn.Data());" << endl;
   CandSliceListHandle *cslh = dynamic_cast<CandSliceListHandle *>
       (candrec->FindCandHandle("CandSliceListHandle", fListIn.Data()));

// Build a CandMSTClusterList by making grouping together digit pairs
// in a CandSliceList.
   // Get Singleton instance of AlgFactory.
   MSG("BubJobC", Msg::kVerbose)
      << "AlgFactory &af = AlgFactory::GetInstance();" << endl;
   AlgFactory &af = AlgFactory::GetInstance();

   // Get an AlgHandle to AlgBandClusterList with "default" AlgConfig.
   MSG("BubJobC", Msg:: kVerbose)
      << "AlgHandle ablh = af.GetAlgHandle(\"AlgBandClusterList\","
      << "\"default\");" << endl;
   AlgHandle ablh = af.GetAlgHandle("AlgBandClusterList", "default");

   MSG("BubCand", Msg::kVerbose) << "CandContext cx(this);" << endl;
   CandContext cx(this, mom);

   MSG("BubCand", Msg::kVerbose) << "cx.SetDataIn(cslh);" << endl;
   cx.SetDataIn(cslh);

   MSG("BubCand", Msg::kVerbose) << "cx.SetCandRecord(candrec);" <<endl;
   cx.SetCandRecord(candrec);
   
   MSG("BubCand", Msg::kVerbose)
      << "CandMSTClusterListHandle cblh = "
      << "CandMSTClusterList::MakeCandidate(ablh, cx);" << endl;
   CandMSTClusterListHandle cblh =
                            CandMSTClusterList::MakeCandidate(ablh,cx);
   cblh.SetName(fListOut.Data());
   cblh.SetTitle( TString("Created by BandClusterListModule from ")
                     .Append(cslh->GetName()) );

// Check whether any CandMSTClusters found.
   if (cblh.GetNDaughters() == 0) return JobCResult::kFailed;

   MSG("BubCand", Msg::kVerbose)
      << "candrec->SecureCandHandle(cblh);" << endl;
   candrec->SecureCandHandle(cblh);
   return JobCResult::kPassed;
}

//......................................................................

const Registry &BandClusterListModule::DefaultConfig() const
{
//
//  Purpose:    Method to return default configuration.
//
//  Arguments:  n/a
//
//  Return:     Registry item containing default configuration.
//

  MSG("BubJobC", Msg::kDebug)
    << "BandClusterListModule::DefaultConfig" << endl;

  static Registry r;

  std::string name = this->JobCModule::GetName();
  name += ".config.default";
  r.SetName(name.c_str());
  r.UnLockValues();
  r.Set("ListIn",  "");
  r.Set("ListOut", "candbandclusterlist");
  r.Set("BandSpan", 4.5);
  r.LockValues();

  return r;
}

//......................................................................

void BandClusterListModule::Config(const Registry &r)
{
//
//  Purpose:  Configure the module given a registry.
//
//  Arguments:
//    r       in      Registry to use to configure the module.
//
//  Return:   n/a
//

  MSG("BubJobC",Msg::kDebug) << "BandClusterListModule::Config" << endl;

// Set input/output list names.
  const char *tmpcs = 0;
  if (r.Get("ListIn",  tmpcs))  fListIn  = tmpcs;
  if (r.Get("ListOut", tmpcs))  fListOut = tmpcs;

// Copy registry and remove non-AlgConfig keys.
  Registry rc(r);
  rc.UnLockKeys();
  rc.RemoveKey("ListIn");
  rc.RemoveKey("ListOut");
  rc.LockKeys();

/*
!!!! Now that Registry has stronger type checking, turn off type
!!!! checking in XxxModules to avoid warnings.

// Convert AlgConfig parameters to the correct type.
  int tmpi;
  if (rc.Get("BandSpan", tmpi)) {
    MSG("BubAlg", Msg::kWarning) << "BandClusterListModule::BandSpan "
      << "should be a Double_t and not an Int_t." << endl;
    rc.UnLockKeys();
    rc.UnLockValues();
    rc.RemoveKey("BandSpan");
    rc.Set("BandSpan", static_cast<Double_t>(tmpi));
    rc.LockValues();
    rc.LockKeys();
  }
*/

// Retrieve handle to AlgConfig for ("AlgBandClusterList", "default")
  AlgFactory &af = AlgFactory::GetInstance();
  AlgHandle ah = af.GetAlgHandle("AlgBandClusterList", "default");
  AlgConfig &axbl = ah.GetAlgConfig();

// Set AlgConfig parameters for ("AlgBandClusterList", "default")
  axbl.UnLockValues();
  axbl.Merge(rc);
  axbl.LockValues();
}

//......................................................................

/*
void BandClusterListModule::HandleCommand(JobCommand *command) 
{
//
//  Purpose:  Method to interpret module commands.
//
//  Arguments:
//    command   in    Command to interpret.
//
//  Return:   n/a
//
//  Commands implemented:
//    Set BandSpan    Set number of strip widths for central band
//

   MSG("BubJobC", Msg::kDebug)
      << "BandClusterListModule::HandleCommand" << endl;

   TString cmd = command->PopCmd();

// Set reconstruction parameters.
   if (cmd == "Set") {    // Set cut threshold.
      TString opt = command->PopOpt();
      if      (opt == "BandSpan") {
         Float_t bandspan = command->PopFloatOpt();
         if (!fBandSpan) {
            AlgFactory &af = AlgFactory::GetInstance();
            AlgHandle alh = af.GetAlgHandle("AlgBandClusterList",
                                            "default");
            AlgConfig &ac = alh.GetAlgConfig();
            ac.UnLockValues();
            ac.Set("BandSpan", bandspan);
            ac.LockValues();
         }
         else fBandSpan = bandspan;
      }
      else {
         MSG("BubJobC", Msg::kWarning)
            << "BandClusterListModule: Unrecognized option " << opt
            << endl;
      }
   }

// Invalid command.
   else {
      MSG("BubJobC", Msg::kWarning)
        << "BandClusterListModule: Unrecognized command " << cmd << endl;
   }
}
*/

//......................................................................

void BandClusterListModule::Help() 
{
//
//  Purpose:    Print help information for BandClusterListModule.
//
//  Arguments:  n/a
//
//  Return:     n/a
//

  MSG("BubJobC", Msg::kInfo)
    << "Help for 'BandClusterListModule':" << endl
    << " BandClusterListModule is a module to reconstruct" << endl
    << " clusters by fitting a straight track to strips with" << endl
    << " digits on both ends, defining a central band about" << endl
    << " this track, then including any strips within this band" << endl
    << " in the main cluster. All remaining strips are placed" << endl
    << " separate clusters. The clusters can be reconstructed" << endl
    << " by adding:" << endl
    << "     BandClusterListModule::Reco" << endl
    << " to the Path to be run." << endl
    << endl
    << "Commands implemented:" << endl
    << " /BandClusterListModule/Set BandSpan <value>" << endl
    << "     Set number of strip widths from the central track" << endl
    << "     that the strip position of a digit must lie for" << endl
    << "     the digit to be retained in the central cluster." << endl
    << endl;
}
