
#include "customary.hpp"


namespace hark
{

class HARK_Sub_Localization: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    HARK_Sub_Localization(const std::map<std::string, std::string> &args): _args(args)
    {
    }

public:
    void build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output){
        auto &node_cm_identity_matrix = network.create<hark::Node, hark::node::CMIdentityMatrix, hark::dispatch::Repeat>();
        auto &node_constant__for_operation_flag = network.create<hark::Node, hark::node::Constant, hark::dispatch::Repeat>();
        auto &node_localize_music = network.create<hark::Node, hark::node::LocalizeMUSIC>();
        auto &node_source_tracker = network.create<hark::Node, hark::node::SourceTracker>();
        auto &node_source_interval_extender = network.create<hark::Node, hark::node::SourceIntervalExtender>();

        //auto &node_plotmusicspec_kivy = network.create<hark::****, hark::****::plotQuickMusicSpecKivy>();
        //auto &node_plotsource_kivy = network.create<hark::****, hark::****::plotQuickSourceKivy>();

        node_cm_identity_matrix
            << hark::Input("NB_CHANNELS", 8)
            << hark::Input("LENGTH", 512)
            ;

        node_constant__for_operation_flag
            << hark::Input("VALUE", true)
            ;

        node_localize_music
            << hark::Input("INPUT", input["SPEC"])
            << hark::Input("NOISECM", node_cm_identity_matrix["OUTPUT"])
            << hark::Input("OPERATION_FLAG", node_constant__for_operation_flag["OUTPUT"])
            << hark::Input("MUSIC_ALGORITHM", "SEVD")
            // << hark::Input("TF_CHANNEL_SELECTION", std::vector<int>())
            // << hark::Input("LENGTH", 512)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("TF_INPUT_TYPE", "FILE")
            // << hark::Input("A_MATRIX", "")
            << hark::Input("A_MATRIX", "tamago_rectf.zip")
            // << hark::Input("WINDOW", 50)
            // << hark::Input("WINDOW_TYPE", "FUTURE")
            << hark::Input("WINDOW_TYPE", "MIDDLE")
            // << hark::Input("PERIOD", 50)
            // << hark::Input("NUM_SOURCE", 2)
            // << hark::Input("MIN_DEG", -180)
            // << hark::Input("MAX_DEG", 180)
            // << hark::Input("LOWER_BOUND_FREQUENCY", 500)
            << hark::Input("LOWER_BOUND_FREQUENCY", 3000)
            // << hark::Input("UPPER_BOUND_FREQUENCY", 2800)
            << hark::Input("UPPER_BOUND_FREQUENCY", 6000)
            // << hark::Input("SPECTRUM_WEIGHT_TYPE", "Uniform")
            << hark::Input("SPECTRUM_WEIGHT_TYPE", "A_Characteristic")
            // << hark::Input("A_CHAR_SCALING", 1.0)
            // << hark::Input("ENABLE_EIGENVALUE_WEIGHT", true)
            << hark::Input("ENABLE_EIGENVALUE_WEIGHT", false)
            // << hark::Input("MAXIMUM_OUT_PEAKS", -1)
            // << hark::Input("ENABLE_OUTPUT_SPECTRUM", false)
            << hark::Input("ENABLE_OUTPUT_SPECTRUM", true)
            // << hark::Input("ENABLE_OUTPUT_SPECTRUM_BIN", false)
            // << hark::Input("ENABLE_OUTPUT_TF_INFO", false)
            // << hark::Input("ENABLE_OUTPUT_RXXS", false)
            // << hark::Input("ENABLE_OUTPUT_RXXN", false)
            // << hark::Input("DEBUG", false)
            << hark::Input("DEBUG", true)
            ;

        /*
        node_plotmusicspec_kivy
            << hark::Input("SPECTRUM", node_localize_music["SPECTRUM"])
            ;
        */

        node_source_tracker
            << hark::Input("INPUT", node_localize_music["OUTPUT"])
            // << hark::Input("THRESH", 20.0f)
            << hark::Input("THRESH", 25.0f)
            // << hark::Input("PAUSE_LENGTH", 800.0f)
            << hark::Input("PAUSE_LENGTH", 1200.0f)
            // << hark::Input("MIN_SRC_INTERVAL", 20.0f)
            // << hark::Input("MIN_ID", 0)
            // << hark::Input("DEBUG", false)
            ;

        node_source_interval_extender
            << hark::Input("SOURCES", node_source_tracker["OUTPUT"])
            // << hark::Input("PREROLL_LENGTH", 50)
            << hark::Input("PREROLL_LENGTH", 80)
            ;

        /*
        node_plotsource_kivy
            << hark::Input("SOURCES", node_source_interval_extender["OUTPUT"])
            ;
        */

        output["OUTPUT"] << node_source_interval_extender["OUTPUT"];
    }
};


