/*
 *       File name:  aghermann/ui/sf/channel.hh
 *         Project:  Aghermann
 *          Author:  Andrei Zavada <johnhommer@gmail.com>
 * Initial version:  2013-09-07
 *
 *         Purpose:  scoring facility channel representation
 *
 *         License:  GPL
 */

#ifndef AGH_AGHERMANN_UI_SF_CHANNEL_H_
#define AGH_AGHERMANN_UI_SF_CHANNEL_H_

#include <forward_list>
#include <list>
#include <string>

#include <cairo/cairo.h>

#include "common/alg.hh"
#include "common/config-validate.hh"
#include "libsigproc/forward-decls.hh"
#include "libsigfile/forward-decls.hh"
#include "libmetrics/page-metrics-base.hh"
#include "libmetrics/bands.hh"
#include "aghermann/artifact-detection/forward-decls.hh"
#include "aghermann/patterns/patterns.hh"
#include "aghermann/expdesign/forward-decls.hh"
#include "aghermann/expdesign/recording.hh"

#include "sf.hh"

#if HAVE_CONFIG_H && !defined(VERSION)
#  include "config.h"
#endif


using namespace std;

namespace agh {
namespace ui {

struct SScoringFacility::SChannel {

        DELETE_DEFAULT_METHODS (SChannel);

        bool operator==( const string&) const;
        bool operator==( const SChannel&) const;

      // references to CExpDesign objects we represent
        agh::CRecording&
                crecording;
        const sigfile::SChannel&
                schannel;
        sigfile::SFilterPack&
                filters;
        list<sigfile::SAnnotation>&
                annotations;
        sigfile::SArtifacts&
                artifacts;

      // shortcuts
        int
        h() const
                { return crecording.h(); }
        const char*
        name() const
                { return schannel.name(); }
        sigfile::SChannel::TType
        type() const
                { return schannel.type(); }
        size_t n_samples() const;
        size_t samplerate() const;

      // parent
        SScoringFacility&
                _p;

      // signal waveforms, cached here
        valarray<TFloat>
                signal_original,
                signal_filtered,
                signal_reconstituted;  // while it's hot
        void get_signal_original();
        void get_signal_filtered();

      // filters
        bool have_low_pass() const;
        bool have_high_pass() const;
        bool have_notch_filter() const;

      // artifacts
        float percent_dirty;
        float
        calculate_dirty_percent();

        void
        detect_artifacts( const agh::ad::SComprehensiveArtifactDetectionPPack&);

      // annotations
        list<sigfile::SAnnotation*>
        in_annotations( double time) const;

      // signal metrics
        agh::pattern::SPatternPPack<TFloat>
                pattern_params;

        sigproc::SCachedLowPassCourse<TFloat>
                signal_lowpass;
        sigproc::SCachedBandPassCourse<TFloat>
                signal_bandpass;
        sigproc::SCachedEnvelope<TFloat>
                signal_envelope;
        sigproc::SCachedDzcdf<TFloat>
                signal_dzcdf;
        void
        drop_cached_signal_properties()
                {
                        signal_lowpass.drop();
                        signal_bandpass.drop();
                        signal_envelope.drop();
                        signal_dzcdf.drop();
                }

      // profiles
        // psd
        struct SProfilePSD {
                valarray<TFloat>
                        course;
                double  from, upto;
                double  display_scale; // saved via libconfig, requiring it to be double
                array<valarray<TFloat>, metrics::TBand::TBand_total>
                        course_in_bands;
                size_t  focused_band,
                        uppermost_band;
        };
        void get_psd_course();
        void get_psd_in_bands();
        SProfilePSD
                psd;
        // swu
        struct SProfileSWU {
                valarray<TFloat>
                        course;
                double  f0;
                double  display_scale;
        };
        void get_swu_course();
        SProfileSWU
                swu;
        // mc
        struct SProfileMC {
                valarray<TFloat>
                        course;
                double  display_scale;
                double  f0;
        };
        SProfileMC
                mc;
        void get_mc_course();

        tuple<metrics::TType, valarray<TFloat>&>
        which_profile( metrics::TType);

        void update_profile_display_scales();

      // spectrum
        valarray<TFloat>
                spectrum;  // per page, is volatile
        float   spectrum_upper_freq;
        unsigned
                spectrum_bins,
                last_spectrum_bin;
        void get_spectrum(); // at current page
        void get_spectrum( size_t p);

      // raw profile, histogram, steady tone for EMG
        static constexpr double raw_profile_dt = 1.;
        valarray<TFloat>
                raw_profile;
        void
        get_raw_profile();

        TFloat  emg_steady_tone;
        valarray<size_t>
                histogram;
        static const size_t hist_bins = 20;
        double  hist_range_min,
                hist_binsize;

