/*
 * This file is part of the Owl Positioning System (OwlPS) project.
 * It is subject to the copyright notice and license terms in the
 * COPYRIGHT.t2t file found in the top-level directory of this
 * distribution and at
 *   https://code.lm7.fr/mcy/owlps/src/master/COPYRIGHT.t2t
 * No part of the OwlPS Project, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms
 * contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
 * distributed along with this file, either separately or by replacing
 * this notice by the COPYRIGHT.t2t file's contents.
 */


#include "inputdatareader.hh"
#include "capturepointsreadercsv.hh"
#include "mobilesreadercsv.hh"
#include "topologyreadercsv.hh"
#include "inputcsv.hh"
#include "calibrationrequest.hh"
#include "configuration.hh"
#include "posexcept.hh"
#include "stock.hh"

#include <iostream>

using namespace std ;



/* *** Constructors *** */


InputDataReader::InputDataReader()
{
  read_access_points() ;
  read_mobiles() ;
  read_topology() ;
  read_reference_points() ;
}


InputDataReader::~InputDataReader()
{
  for (auto i = reference_points_media.begin() ;
       i != reference_points_media.end() ; ++i)
    delete *i ;
  reference_points_media.clear() ;
}



/* *** Access points *** */


void InputDataReader::read_access_points()
{
  if (! Configuration::is_configured("data-input.cp-medium"))
    return ;

  initialise_access_points_media() ;

  if (Configuration::is_configured("verbose"))
    cerr << Stock::nb_cps() << " capture points stored.\n" ;
}


void InputDataReader::initialise_access_points_media()
{
  const vector<string> &media_names =
    Configuration::string_vector_value("data-input.cp-medium") ;

  for (auto i = media_names.begin() ; i != media_names.end() ; ++i)
    {
      if (*i == "CSV")
        initialise_access_points_csv() ;

      else
        throw bad_configuration(
          "Access points input medium type unknown \""+ *i +"\"") ;
    }
}


void InputDataReader::initialise_access_points_csv()
{
  if (! Configuration::is_configured("data-input.cp-csv-file"))
    throw missing_configuration(
      "No input CSV file specified for capture points") ;

  CapturePointsReaderCSV(
    Configuration::string_value("data-input.cp-csv-file")) ;
}



/* *** Mobiles *** */


void InputDataReader::read_mobiles()
{
  if (! Configuration::is_configured("data-input.mobile-medium"))
    return ;

  initialise_mobiles_media() ;

  if (Configuration::is_configured("verbose"))
    cerr << Stock::nb_mobiles() << " mobiles stored.\n" ;
}


void InputDataReader::initialise_mobiles_media()
{
  const vector<string> &media_names =
    Configuration::string_vector_value("data-input.mobile-medium") ;

  for (auto i = media_names.begin() ; i != media_names.end() ; ++i)
    {
      if (*i == "CSV")
        initialise_mobiles_csv() ;

      else
        throw bad_configuration(
          "Mobiles' input medium type unknown \""+ *i +"\"") ;
    }
}


void InputDataReader::initialise_mobiles_csv()
{
  if (! Configuration::is_configured("data-input.mobile-csv-file"))
    throw missing_configuration(
      "No input CSV file specified for mobiles") ;

  MobilesReaderCSV(
    Configuration::string_value("data-input.mobile-csv-file")) ;
}



/* *** Topology *** */


void InputDataReader::read_topology()
{
  if (! Configuration::is_configured("data-input.topology-medium"))
    return ;

  initialise_topology_media() ;

  if (Configuration::is_configured("verbose"))
    {
      cerr
          << Stock::nb_buildings() << " buildings stored.\n"
          << Stock::nb_waypoints() << " waypoints stored.\n" ;
    }
}


void InputDataReader::initialise_topology_media()
{
  const vector<string> &media_names =
    Configuration::string_vector_value("data-input.topology-medium") ;

  for (auto i = media_names.begin() ; i != media_names.end() ; ++i)
    {
      if (*i == "CSV")
        initialise_topology_csv() ;

      else
        throw bad_configuration(
          "Topology input medium type unknown \""+ *i +"\"") ;
    }
}


void InputDataReader::initialise_topology_csv()
{
  if (! Configuration::is_configured("data-input.areas-csv-file"))
    throw missing_configuration(
      "No topology input CSV file specified for areas") ;

  if (! Configuration::is_configured("data-input.waypoints-csv-file"))
    throw missing_configuration(
      "No topology input CSV file specified for waypoints") ;

  TopologyReaderCSV(
    Configuration::string_value("data-input.areas-csv-file"),
    Configuration::string_value("data-input.waypoints-csv-file")) ;
}



/* *** Reference points *** */


void InputDataReader::read_reference_points()
{
  if (! Configuration::is_configured("data-input.reference-points-medium"))
    return ;

  initialise_reference_points_media() ;
  read_from_reference_points_media() ;

  if (Configuration::is_configured("verbose"))
    cerr
        << Stock::nb_calibration_requests()
        << " calibration requests stored, in\n"
        << Stock::nb_reference_points() << " reference points.\n" ;

}


void InputDataReader::initialise_reference_points_media()
{
  const vector<string> &media_names =
    Configuration::string_vector_value("data-input.reference-points-medium") ;

  for (auto i = media_names.begin() ; i != media_names.end() ; ++i)
    {
      if (*i == "CSV")
        initialise_reference_points_csv() ;

      else
        throw bad_configuration(
          "Reference points input medium type unknown \""+ *i +"\"") ;
    }
}


void InputDataReader::initialise_reference_points_csv()
{
  if (! Configuration::is_configured("data-input.reference-points-csv-file"))
    throw missing_configuration(
      "No reference points input CSV file is configured") ;

  reference_points_media.push_back(
    new InputCSV(
      Configuration::string_value("data-input.reference-points-csv-file"))) ;
}


void InputDataReader::read_from_reference_points_media()
{
  for (auto i = reference_points_media.begin() ;
       i != reference_points_media.end() ; ++i)
    {
      while (! (*i)->eof())
        {
          const Request &request = (*i)->get_next_request() ;

          if (! request)
            continue ;

          CalibrationRequest *calibration_request =
            dynamic_cast<CalibrationRequest*>(
              const_cast<Request*>(&request)) ;
          if (!calibration_request)
            cerr << "Warning! Invalid calibration request at line "
                 << (*i)->get_current_line_nb() << endl ;
          else
            Stock::store_calibration_request(*calibration_request) ;
        }
    }
}
