/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include "apps-precomp.h"  // Precompiled headers
//

#include <mrpt/containers/stl_containers_utils.h>
#include <mrpt/obs/CObservationGasSensors.h>

#include "rawlog-edit-declarations.h"

using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace mrpt::apps;
using namespace std;
using namespace mrpt::io;

// ======================================================================
//		op_export_enose_txt
// ======================================================================
DECLARE_OP_FUNCTION(op_export_enose_txt)
{
  // A class to do this operation:
  class CRawlogProcessor_ExportENOSE_TXT : public CRawlogProcessorOnEachObservation
  {
   protected:
    string m_inFile;

    map<string, FILE*> lstFiles;
    string m_filPrefix;

   public:
    size_t m_entriesSaved;

    // Default Constructor
    CRawlogProcessor_ExportENOSE_TXT(
        CFileGZInputStream& in_rawlog, TCLAP::CmdLine& cmdline, bool Verbose) :
        CRawlogProcessorOnEachObservation(in_rawlog, cmdline, Verbose), m_entriesSaved(0)
    {
      getArgValue<string>(cmdline, "input", m_inFile);

      m_filPrefix = extractFileDirectory(m_inFile) + extractFileName(m_inFile);
    }

    // Return false on any error.
    bool processOneObservation(CObservation::Ptr& o) override
    {
      if (!IS_CLASS(*o, CObservationGasSensors)) return true;

      const CObservationGasSensors* obs = dynamic_cast<CObservationGasSensors*>(o.get());

      auto it = lstFiles.find(obs->sensorLabel);

      FILE* f_this;

      if (it == lstFiles.end())  // A new file for this sensorlabel??
      {
        const std::string fileName =
            m_filPrefix + string("_") +
            fileNameStripInvalidChars(
                obs->sensorLabel.empty() ? string("ENOSE") : obs->sensorLabel) +
            string(".txt");

        VERBOSE_COUT << "Writing e-nose TXT file: " << fileName << endl;

        f_this = lstFiles[obs->sensorLabel] = os::fopen(fileName.c_str(), "wt");
        if (!f_this) THROW_EXCEPTION_FMT("Cannot open output file for write: %s", fileName.c_str());

        // The first line is a description of the columns:
        //------------------------------------------------
        // Time:
        ::fprintf(f_this, "%% %13s ", "Time");

        // For each E-nose (if more than one)
        for (size_t j = 0; j < obs->m_readings.size(); j++)
        {
          // Temperature
          ::fprintf(f_this, " Temp%u ", static_cast<unsigned int>(j));

          // For each sensor on the E-nose
          for (size_t k = 0; k < obs->m_readings[j].readingsVoltage.size(); k++)
            ::fprintf(
                f_this, " S%u_%u ", static_cast<unsigned int>(j), static_cast<unsigned int>(k));
        }
        ::fprintf(f_this, "\n");
      }
      else
        f_this = it->second;

      // For each entry in this sequence: Compute the timestamp and save
      // all values:
      ASSERT_(obs->timestamp != INVALID_TIMESTAMP);
      TTimeStamp t = obs->timestamp;

      double sampleTime = mrpt::Clock::toDouble(t);

      // Time:
      ::fprintf(f_this, "%14.4f ", sampleTime);

      // For each E-nose (if more than one)
      for (const auto& m_reading : obs->m_readings)
      {
        // Temperature
        float temp = 0.0;
        if (m_reading.hasTemperature == true) temp = m_reading.temperature;
        ::fprintf(f_this, "%3.4f ", temp);

        // For each sensor on the E-nose
        mrpt::containers::printSTLContainer(m_reading.readingsVoltage);
      }

      ::fprintf(f_this, "\n");
      m_entriesSaved++;
      return true;  // All ok
    }

    // Destructor: close files and generate summary files:
    ~CRawlogProcessor_ExportENOSE_TXT()
    {
      for (auto it = lstFiles.begin(); it != lstFiles.end(); ++it)
      {
        os::fclose(it->second);
      }

      // Save the joint file:
      // -------------------------
      VERBOSE_COUT << "Number of different E-nose sensorLabels  : " << lstFiles.size() << endl;

      lstFiles.clear();
    }  // end of destructor
  };

  // Process
  // ---------------------------------
  CRawlogProcessor_ExportENOSE_TXT proc(in_rawlog, cmdline, verbose);
  proc.doProcessRawlog();

  // Dump statistics:
  // ---------------------------------
  VERBOSE_COUT << "Time to process file (sec)        : " << proc.m_timToParse << "\n";
  VERBOSE_COUT << "Number of records saved           : " << proc.m_entriesSaved << "\n";
}