class HARK_Sub_Separation: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    HARK_Sub_Separation(const std::map<std::string, std::string> &args): _args(args)
    {
    }

public:
    void build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output){
        auto &node_ghdss = network.create<hark::Node, hark::node::GHDSS>();
        auto &node_synthesize = network.create<hark::Node, hark::node::Synthesize>();
        auto &node_save_wave_pcm = network.create<hark::Node, hark::node::SaveWavePCM>();
        auto &node_power_calc_for_map = network.create<hark::Node, hark::node::PowerCalcForMap>();
        // auto &node_hrle = network.create<hark::Node, hark::node::HRLE>();
        auto &node_estimate_leak = network.create<hark::Node, hark::node::EstimateLeak>();
        auto &node_calc_spec_add_power = network.create<hark::Node, hark::node::CalcSpecAddPower>();
        auto &node_calc_spec_sub_gain = network.create<hark::Node, hark::node::CalcSpecSubGain>();
        auto &node_spectral_gain_filter = network.create<hark::Node, hark::node::SpectralGainFilter>();

        node_ghdss
            << hark::Input("INPUT_FRAMES", input["SPEC"])
            << hark::Input("INPUT_SOURCES", input["SOURCE"])
            // << hark::Input("TRANSFER_FUNCTION", node_****["TRANSFER_FUNCTION"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("LOWER_BOUND_FREQUENCY", 0)
            // << hark::Input("UPPER_BOUND_FREQUENCT", 8000)
            << hark::Input("TF_INPUT_TYPE", "FILE")
            // << hark::Input("TF_CONJ_FILENAME", "")
            << hark::Input("TF_CONJ_FILENAME", "tamago_rectf.zip")
            // << hark::Input("INITW_FILENAME", "")
            // << hark::Input("SS_METHOD", "ADAPTIVE")
            // << hark::Input("SS_METHOD", "FIX")
            // << hark::Input("SS_MYU", 0.001f)
            // << hark::Input("SS_SCAL", 1.0f)
            // << hark::Input("NOISE_FLOOR", 0.0f)
            // << hark::Input("LC_CONST", "FULL")
            << hark::Input("LC_CONST", "DIAG")
            // << hark::Input("LC_METHOD", "ADAPTIVE")
            // << hark::Input("LC_METHOD", "FIX")
            // << hark::Input("LC_MYU", 0.001f)
            // << hark::Input("UPDATE_METHOD_TF_CONF", "POS")
            // << hark::Input("UPDATE_METHOD_W", "ID_POS")
            << hark::Input("UPDATE_METHOD_W", "ID")
            // << hark::Input("UPDATE_ACCEPT_DISTANCE", 300.0f)
            // << hark::Input("EXPORT_W", false)
            // << hark::Input("EXPORT_W_FILENAME", "")
            // << hark::Input("UPDATE", "STEP")
            ;

        node_synthesize
            << hark::Input("INPUT", node_ghdss["OUTPUT"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("MIN_FREQUENCY", 125)
            // << hark::Input("MAX_FREQUENCY", 7900)
            // << hark::Input("WINDOW", "HAMMING")
            // << hark::Input("OUTPUT_GAIN", 1.0f)
            << hark::Input("OUTPUT_GAIN", 0.0003125f)
            ;

        node_save_wave_pcm
            << hark::Input("INPUT", node_synthesize["OUTPUT"])
            // << hark::Input("ENABLE", true)
            // << hark::Input("BASENAME", "sep_")
            << hark::Input("BASENAME", "ghdss_{srcid}_")
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("BITS", "int16")
            // << hark::Input("INPUT_BITS", "as_BITS")
            ;

        node_power_calc_for_map
            << hark::Input("INPUT", node_ghdss["OUTPUT"])
            // << hark::Input("POWER_TYPE", "POW")
            ;

        /*
        node_hrle
            << hark::Input("INPUT_SPEC", node_power_calc_for_map["OUTPUT"])
            // << hark::Input("LX", 0.85f)
            << hark::Input("LX", 0.10f)
            // << hark::Input("TIME_CONSTANT_METHOD", "LEGACY")
            // << hark::Input("TIME_CONSTANT", 0.75f)
            // << hark::Input("TIME_CONSTANT_METHOD", "MILLISECOND")
            // << hark::Input("DECAY_FACTOR", 150)
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("NUM_BIN", 1000)
            << hark::Input("NUM_BIN", 2000)
            // << hark::Input("MIN_LEVEL", -100)
            << hark::Input("MIN_LEVEL", -200)
            // << hark::Input("STEP_LEVEL", 0.2f)
            // << hark::Input("DEBUG", false)
            ;
        */

        node_estimate_leak
            << hark::Input("INPUT_POWER_SPEC", node_power_calc_for_map["OUTPUT"])
            // << hark::Input("LEAK_FACTOR", 0.25f)
            // << hark::Input("OVER_CANCEL_FACTOR", 1)
            ;

        /*
        node_calc_spec_add_power
            << hark::Input("INPUT_POWER_SPEC1", node_estimate_leak["LEAK_POWER_SPEC"])
            << hark::Input("INPUT_POWER_SPEC2", node_hrle["NOISE_SPEC"])
            ;
        */

        node_calc_spec_sub_gain
            << hark::Input("INPUT_POWER_SPEC", node_power_calc_for_map["OUTPUT"])
            // << hark::Input("NOISE_SPEC", node_calc_spec_add_power["OUTPUT_POWER_SPEC"])
            << hark::Input("NOISE_SPEC", node_estimate_leak["LEAK_POWER_SPEC"])
            // << hark::Input("ALPHA", 1.0f)
            // << hark::Input("BETA", 0.0f)
            // << hark::Input("SS_METHOD", 2)
            ;

        node_spectral_gain_filter
            << hark::Input("INPUT_SPEC", node_ghdss["OUTPUT"])
            << hark::Input("VOICE_PROB", node_calc_spec_sub_gain["VOICE_PROB"])
            << hark::Input("GAIN", node_calc_spec_sub_gain["GAIN"])
            ;

        output["OUTPUT"] << node_spectral_gain_filter["OUTPUT_SPEC"];
    }
};


class HARK_Sub_Recognition: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    HARK_Sub_Recognition(const std::map<std::string, std::string> &args): _args(args)
    {
    }

public:
    void build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output){
        auto &node_pre_emphasis = network.create<hark::Node, hark::node::PreEmphasis>();
        auto &node_mel_filter_bank = network.create<hark::Node, hark::node::MelFilterBank>();
        auto &node_msls_extraction = network.create<hark::Node, hark::node::MSLSExtraction>();
        auto &node_delta = network.create<hark::Node, hark::node::Delta>();
        auto &node_feature_remover = network.create<hark::Node, hark::node::FeatureRemover>();
        auto &node_spectral_mean_normalization_incremental = network.create<hark::Node, hark::node::SpectralMeanNormalizationIncremental>();
        auto &node_speech_recognition_client = network.create<hark::Node, hark::node::SpeechRecognitionClient>();
        auto &node_save_features = network.create<hark::Node, hark::node::SaveHTKFeatures>();

        node_pre_emphasis
            << hark::Input("INPUT", input["SPEC"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("PREEMCOEF", 0.97f)
            // << hark::Input("INPUT_TYPE", "WAV")
            << hark::Input("INPUT_TYPE", "SPECTRUM")
            ;

        node_mel_filter_bank
            << hark::Input("INPUT", node_pre_emphasis["OUTPUT"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("CUTOFF", 8000)
            // << hark::Input("MIN_FREQUENCY", 63)
            // << hark::Input("MAX_FREQUENCY", 8000)
            // << hark::Input("FBANK_COUNT", 13)
            << hark::Input("FBANK_COUNT", 40)
            ;

        node_msls_extraction
            << hark::Input("FBANK", node_mel_filter_bank["OUTPUT"])
            << hark::Input("SPECTRUM", node_pre_emphasis["OUTPUT"])
            // << hark::Input("FBANK_COUNT", 13)
            << hark::Input("FBANK_COUNT", 40)
            // << hark::Input("NORMALIZATION_MODE", "CEPSTRAL")
            << hark::Input("NORMALIZATION_MODE", "SPECTRAL")
            // << hark::Input("USE_LEGACY_MODE", true)
            // << hark::Input("USE_HTK_LIFTER", false)
            // << hark::Input("LIFTERING_COEF", 22)
            // << hark::Input("USE_POWER", false)
            << hark::Input("USE_POWER", true)
            ;

        node_delta
            << hark::Input("INPUT", node_msls_extraction["OUTPUT"])
            // << hark::Input("FBANK_COUNT", 41)
            ;

        node_feature_remover
            << hark::Input("INPUT", node_delta["OUTPUT"])
            << hark::Input("SELECTOR", "40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81")
            ;

        node_spectral_mean_normalization_incremental
            << hark::Input("INPUT", node_feature_remover["OUTPUT"])
            << hark::Input("SM_HISTORY", false)
            << hark::Input("NOT_EOF", true)
            // << hark::Input("FBANK_COUNT", 13)
            << hark::Input("FBANK_COUNT", 40)
            // << hark::Input("PERIOD", 20)
            << hark::Input("PERIOD", 1)
            // << hark::Input("SM_ALGORITHM", "INCREMENTAL")
            // << hark::Input("SM_FILENAME", "")
            // << hark::Input("SM_HISTORY_FILENAME", "")
            // << hark::Input("IGNORE_FRAMES", false)
            // << hark::Input("BASENAME", "smn_")
            << hark::Input("BASENAME", "")
            // << hark::Input("OUTPUT_FNAME", "out.txt")
            << hark::Input("OUTPUT_FNAME", "")
            << hark::Input("SM_EXPORT_FILENAME", "")
            << hark::Input("SM_EXPORT_ALGORITHM", "LAST_SRC")
            ;

        node_speech_recognition_client
            << hark::Input("FEATURES", node_spectral_mean_normalization_incremental["OUTPUT"])
            << hark::Input("MASKS", node_spectral_mean_normalization_incremental["OUTPUT"])
            << hark::Input("SOURCES", input["SOURCE"])
            // << hark::Input("MFM_ENABLED", false)
            // << hark::Input("HOST", "127.0.0.1")
            << hark::Input("HOST", "localhost")
            << hark::Input("PORT", 5530)
            // << hark::Input("SOCKET_ENABLED", true)
            << hark::Input("SOCKET_ENABLED", false)
            << hark::Input("PROTOCOL_TYPE", 1)
            ;

        node_save_features
            << hark::Input("FEATURES", node_spectral_mean_normalization_incremental["OUTPUT"])
            << hark::Input("SOURCES", input["SOURCE"])
            // << hark::Input("BASENAME", "")
            << hark::Input("BASENAME", "feature_")
            // << hark::Input("HTK_PERIOD", 100000)
            // << hark::Input("FEATURE_TYPE", "USER")
            ;

        output["OUTPUT"] << node_spectral_mean_normalization_incremental["OUTPUT"];
    }
};


class HARK_Main_Loop: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    HARK_Main_Loop(const std::map<std::string, std::string> &args): _args(args)
    {
    }

public:
    void build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output){
        auto &node_audio_stream_from_wave = network.create<hark::Node, hark::node::AudioStreamFromWave, hark::dispatch::TriggeredRepeat>();
        auto &node_multi_gain = network.create<hark::Node, hark::node::MultiGain>();
        auto &node_multi_fft = network.create<hark::Node, hark::node::MultiFFT>();

        //auto &node_sub_localization = network.create<hark::Network, HARK_Sub_Localization, hark::dispatch::TriggeredRepeat>("Localization", this->_args)
        //    << hark::Input("SPEC", node_multi_fft["OUTPUT"]);

        auto &node_sub_localization = network.create_network(new HARK_Sub_Localization(this->_args), new hark::dispatch::TriggeredRepeat(), "Localization")
            << hark::Input("SPEC", node_multi_fft["OUTPUT"]);

        //auto &node_sub_separation = network.create<hark::Network, HARK_Sub_Separation, hark::dispatch::TriggeredRepeat>("Separation", this->_args)
        //    << hark::Input("SPEC", node_multi_fft["OUTPUT"])
        //    << hark::Input("SOURCE", node_sub_localization["OUTPUT"]);

        auto &node_sub_separation = network.create_network(new HARK_Sub_Separation(this->_args), new hark::dispatch::TriggeredRepeat(), "Separation")
            << hark::Input("SPEC", node_multi_fft["OUTPUT"])
            << hark::Input("SOURCE", node_sub_localization["OUTPUT"]);

        //auto &node_sub_recognition = network.create<hark::Network, HARK_Sub_Recognition, hark::dispatch::TriggeredRepeat>("Recognition", this->_args)
        //    << hark::Input("SPEC", node_sub_separation["OUTPUT"])
        //    << hark::Input("SOURCE", node_sub_localization["OUTPUT"]);

        auto &node_sub_recognition = network.create_network(new HARK_Sub_Recognition(this->_args), new hark::dispatch::TriggeredRepeat(), "Recognition")
            << hark::Input("SPEC", node_sub_separation["OUTPUT"])
            << hark::Input("SOURCE", node_sub_localization["OUTPUT"]);

        /*
        auto &node_vad_zc = network.create<hark::Node, hark::node::VADZC>();
        auto &node_multi_fft = network.create<hark::Node, hark::node::MultiFFT>();
        auto &node_synthesize = network.create<hark::Node, hark::node::Synthesize>();
        auto &node_save_wave_pcm = network.create<hark::Node, hark::node::SaveWavePCM>();
        */

        node_audio_stream_from_wave
            << hark::LoopCondition(node_audio_stream_from_wave["NOT_EOF"])
            << hark::Input("INPUT", input["INPUT"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("USE_WAIT", true)
            ;

        node_multi_gain
            << hark::Input("INPUT", node_audio_stream_from_wave["AUDIO"])
            << hark::Input("GAIN", 0.0009765625 * 256)
            ;

        node_multi_fft
            << hark::Input("INPUT", node_multi_gain["OUTPUT"])
            // << hark::Input("LENGTH", 512)
            // << hark::Input("WINDOW", "CONJ")
            // << hark::Input("WINDOW_LENGTH", 512)
            ;

        output["OUTPUT"] << node_sub_separation["OUTPUT"];

/*
        node_vad_zc
            << hark::Input("INPUT", node_audio_stream_from_wave["AUDIO"])
            // << hark::Input("ADVANCE", 160)
            // << hark::Input("LENGTH", 512)
            << hark::Input("CHANNEL_COUNT", 17)
            // << hark::Input("SAMPLING_RATE", 16000)
            // << hark::Input("STRIP_ZERO", true)
            // << hark::Input("ZERO_MEAN", false)
            << hark::Input("LEVEL_THRESHOLD", 60.f)
            << hark::Input("ZEROCROSS_THRESHOLD", 80)
            << hark::Input("HEAD_MARGIN", 400.f)
            << hark::Input("TAIL_MARGIN", 600.f)
            ;

        node_multi_fft
            << hark::Input("INPUT", node_vad_zc["OUTPUT"]);

        node_synthesize
            << hark::Input("INPUT", node_multi_fft["OUTPUT"]);

        node_save_wave_pcm
            << hark::Input("INPUT", node_synthesize["OUTPUT"])
            << hark::Input("INPUT_BITS", "int24");
*/

    }
};


class HARK_Main: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    HARK_Main(const std::map<std::string, std::string> &args): _args(args)
    {
    }

public:
    void build(hark::Network &network, hark::DataSourceMap &input, hark::DataSinkMap &output){
        auto &filename = network.create<hark::Node, hark::node::Constant, hark::dispatch::OneShot>()
            << hark::Input("VALUE", "2SPK-ja.wav");

        auto &stream = network.create<hark::Node, hark::node::InputStream>()
            << hark::Input("INPUT", filename["OUTPUT"]);

        //auto &loop = network.create<hark::Network, HARK_Main_Loop, hark::dispatch::TriggeredRepeat>("HARK_Main_Loop", this->_args)
        //    << hark::Input("INPUT", stream["OUTPUT"]);

        auto &loop = network.create_network(new HARK_Main_Loop(this->_args), new hark::dispatch::TriggeredRepeat(), "HARK_Main_Loop")
            << hark::Input("INPUT", stream["OUTPUT"]);
    }
};

} // namespace hark end.


int process()
{
    std::map<std::string, std::string> args;
    std::shared_ptr<hark::Network> network(hark::Network::create<hark::HARK_Main>("HARK_Main", args));
    network->execute();
    return 0;
}


int main(int argc, char *argv[])
{
    try{
        process();
    }
    catch(std::exception &ex){
        std::cerr << "Error in process: " << ex.what() << std::endl;
        return EXIT_FAILURE;
    }
    catch(...){
        std::cerr << "Error in process: " << "not std::exception type" << std::endl;
        throw;
    }
    return EXIT_SUCCESS;
}

