// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/util/shins_util.h 3975 2022-06-14 18:34:48Z depa $


#pragma once

//#include <sstream>
#include <stdexcept>
//#include <typeinfo>
//#include <cstring>
//#include <cstdlib>
//#include <unistd.h>
#include <tr1/tuple>
//
//#include <boost/algorithm/string/classification.hpp>
//#include <boost/algorithm/string/predicate.hpp>
//#include <boost/algorithm/string/split.hpp>
#include <boost/asio.hpp>
//#include <boost/chrono.hpp>
//#include <boost/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
//#include <boost/typeof/typeof.hpp>
//#if defined BOOST_NO_CXX11_LAMBDAS
//#include <boost/lambda/lambda.hpp>
//#include <boost/lambda/bind.hpp>
//#include <boost/lambda/casts.hpp>
//#include <boost/ref.hpp>
//#endif
//
#include <Nice/Log.h>
#include <Nice/BuiltinSequences.h>
#include <Nice/Map/Point.h>
//
//#include "common_sharknir.h"
#include "convert.h"
////#include "threadsafe_queue.h"
#include "logger.h"
//#include "constants.h"
#include "defaults.hpp"
//#include "inotifier.h"

#include "shins_util_f.h"

namespace shins {
namespace util {
// template <typename T> class threadsafe_queue;

struct tagElementHeader
{
    std::string type;
    std::string nameid;
    int mechanical_id;
    float position1;
    float position2;
    int encoder1;
    int encoder2;
    int status;
    int intValue;
};

typedef typename std::map< std::string, std::map<std::string, std::tr1::tuple<int, int> > > mapPosType;
// typedef typename boost::shared_ptr<shins::util::threadsafe_queue<pcf::IndiProperty> > tsQueueIndiPropPtr;
// mapPosType mapMainNamedPos;

// ++++ METHODS ++++

std::vector< std::string > split_with_boost(const std::string& _str, const std::string& _strTokens);

std::map<std::string, std::string> build_cfg_files_map();

mapPosType get_main_named_pos_map_boost(const std::map<std::string, std::string>& _mapCfgFiles);

void io_service_thread(boost::shared_ptr< boost::asio::io_service > _ptrIoService);

std::map<std::string, int> initMap();

std::vector<std::string> getAliasesFromFile(const std::string& _strFileName, const std::string& _which);

boost::chrono::steady_clock::duration timer(const int& _movingDevs, const boost::chrono::steady_clock::duration& delay);

/** @brief      Returns value for environment variable
 *  @param[in]  _vecFloat  The vector float
 *  @return     { description_of_the_return_value } */
std::vector<int> reinterpret_float_to_int(const std::vector<float>& _vecFloat);
std::vector<int> uint_to_seqint(unsigned int sau);

std::string get_login();

int create_telemetry_dirs();


std::string get_env(const std::string& _var);


std::string seq_int_to_str(Nice::SeqInt seq_int, int halfsize = 10);

std::string seq_float_to_str(Nice::SeqFloat seq_float, int halfsize = 10);

std::string seq_double_to_str(std::vector<double> seq_double, int halfsize = 10);

std::map<std::string, std::tr1::tuple<double, double> > get_main_units_one_axe(const std::string & cfgFile);
std::map<std::string, std::tr1::tuple<double, double, double, double, double, double> > get_main_units_two_axes(const std::string & cfgFile);
std::map<std::string, double > get_named_positions_one_axe(const std::string & cfgFile);
std::map<std::string, Nice::Point > get_named_positions_two_axes(const std::string & cfgFile);
std::string get_alias_from_config(const std::string & cfgFile);

void os_log_banner(const std::string & _banner);

void debug_save_memory_block(const char * pBlock, size_t block_size, const char * pFilename);


// ++++++++++++++++++++++++++
// ++++ TEMPLATE METHODS ++++
// ++++++++++++++++++++++++++
template <typename T, typename M, typename K>
T get_value_from_map(const M& _map, const K& _key)
{
//    U6_LLOG("shins_util.h::" << __FUNCTION__);
    T value = T();
    BOOST_AUTO(it, _map.find(_key));
    if(it == _map.end())
    {
        std::stringstream log_msg;
        log_msg << "shins_util.h::" << __FUNCTION__ << " Key " << _key << " not in map!";
        W_LLOG(log_msg.str());
        std::invalid_argument err(log_msg.str());
//        U8_LLOG("");
        throw err;
    }
    else
    {
        value = convertStringToType<T>(it->second);
    }
//    U8_LLOG("");
    return value;
}


template <typename T, typename M, typename K>
T get_value_from_map_with_default(const M& _map, const K& _key, const T&defaultValue)
{
//    U6_LLOG("shins_util.h::" << __FUNCTION__);
    T value = T();
    BOOST_AUTO(it, _map.find(_key));
    if(it == _map.end())
    {
        W_LLOG("shins_util.h" << __FUNCTION__ << " Key " << _key << " not in map! Setting to default value " << defaultValue);
        value = defaultValue;
    }
    else
    {
        value = convertStringToType<T>(it->second);
    }
//    U8_LLOG("");
    return value;
}


template <typename T, typename R>
std::vector<R> reinterpret_T_to_R(const std::vector<T>& _vecT)
{
//    U6_LLOG("shins_util.h::" << __FUNCTION__);
    std::vector<R> vecR;
    // check _t is iterable
    // ... TBD

    vecR.resize(_vecT.size(), 0);

#if defined BOOST_NO_CXX11_LAMBDAS
    for (unsigned int i=0; i<_vecT.size(); i++)
    {
        std::memcpy(&vecR[i], &_vecT[i], sizeof(R));
    }
#else
    std::transform(vecR.begin(), vecR.end(), _vecT.begin(), vecR.begin(),
                   [](R& _n, const T& _t){
                std::memcpy(&_n, &_t, sizeof(_t));
                return _n;
            });
#endif
    // std::for_each(vecR.begin(), vecR.end(), std::cout << boost::lambda::_1 << "\n") ;
//    U8_LLOG("");
    return vecR;
};