      // region
        void mark_region_as_artifact( bool do_mark);
        void mark_region_as_annotation( const string&, sigfile::SAnnotation::TType);
        void mark_region_as_pattern();

      // ctor, dtor
        SChannel( agh::CRecording& r, SScoringFacility&, size_t y, int seq);

        double  zeroy;
        bool operator<( const SChannel&) const;

        double  signal_display_scale;

        // saved flags
        bool    hidden,
                draw_zeroline,
                draw_original_signal,
                draw_filtered_signal,
                zeromean_original,
                zeromean_filtered,
                draw_psd,
                draw_swu,
                draw_mc,
                draw_emg,
                draw_psd_bands,
                autoscale_profile,
                draw_spectrum,
                resample_signal,
                resample_power,
                draw_selection_course,
                draw_selection_envelope,
                draw_selection_dzcdf,
                draw_phasic_spindle,
                draw_phasic_Kcomplex,
                draw_phasic_eyeblink,
                draw_emg_steady_tone;
        bool    discard_marked,
                apply_reconstituted;

        agh::confval::CConfigKeys
                config;

        void update_channel_menu_items( double x);
        void update_power_menu_items();
        void selectively_enable_selection_menu_items();

      // selection and marquee
        float   marquee_mstart,
                marquee_mend,        // in terms of event->x
                marquee_start,
                marquee_end;         // set on button_release
        double  selection_start_time,
                selection_end_time;  // in seconds
        size_t  selection_start,
                selection_end;       // in samples
        TFloat  selection_SS,
                selection_SU;
        size_t marquee_to_selection();
        void put_selection( size_t a, size_t e);
        void put_selection( double a, double e);
    private:
        void _put_selection();

    public:
        float spp() const;
        float fine_line() const;
        int sample_at_click( double) const;

        GtkMenuItem
                *menu_item_when_hidden;

      // comprehensive draw
        void draw_for_montage( const string& fname, int width, int height); // to a file
        void draw_for_montage( cairo_t*); // to montage

    protected:
        void draw_page( cairo_t*, int wd, float zeroy, // writers to an svg file override zeroy (with 0)
                        bool draw_marquee) const;
        void draw_overlays( cairo_t*, int wd, float zeroy) const;

      // strictly draw the signal waveform bare
      // (also used as such in some child dialogs)
        void draw_signal_original( size_t width, int vdisp, cairo_t *cr) const
                {
                        draw_signal( signal_original, width, vdisp, cr);
                }
        void draw_signal_filtered( size_t width, int vdisp, cairo_t *cr) const
                {
                        draw_signal( signal_filtered, width, vdisp, cr);
                }
        friend class SScoringFacility;
        void draw_signal_reconstituted( size_t width, int vdisp, cairo_t *cr) const
                {
                        draw_signal( signal_reconstituted, width, vdisp, cr);
                }
      // generic draw_signal wrapper
        void draw_signal( const valarray<TFloat>& signal,
                          size_t width, int vdisp, cairo_t *cr) const;
};

inline bool
SScoringFacility::SChannel::
operator==( const string& _name) const
{
        return _name == name();
}
// inline bool
// SScoringFacility::SChannel::
// operator==( const SChannel& rv) const
// {
//         return name == rv.name;
// }


inline bool
SScoringFacility::SChannel::
have_low_pass() const
{
        return isfinite(filters.low_pass_cutoff)
                && filters.low_pass_cutoff > 0.
                && filters.low_pass_order > 0;
}

inline bool
SScoringFacility::SChannel::
have_high_pass() const
{
        return isfinite(filters.high_pass_cutoff)
                && filters.high_pass_cutoff > 0.
                && filters.high_pass_order > 0;
}
inline bool
SScoringFacility::SChannel::
have_notch_filter() const
{
        return filters.notch_filter != sigfile::SFilterPack::TNotchFilter::none;
}

inline size_t
SScoringFacility::SChannel::
n_samples() const
{
        return signal_filtered.size();
}


inline bool
SScoringFacility::SChannel::
operator<( const SChannel& rv) const
{
        return zeroy < rv.zeroy;
}


inline float
SScoringFacility::SChannel::
spp() const
{
        return (float)samplerate() * _p.vpagesize() / _p.da_wd;
}
inline float
SScoringFacility::SChannel::
fine_line() const
{
        return ((not resample_signal) and spp() > 1.)
                ? agh::alg::value_within( .6 / (spp() + .2), .1, 3.)
                : .6;
}
inline int
SScoringFacility::SChannel::
sample_at_click( double x) const
{
        return _p.time_at_click( x) * samplerate();
}




inline size_t
SScoringFacility::SChannel::
samplerate() const
{
        return crecording.F().samplerate(h());
}

}
} // namespace agh::ui

#endif

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