void SDAMakePhysSignals::exec(){
	if(auto signal=dynamic_cast<const JPetRecoSignal*const>(getEvent())){
		JPetPhysSignal physSignal;
		physSignal.setRecoSignal(*signal);
		// NOTE: This module currently sets number of photoelectrons
		// equal to charge of JPetRecoSignal
		physSignal.setPhe(physSignal.getRecoSignal().getCharge() );
		fWriter->write(physSignal);
	}
}
void TaskD::exec()
{
  // A dummy analysis example:
  JPetPhysSignal currSignal = (JPetPhysSignal&) (*getEvent());
  
  // increment the counter of signals
  getStatistics().getCounter("No. initial signals")++;

  if (fSignals.empty()) {
    fSignals.push_back(currSignal);
  } else {
    if (fSignals[0].getTimeWindowIndex() == currSignal.getTimeWindowIndex()) {
      fSignals.push_back(currSignal);
    } else {
      getStatistics().getHisto1D("No. signals in TSlot").Fill(fSignals.size());
      saveHits(createHits(fSignals)); //create LORs from previously saved signals
      fSignals.clear();
      fSignals.push_back(currSignal);
    }
  }
}
void HitFinder::fillSignalsMap(JPetPhysSignal signal)
{
	auto scinId = signal.getPM().getScin().getID();
	if (signal.getPM().getSide() == JPetPM::SideA) {
		if (fAllSignalsInTimeWindow.find(scinId) != fAllSignalsInTimeWindow.end()) {
			fAllSignalsInTimeWindow.at(scinId).first.push_back(signal);
		} else {
			std::vector<JPetPhysSignal> sideA = {signal};
			std::vector<JPetPhysSignal> sideB;
			fAllSignalsInTimeWindow.insert(std::make_pair(scinId,
						std::make_pair(sideA, sideB)));
		}
	} else {
		if (fAllSignalsInTimeWindow.find(scinId) != fAllSignalsInTimeWindow.end()) {
			fAllSignalsInTimeWindow.at(scinId).second.push_back(signal);
		} else {
			std::vector<JPetPhysSignal> sideA;
			std::vector<JPetPhysSignal> sideB = {signal};
			fAllSignalsInTimeWindow.insert(std::make_pair(scinId,
						std::make_pair(sideA, sideB)));
		}
	}
}
/**
 * Method rewrites Reco Signal to Phys Signal.
 * Time of Signal set to time of the Leading Signal Channel at the lowest threshold.
 * Other fields are set to -1, quality fields set to 0.
 */
