/*
 * 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 "trilaterationalgorithm.hh"
#include "minmax.hh"
#include "mobile.hh"
#include "configuration.hh"
#include "posexcept.hh"

using namespace std ;



/* *** Constructors *** */


TrilaterationAlgorithm::TrilaterationAlgorithm():
  request(nullptr)
{
  // Will be changed when other trilateration methods will be
  // implemented.

  if (! Configuration::is_configured("positioning.area-start") ||
      ! Configuration::is_configured("positioning.area-stop"))
    throw missing_configuration(
      "You want to use MinMax, but either positioning.area-start or"
      " positioning.area-stop is not defined!") ;

  Point3D minmax_start(
    Configuration::string_value("positioning.area-start")) ;
  Point3D minmax_stop(
    Configuration::string_value("positioning.area-stop")) ;

  trilateration_method = new MinMax(minmax_start, minmax_stop) ;
}


TrilaterationAlgorithm::~TrilaterationAlgorithm()
{
  delete trilateration_method ;
}



/* *** Operations *** */


double TrilaterationAlgorithm::
make_constant_term(const Measurement &measurement)
{
  assert(request) ;
  const Mobile *mobile = request->get_mobile() ;
  assert(mobile) ;
  const CapturePoint *cp = measurement.get_cp() ;
  assert(cp) ;

  return
    cp->friis_constant_term() +
    mobile->get_antenna_gain() +
    mobile->get_trx_power() ;
}


Result TrilaterationAlgorithm::compute(const Request &_request)
{
  request = &_request ;

  compute_cp_distance_circles() ;
  Point3D position(trilaterate()) ;

  return Result(request, name, position) ;
}


void TrilaterationAlgorithm::compute_cp_distance_circles()
{
  cp_distances.clear() ;

  const unordered_map<string, Measurement> &measurements =
    request->get_measurements() ;

  for (auto i = measurements.begin() ; i != measurements.end() ; ++i)
    cp_distances[i->second.get_cp()] = estimate_distance(i->second) ;
}
