//
// Pibero Djawotho <pibero@indiana.edu>
// Indiana University
// Nov 18 2007
//

// ROOT
#include "TH1.h"
#include "TH2.h"

// STAR
#include "StEventTypes.h"
#include "StMuDSTMaker/COMMON/StMuTypes.hh"
#include "StEmcUtil/database/StBemcTables.h"
#include "StDaqLib/EMC/StEmcDecoder.h"
#include "StEmcPool/StBEMCPlots/BEMC_DSM_decoder.h"
//#include "StDaqLib/TRG/trgStructures2007.h"
#include "StDaqLib/TRG/trgStructures2008.h"

// Local
#include "StHeavyTrigger/Upsilon.hh"
#include "StHeavyTrigger/StHeavyTrigger.h"
#include "StHeavyTriggerMaker.h"

extern Upsilon ups;

ClassImp(StHeavyTriggerMaker);

void StHeavyTriggerMaker::Clear(Option_t* option)
{
//  memset(mTriggerData, 0, sizeof(TrgDataType2007));
  memset(mTriggerData, 0, sizeof(TrgDataType2008));
  memset(mAdc, 0, sizeof(mAdc));
  memset(mHT, 0, sizeof(mHT));
  memset(mTP, 0, sizeof(mTP));
  memset(mNumberOfMaskedTowers, 0, sizeof(mNumberOfMaskedTowers));

  if (mTrigger) delete mTrigger;

  StMaker::Clear(option);
}

int StHeavyTriggerMaker::InitRun(int runNumber)
{
  memset(mTowerStatus, 0, sizeof(mTowerStatus));
  memset(mPedestal, 0, sizeof(mPedestal));

  mBemcTables->loadTables(this);
  mEmcDecoder->SetDateTime(GetDate(), GetTime());

  // Load BEMC table
  for (int id = 1; id <= NTOWERS; ++id) {
    int rdo, crate, crateSeq;

    assert(mEmcDecoder->GetDaqIdFromTowerId(id, rdo));
    assert(mEmcDecoder->GetCrateFromTowerId(id, crate, crateSeq));

    mBemcTables->getTriggerTowerStatus(crate, crateSeq, mTowerStatus[rdo]);
    mBemcTables->getTriggerPedestal(crate, crateSeq, mPedestal[rdo]);
  }

  mBemcTables->getTriggerPedestalShift(mPedestalShift);

  for (int crate = 1; crate <= 30; ++crate) {
    for (int patch = 0; patch < 10; ++patch) {
      int triggerPatch;

      assert(mEmcDecoder->GetTriggerPatchFromCrate(crate, patch * 16, triggerPatch));

      mBemcTables->getTriggerHighTowerStatus(triggerPatch, mHighTowerStatus[triggerPatch]);
      mBemcTables->getTriggerPatchStatus(triggerPatch, mTriggerPatchStatus[triggerPatch]);
      mBemcTables->getTriggerBitConv(crate, patch, mBitConvMode[triggerPatch]);
      mBemcTables->getTriggerFormulaTag(crate, patch, mFormula[triggerPatch]);
      mBemcTables->getTriggerFormulaParameters(crate, patch, mParameters[triggerPatch]);
    }
  }

  // Dump BEMC table to file
  const char* filename = Form("bemcStatus.txt", runNumber);
  ofstream out(filename);
  assert(out);
  printLocalBemcTable(out);
  out.close();

  // Initialize L2 triggers
  //int userInt[] = { 18, 5, 10, 0, 25 };
  int userInt[] = { 18, 5, 10, 0, 25 };
  float userFloat[] = { 4.5 , 3.0 , 6.5 , 25, 0.0 };
  ups.init(runNumber, userInt, userFloat);

  return StMaker::InitRun(runNumber);
}

int StHeavyTriggerMaker::Init()
{
  mPedestalShift = 0;

  mBemcTables = new StBemcTables;
  mEmcDecoder = new StEmcDecoder;

//  mTriggerData = new TrgDataType2007;
  mTriggerData = new TrgDataType2008;
  mTrigger = 0;
//TrgDataType2007* mTriggerData;
  //unsigned short* mBemcData;

  mHighTowerFreq = new TH1F("highTowerFreq", "High Tower Trigger Corruption;Trigger Patch", 300, 0, 300);
  mTriggerPatchFreq = new TH1F("triggerPatchFreq", "Patch Sum Trigger Corruption;Trigger Patch", 300, 0, 300);

  mHighTowerCorr = new TH2F("highTowerCorr", "High Tower Trigger Corruption;DSM High Tower;Simulated High Tower", 64, 0, 64, 64, 0, 64);
  mTriggerPatchCorr = new TH2F("triggerPatchCorr", "Patch Sum Trigger Corruption;DSM Patch Sum;Simulated Patch Sum", 64, 0, 64, 64, 0, 64);

  mHighTowerAdc = new TH2F("highTowerAdc", "DSM L0 Input - High Tower;Trigger Patch;ADC", 300, 0, 300, 64, 0, 64);
  mTriggerPatchAdc = new TH2F("triggerPatchAdc", "DSM L0 Input - Patch Sum;Trigger Patch;ADC", 300, 0, 300, 64, 0, 64);

  return StMaker::Init();
}