JPetPhysSignal SignalTransformer::createPhysSignal(const JPetRecoSignal& recoSignal)
{
  JPetPhysSignal physSignal;
  physSignal.setRecoSignal(recoSignal);
  physSignal.setPhe(-1.0);
  physSignal.setQualityOfPhe(0.0);
  physSignal.setQualityOfTime(0.0);
  physSignal.setRecoFlag(recoSignal.getRecoFlag());
  std::vector<JPetSigCh> leadingSigChVec = recoSignal.getRawSignal().getPoints(
    JPetSigCh::Leading, JPetRawSignal::ByThrValue
  );
  physSignal.setTime(leadingSigChVec.at(0).getValue());
  return physSignal;
}
vector<JPetHit> TaskC::createHits(const vector<JPetRawSignal>& signals)
{
  vector<JPetHit> hits;
  for (auto i = signals.begin(); i != signals.end(); ++i) {
    for (auto j = i; ++j != signals.end();) {
      if (i->getPM().getScin() == j->getPM().getScin()) {
        // found 2 signals from the same scintillator
        // wrap the RawSignal objects into RecoSignal and PhysSignal
        // for now this is just wrapping opne object into another
        // in the future analyses it will involve more logic like
        // reconstructing the signal's shape, charge, amplitude etc.
        JPetRecoSignal recoSignalA;
        JPetRecoSignal recoSignalB;
        JPetPhysSignal physSignalA;
        JPetPhysSignal physSignalB;
        // assign sides A and B properly
        if (
          (i->getPM().getSide() == JPetPM::SideA)
          && (j->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*i);
          recoSignalB.setRawSignal(*j);
        } else if (
          (j->getPM().getSide() == JPetPM::SideA)
          && (i->getPM().getSide() == JPetPM::SideB)
        ) {
          recoSignalA.setRawSignal(*j);
          recoSignalB.setRawSignal(*i);
        } else {
          // if two hits on the same side, ignore
          WARNING("TWO hits on the same scintillator side we ignore it");
          continue;
        }

        if ( recoSignalA.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;
        if ( recoSignalB.getRawSignal().getNumberOfPoints(JPetSigCh::Leading) < 4 ) continue;

        bool thresholds_ok = true;
        for (int i = 1; i <= 4; ++i) {
          if ( recoSignalA.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
          if ( recoSignalB.getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).count(i) < 1 ) {
            thresholds_ok = false;
          }
        }
        if (thresholds_ok == false) {
          continue;
        }

        physSignalA.setRecoSignal(recoSignalA);
        physSignalB.setRecoSignal(recoSignalB);
        auto leading_points_a = physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);
        auto leading_points_b = physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading);

        //skip signals with no information on 1st threshold
        // if(leading_points_a.count(1) == 0) continue;
        // if(leading_points_b.count(1) == 0) continue;

        physSignalA.setTime(leading_points_a.at(1));
        physSignalB.setTime(leading_points_b.at(1));


        JPetHit hit;
        hit.setSignalA(physSignalA);
        hit.setSignalB(physSignalB);
        hit.setScintillator(i->getPM().getScin());
        hit.setBarrelSlot(i->getPM().getScin().getBarrelSlot());

        physSignalA.setTime(physSignalA.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));
        physSignalB.setTime(physSignalB.getRecoSignal().getRawSignal().getTimesVsThresholdNumber(JPetSigCh::Leading).at(1));

        hit.setTime( 0.5 * ( hit.getSignalA().getTime() + hit.getSignalB().getTime()) );

        hits.push_back(hit);
        getStatistics().getCounter("No. found hits")++;
      }
    }
  }
  return hits;
}
JPetPhysSignal JPetSimplePhysSignalReco::createPhysSignal(JPetRecoSignal& recoSignal)
{
  // create a Phys Signal
  JPetPhysSignal physSignal;

  // use the values from Reco Signal to set the physical properties of signal
  // here, a dummy example - much more sophisticated procedures should go here
  physSignal.setPhe( recoSignal.getCharge() * 1.0 + 0.0 );
  physSignal.setQualityOfPhe(1.0);

  // in the previous module (C2) we have reconstructed one time at arbitrary
  // threshold - now we retrieve it by getting a map of times vs. thresholds,
  // and taking its first (and only) element by the begin() iterator. We get
  // an std::pair, where first is the threshold value, and second is time.
  double time = recoSignal.getRecoTimesAtThreshold().begin()->second;

  // -----------------------------------------------------------
  //
  // Estimate the time of the signal based on raw signal samples
  JPetRawSignal rawSignal = recoSignal.getRawSignal();

  if (rawSignal.getNumberOfPoints(JPetSigCh::Leading) >= 2
      && rawSignal.getNumberOfPoints(JPetSigCh::Trailing) >= 2) {
    // get number of points on leading edge
    int iNumPoints = rawSignal.getNumberOfPoints(JPetSigCh::Leading);

    std::vector<JPetSigCh> leadingPoints = rawSignal.getPoints(
        JPetSigCh::Leading, JPetRawSignal::ByThrValue);

    // create vectors
    vector<float> vecTime(iNumPoints);
    vector<float> vecVolt(iNumPoints);

    for (int j = 0; j < iNumPoints; j++) {
      vecTime(j) = leadingPoints.at(j).getValue();
      vecVolt(j) = leadingPoints.at(j).getThreshold();
    }

    // To evaluate time below parameters should be specified:

    // the parameter alfa of the below expression need to be specified:
    // vecVolt = a(t - vecTime)^(alfa);
    // Here alfa is fixed for the linear case.
    // Caution! alfa has to be an integer and positive value, negative values are ignored.
    int alfa = getAlpha();

    // thr_sel specifies the threshold level to read the time value,
    // and with thr_sel the below equation may be solved:
    // thr_sel = a(t - time)^(alfa);
    // Caution! thr_sel has to negative, and for positive values the program will set thr_sel equal to 0.
    float thr_sel = getThresholdSel();

    // The evaluation of time based on alfa and thr_sel
    assert(thr_sel < 0);
    assert(alfa > 0);
    time = static_cast<double>(polynomialFit(vecTime, vecVolt, alfa, thr_sel));
  }
  // ------------------------------------------------------------

  physSignal.setTime(time);
  physSignal.setQualityOfTime(1.0);

  // store the original JPetRecoSignal in the PhysSignal as a processing history
  physSignal.setRecoSignal(recoSignal);
  return physSignal;
}