/*
 * 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.
 */


#ifndef _OWLPS_POSITIONING_POSUTIL_HH_
#define _OWLPS_POSITIONING_POSUTIL_HH_

class Measurement ;

#include <unordered_map>
#include <boost/algorithm/string/case_conv.hpp>
#include <stdint.h> // <cstdint> is not C++ 98 compliant

/// Utilitary class
class PosUtil
{
public:
  /// The speed of light, in m/s
  static const unsigned long LIGHT_SPEED = 299792458 ;

  /** @name Hashes */
  //@{
  template <class T> static void hash_combine(
    std::size_t &seed, const T &v) ;
  //@}

  /** @name Maths */
  //@{
  /// Returns the radian value of `degrees`
  static double deg2rad(const double degrees) ;
  /// Returns the degree value of `radians`
  static double rad2deg(const double radians) ;
  /// Checks if `value` is in the interval [center-width;center+width]
  static bool is_in_interval(const float center, const float bound,
                             const float value) ;
  //@}

  /** @name Measurements */
  //@{
  /// Mutually completes two Measurement lists with missing CPs
  static void complete_with_dummy_measurements(
    std::unordered_map<std::string, Measurement> &measurements1,
    std::unordered_map<std::string, Measurement> &measurements2) ;
  /// Computes the similarity of two Measurement lists
  static float similarity(
    std::unordered_map<std::string, Measurement> &measurements1,
    std::unordered_map<std::string, Measurement> &measurements2) ;
  //@}

  /** @name Wi-Fi */
  //@{
  /// Converts a Wi-Fi channel to the corresponding frequency in Hz
  static unsigned long wifi_channel_to_hz(const unsigned long &channel) ;
  //@}

  /** @name Strings */
  //@{
  static void to_upper(std::string &str) ;
  static std::string int_to_mac(const uint32_t source) ;
  //@}
} ;



/* *** Hashes *** */


template <class T> inline void PosUtil::
hash_combine(std::size_t &seed, const T &v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2) ;
}



/* *** Maths *** */


/**
 * This function checks if `value` belongs to the symmetrical interval
 * [center-bound;center+bound].
 *
 * @param center The center of the interval.
 * @param bound Half the width of the interval.
 * @param value The value to check the presence in the interval.
 *
 * @returns `true` if value belongs to the interval.
 * @returns `false` if value does not belong to the interval.
 */
inline bool PosUtil::
is_in_interval(const float center, const float bound, const float value)
{
  if (bound == 0)
    return value == center ;

  assert(bound > 0) ;
  float interval_min = center - bound ;
  float interval_max = center + bound ;
  return interval_min <= value && value <= interval_max ;
}



/* *** Strings *** */


inline void PosUtil::to_upper(std::string &str)
{
  boost::to_upper(str) ;
}


#ifdef NDEBUG
# define assert_uppercase(STR)
#else // NDEBUG
# define assert_uppercase(STR)                  \
  do {                                          \
    std::string str((STR)) ;                    \
    std::string str_up(str) ;                   \
    PosUtil::to_upper(str_up) ;                 \
    assert(str_up == str) ;                     \
  } while (0)
#endif // NDEBUG



#endif // _OWLPS_POSITIONING_POSUTIL_HH_