    template <typename T> int sgn(T val) {
      return (T(0) < val) - (val < T(0));
  }

    struct SObContext
    {
        std::string defocus_lamp;
        std::string focus_lamp;
        std::string flat_field_lamp;
        std::string observation_block;
        std::string template_name;
        std::string template_id;
        std::string template_script;
        std::string template_time;
        std::string dpr_type;
        std::string info_obs_comm;
        std::string info_object;
        std::string info_partner;
        std::string info_observer;
        std::string info_pi_coi;
        std::string info_propid;
        std::string ncpa_file;
        std::string ncpa_rotation_status;
        std::string l_auth_ins_from_DD;
        std::string r_auth_ins_from_DD;
    };

    struct STcsPreset
    {
        std::string object_name;
        std::string target_coordsys;
        std::string equinox;
        std::string telescope_mode;
        std::string ao_mode;
        int binocular;
        float epoch;
        float objra;
        float objdec;
        float objmag;
        float pmra;
        float pmdec;
        float aora;
        float aodec;
        float aomag;
        float pmaora;
        float pmaodec;
        float gsra;
        float gsdec;
        float gsmag;
        float pmgsra;
        float pmgsdec;
    };


    template <typename T>
    bool getValue(std::string s, T & res)
    {
        std::stringstream valuestring(s);
        valuestring >> res;
        // std::ifstream::goodbit << suc::tilde << std::ifstream::eofbit << suc::tilde << std::ifstream::failbit <<  suc::tilde << std::ifstream::badbit
        return (valuestring.rdstate() & (std::ifstream::failbit | std::ifstream::badbit)) == 0;
    }


} // util namespace
} // shins namespace
