/*
 *       File name:  aghermann/rk1968/rk1968.hh
 *         Project:  Aghermann
 *          Author:  Andrei Zavada <johnhommer@gmail.com>
 * Initial version:  2013-05-16
 *
 *         Purpose:  assisted score
 *
 *         License:  GPL
 */

#ifndef AGH_AGHERMANN_RK1968_RK1968_H_
#define AGH_AGHERMANN_RK1968_RK1968_H_

#include <float.h>
#include <string>

extern "C" {
#include <lua.h>
}

#include "aghermann/expdesign/dirlevel.hh"
#include "libsigproc/sigproc.hh"

using namespace std;

namespace agh {
namespace rk1968 {

class CScoreAssistant
  : public CStorablePPack {

    public:
        static constexpr const char* common_subdir = ".rk1968/";

        CScoreAssistant (const string& name_,
                         TExpDirLevel, CExpDesign&, const SExpDirLevelId&);
        explicit CScoreAssistant (const CScoreAssistant& rv)
              : CStorablePPack (common_subdir, rv.name + " (dup)", TExpDirLevel::transient, rv.ED, rv.level_id),
                status (0),
                script_contents (rv.script_contents),
                lua_state (nullptr)
                {}
        explicit CScoreAssistant (CExpDesign& ED_, const SExpDirLevelId& level_id_)
              : CStorablePPack (common_subdir, "(unnamed)", TExpDirLevel::transient, ED_, level_id_),
                status (0),
                lua_state (nullptr)
                {}

       ~CScoreAssistant ();

        CScoreAssistant&
        operator=( CScoreAssistant&& rv)
                {
                        CStorablePPack::operator=( rv);
                        script_contents = move(rv.script_contents);
                        lua_state = rv.lua_state;
                        rv.lua_state = nullptr;
                        return *this;
                }
        CScoreAssistant&
        operator=( const CScoreAssistant& rv)
                {
                        CStorablePPack::operator=( rv);
                        script_contents = rv.script_contents;
                        lua_state = nullptr;
                        return *this;
                }

        bool
        operator==( const CScoreAssistant& rv)
                {
                        return  CStorablePPack::operator==( rv) &&
                                script_contents == rv.script_contents;
                }

        enum TFlags { enofile = 1 << 0, ecompile = 1 << 1, };
        int status;

        // this one is not libconfig-based, so override these
        int load();
        int save() const;

        string script_contents;
        int compile();

        enum class TScoreErrors {
                ok,
                no_script,
                no_eeg_channels,
                lua_call_error,
                script_error,
        };
        static const char*
        score_error_s( TScoreErrors x)
                {
                        switch ( x ) {
                        case TScoreErrors::ok:                         return "OK";
                        case TScoreErrors::no_script:                  return "No script compiled";
                        case TScoreErrors::no_eeg_channels:            return "No EEG channels";
                        case TScoreErrors::lua_call_error:             return "Lua script call failed";
                        case TScoreErrors::script_error:               return "Script signalled error";
                        default:                                       return "(unknown error code)";
                        }
                }
        TScoreErrors
        score( agh::SEpisode&, int* pages_scored_p);

    // private:
    //     friend extern "C" int agh::rk1968::host_get_data( lua_State*);
    //     friend extern "C" int agh::rk1968::host_mark_page( lua_State*);
        agh::SEpisode*
                sepisodep;
        string  specific_error;

    private:
        void lua_init();
        lua_State* lua_state;  // mind reentrancy
};






template <typename T>
pair<T, size_t>
emg_steady_tone( const sigproc::SSignalRef<T>& V, size_t steady_secs, double max_dev_factor)
{
        // static const double env_scope = 1.;
        // static const double dt = 1.;
        // static const double range_min = 0.;
        // static const size_t bins = 20;
        // const double binsize =
        // sigproc::envelope_breadth_histogram(
        //         sigref, env_scope, dt,
        /// take it easy

        if ( unlikely (steady_secs < 1) )
                return {NAN, (size_t)-1};

        // examine 1-sec intervals until a length of, say, 10 sec is seen steady enough
        valarray<T> E;
        {
                valarray<T> env_u, env_l;
                sigproc::envelope( V, 1., 1., &env_l, &env_u);
                E.resize( env_u.size());
                E = env_u - env_l;
        }

        for ( size_t t = 0; t + 1 + steady_secs < E.size(); ++t ) {
                auto ma = valarray<T> {E[slice(t, steady_secs, 1)]}.sum() / steady_secs;
                if ( fabs(E[t] - ma) / ma > max_dev_factor )
                        continue;
                return {ma, t};
        }
        return {NAN, (size_t)-1};
}


} // namespace rk1968
} // namespace agh

#endif

// Local Variables:
// Mode: c++
// indent-tabs-mode: nil
// tab-width: 8
// c-basic-offset: 8
// End:
