/**
 * Adds the zero-offset of the chopper to the slit times
 *
 * @param chopper :: PoldiAbstractChopper with slit times, not corrected with zero-offset
 * @return vector with zero-offset-corrected chopper slit times
 */
std::vector<double> PoldiSpectrumDomainFunction::getChopperSlitOffsets(const PoldiAbstractChopper_sptr &chopper)
{
    const std::vector<double> &chopperSlitTimes = chopper->slitTimes();
    std::vector<double> offsets;
    offsets.reserve(chopperSlitTimes.size());
    for(std::vector<double>::const_iterator time = chopperSlitTimes.begin(); time != chopperSlitTimes.end(); ++time) {
        offsets.push_back(*time + chopper->zeroOffset());
    }

    return offsets;
}
/**
 * Adds the zero-offset of the chopper to the slit times
 *
 * @param chopper :: PoldiAbstractChopper with slit times, not corrected with
 *                   zero-offset
 * @return vector with zero-offset-corrected chopper slit times
 */
std::vector<double> PoldiSpectrumDomainFunction::getChopperSlitOffsets(
    const PoldiAbstractChopper_sptr &chopper) {
  const std::vector<double> &chopperSlitTimes = chopper->slitTimes();
  std::vector<double> offsets;
  offsets.reserve(chopperSlitTimes.size());
  for (double chopperSlitTime : chopperSlitTimes) {
    offsets.push_back(chopperSlitTime + chopper->zeroOffset());
  }

  return offsets;
}
void PoldiAutoCorrelation5::logConfigurationInformation(
    boost::shared_ptr<PoldiDeadWireDecorator> cleanDetector,
    PoldiAbstractChopper_sptr chopper) {
  if (cleanDetector && chopper) {
    g_log.information()
        << "____________________________________________________ " << std::endl;
    g_log.information()
        << "_Poldi  chopper conf ------------------------------  " << std::endl;
    g_log.information() << "_Poldi -     Chopper speed:   "
                        << chopper->rotationSpeed() << " rpm" << std::endl;
    g_log.information() << "_Poldi -     Number of slits: "
                        << chopper->slitPositions().size() << std::endl;
    g_log.information() << "_Poldi -     Cycle time:      "
                        << chopper->cycleTime() << " µs" << std::endl;
    g_log.information() << "_Poldi -     Zero offset:     "
                        << chopper->zeroOffset() << " µs" << std::endl;
    g_log.information() << "_Poldi -     Distance:        "
                        << chopper->distanceFromSample() << " mm" << std::endl;

    if (g_log.is(Poco::Message::PRIO_DEBUG)) {
      for (size_t i = 0; i < chopper->slitPositions().size(); ++i) {
        g_log.information() << "_Poldi -     Slits: " << i
                            << ": Position = " << chopper->slitPositions()[i]
                            << "\t Time = " << chopper->slitTimes()[i] << " µs"
                            << std::endl;
      }
    }

    g_log.information()
        << "_Poldi  detector conf ------------------------------  "
        << std::endl;
    g_log.information() << "_Poldi -     Element count:     "
                        << cleanDetector->elementCount() << std::endl;
    g_log.information() << "_Poldi -     Central element:   "
                        << cleanDetector->centralElement() << std::endl;
    g_log.information() << "_Poldi -     2Theta(central):   "
                        << cleanDetector->twoTheta(199) / M_PI * 180.0 << "°"
                        << std::endl;
    g_log.information() << "_Poldi -     Distance(central): "
                        << cleanDetector->distanceFromSample(199) << " mm"
                        << std::endl;

    std::set<int> deadWires = cleanDetector->deadWires();
    g_log.information() << "_Poldi -     Number of dead wires: "
                        << deadWires.size() << std::endl;
    g_log.information() << "_Poldi -     Wire indices: ";
    for (std::set<int>::const_iterator dw = deadWires.begin();
         dw != deadWires.end(); ++dw) {
      g_log.information() << *dw << " ";
    }
    g_log.information() << std::endl;
  }
}
/**
 * Initializes chopper offsets and time transformer
 *
 * In this method, the instrument dependent parameter for the calculation are
 * setup, so that a PoldiTimeTransformer is available to transfer parameters to
 * the time domain using correct factors etc.
 *
 * @param poldiInstrument :: Valid PoldiInstrumentAdapter
 */
void PoldiSpectrumDomainFunction::initializeInstrumentParameters(
    const PoldiInstrumentAdapter_sptr &poldiInstrument) {
  m_timeTransformer = boost::make_shared<PoldiTimeTransformer>(poldiInstrument);
  m_chopperSlitOffsets = getChopperSlitOffsets(poldiInstrument->chopper());

  if (!poldiInstrument) {
    throw std::runtime_error("No valid POLDI instrument.");
  }

  m_2dHelpers.clear();

  PoldiAbstractDetector_sptr detector = poldiInstrument->detector();
  PoldiAbstractChopper_sptr chopper = poldiInstrument->chopper();

  std::pair<double, double> qLimits = detector->qLimits(1.1, 5.0);

  double dMin = Conversions::qToD(qLimits.second);
  double dMax = Conversions::dToQ(qLimits.first);

  for (int i = 0; i < static_cast<int>(detector->elementCount()); ++i) {
    double sinTheta = sin(detector->twoTheta(i) / 2.0);
    double distance =
        detector->distanceFromSample(i) + chopper->distanceFromSample();
    double deltaD = Conversions::TOFtoD(m_deltaT, distance, sinTheta);

    Poldi2DHelper_sptr curr = boost::make_shared<Poldi2DHelper>();
    curr->setChopperSlitOffsets(distance, sinTheta, deltaD,
                                m_chopperSlitOffsets);
    curr->setDomain(dMin, dMax, deltaD);
    curr->deltaD = deltaD;
    curr->minTOFN = static_cast<int>(
        Conversions::dtoTOF(dMin, distance, sinTheta) / m_deltaT);
    curr->setFactors(m_timeTransformer, static_cast<size_t>(i));

    m_2dHelpers.push_back(curr);
  }
}