int StHeavyTriggerMaker::Make()
{


  cout<<"I'm in HeavyTriggerMaker :: Make()"<<endl;

 //ups.run(mTriggerData, mBemcData);
  // Simulate FEE action
  for (int id = 1; id <= NTOWERS; ++id) {
    int rdo, patch;

    assert(mEmcDecoder->GetDaqIdFromTowerId(id, rdo));
    assert(mEmcDecoder->GetTriggerPatchFromTowerId(id, patch));

    if (!mHighTowerStatus[patch]) continue;
    if (!mTriggerPatchStatus[patch]) continue;

    if (!mTowerStatus[rdo]) {
      ++mNumberOfMaskedTowers[patch];
      continue;
    };

    mAdc[rdo] = StMuDst::muEmcCollection()->getTowerADC(id);
    int ped = getFEEpedestal(mPedestal[rdo], mPedestalShift);
    int adc6, adc8;
    simulateFEEaction(mAdc[rdo], ped, mBitConvMode[patch], adc6, adc8);
    if (adc6 > mHT[patch]) mHT[patch] = adc6;
    mTP[patch] += adc8;
  }

  // Simulate FEE LUT
  for (int patch = 0; patch < NPATCHES; ++patch) {
    if (!mHighTowerStatus[patch]) continue;
    if (!mTriggerPatchStatus[patch]) continue;

    int lut;
    int* par = mParameters[patch];
    simulateFEELUT(mTP[patch], mFormula[patch], par[0], par[1], par[2], par[3], par[4], par[5], mNumberOfMaskedTowers[patch], mPedestalShift, lut);
    mTP[patch] = lut;
  }

  mTrigger = new StHeavyTrigger(mHT, mTP, mTriggerData, mAdc);
  AddData(mTrigger);

  // QA
  StEmcTriggerDetector& emcTrig = StMuDst::event()->emcTriggerDetector();
  for (int patch = 0; patch < NPATCHES; ++patch) {
    int dsmHighTower = emcTrig.highTower(patch);
    int dsmTriggerPatch = emcTrig.patch(patch);

    if (dsmHighTower != mHT[patch]) {
      mHighTowerFreq->Fill(patch);
      mHighTowerCorr->Fill(mHT[patch], dsmHighTower);
    }
    else {
      mHighTowerAdc->Fill(patch, dsmHighTower);
    }

    if (dsmTriggerPatch != mTP[patch]) {
      mTriggerPatchFreq->Fill(patch);
      mTriggerPatchCorr->Fill(mTP[patch], dsmTriggerPatch);
    }
    else {
      mTriggerPatchAdc->Fill(patch, dsmTriggerPatch);
    }
  }

 //
  // call the trigger simulator
  //

  mTrigger->isTrigger(mTriggerId);
  cout<<"I'm leaving HeavyTriggerMaker :: Make()"<<endl;

  return kStOk;
}

int StHeavyTriggerMaker::FinishRun(int runNumber)
{
  ups.finish();

  return StMaker::InitRun(runNumber);
}

int StHeavyTriggerMaker::Finish()
{
  delete mBemcTables;
  delete mEmcDecoder;

  return kStOk;
}

void StHeavyTriggerMaker::printBemcTable(ostream& out)
{
  out << "##################################################################################\n";
  out << "# This plain text file contains the complete BEMC trigger configuration\n";
  out << "# Generated by the online BEMC trigger monitoring program on emc01.starp.bnl.gov\n";
  out << "# Timestamp: " << GetDateTime().AsSQLString() << '\n';
  out << "#\n";
  out << "# SoftId\tCrate\tCrate seq\tTower unmasked?\tPatch unmasked in HT?\tPatch unmasked in sum?\tPedestal\ttriggerPatch\n";

  for (int id = 1; id <= NTOWERS; ++id) {
    int crate, crateSeq, triggerPatch;
    int towerStatus, highTowerStatus, triggerPatchStatus;
    float pedestal;

    assert(mEmcDecoder->GetCrateFromTowerId(id, crate, crateSeq));
    assert(mEmcDecoder->GetTriggerPatchFromTowerId(id, triggerPatch));

    mBemcTables->getTriggerTowerStatus(crate, crateSeq, towerStatus);
    mBemcTables->getTriggerPedestal(crate, crateSeq, pedestal);
    mBemcTables->getTriggerHighTowerStatus(triggerPatch, highTowerStatus);
    mBemcTables->getTriggerPatchStatus(triggerPatch, triggerPatchStatus);

    out << "SoftId " << id << '\t' << crate << '\t' << crateSeq << '\t' << towerStatus << '\t' << highTowerStatus << '\t' << triggerPatchStatus << '\t' << pedestal << '\t' << triggerPatch << '\n';
  }

  out << "#\n";

  int pedestalShift;

  mBemcTables->getTriggerPedestalShift(pedestalShift);

  out << "TriggerPedestalShift " << pedestalShift << '\n';
  out << "#\n";

  out << "# triggerPatch\tCrate\tCrate patch\tUnmasked in HT?\tUnmasked in sum?\tBit conversion mode\tLUT formula and parameters\n";

  for (int crate = 1; crate <= 30; ++crate) {
    for (int patch = 0; patch < 10; ++patch) {
      int triggerPatch;
      int highTowerStatus, triggerPatchStatus;
      int bitConvMode, formula, parameters[6];

      assert(mEmcDecoder->GetTriggerPatchFromCrate(crate, patch * 16, triggerPatch));

      mBemcTables->getTriggerHighTowerStatus(triggerPatch, highTowerStatus);
      mBemcTables->getTriggerPatchStatus(triggerPatch, triggerPatchStatus);
      mBemcTables->getTriggerBitConv(crate, patch, bitConvMode);
      mBemcTables->getTriggerFormulaTag(crate, patch, formula);
      mBemcTables->getTriggerFormulaParameters(crate, patch, parameters);

      out << "triggerPatch " << triggerPatch << '\t' << crate << '\t' << patch << '\t'
	  << highTowerStatus << '\t'
	  << triggerPatchStatus << '\t'
	  << bitConvMode << '\t'
	  << formula << "\t"
	  << parameters[0] << '\t'
	  << parameters[1] << '\t'
	  << parameters[2] << '\t'
	  << parameters[3] << '\t'
	  << parameters[4] << '\t'
	  << parameters[5] << '\n';
    }
  }

  out << "# End of file\n";
  out << "##################################################################################" << endl;
}

void StHeavyTriggerMaker::printLocalBemcTable(ostream& out)
{
  out << "##################################################################################\n";
  out << "# This plain text file contains the complete BEMC trigger configuration\n";
  out << "# Generated by the online BEMC trigger monitoring program on emc01.starp.bnl.gov\n";
  out << "# Timestamp: " << GetDateTime().AsSQLString() << '\n';
  out << "#\n";
  out << "# SoftId\tCrate\tCrate seq\tTower unmasked?\tPatch unmasked in HT?\tPatch unmasked in sum?\tPedestal\ttriggerPatch\n";

  for (int id = 1; id <= NTOWERS; ++id) {
    int rdo, crate, crateSeq, triggerPatch;

    assert(mEmcDecoder->GetDaqIdFromTowerId(id, rdo));
    assert(mEmcDecoder->GetCrateFromTowerId(id, crate, crateSeq));
    assert(mEmcDecoder->GetTriggerPatchFromTowerId(id, triggerPatch));

    out << "SoftId " << id << '\t' << crate << '\t' << crateSeq << '\t' << mTowerStatus[rdo] << '\t' << mHighTowerStatus[triggerPatch] << '\t' << mTriggerPatchStatus[triggerPatch] << '\t' << mPedestal[rdo] << '\t' << triggerPatch << '\n';
  }

  out << "#\n";

  out << "TriggerPedestalShift " << mPedestalShift << '\n';
  out << "#\n";

  out << "# triggerPatch\tCrate\tCrate patch\tUnmasked in HT?\tUnmasked in sum?\tBit conversion mode\tLUT formula and parameters\n";

  for (int crate = 1; crate <= 30; ++crate) {
    for (int patch = 0; patch < 10; ++patch) {
      int triggerPatch;

      assert(mEmcDecoder->GetTriggerPatchFromCrate(crate, patch * 16, triggerPatch));

      out << "triggerPatch " << triggerPatch << '\t' << crate << '\t' << patch << '\t'
	  << mHighTowerStatus[triggerPatch] << '\t'
	  << mTriggerPatchStatus[triggerPatch] << '\t'
	  << mBitConvMode[triggerPatch] << '\t'
	  << mFormula[triggerPatch] << "\t"
	  << mParameters[triggerPatch][0] << '\t'
	  << mParameters[triggerPatch][1] << '\t'
	  << mParameters[triggerPatch][2] << '\t'
	  << mParameters[triggerPatch][3] << '\t'
	  << mParameters[triggerPatch][4] << '\t'
	  << mParameters[triggerPatch][5] << '\n';
    }
  }

  out << "# End of file\n";
  out << "##################################################################################" << endl;
}
