#include "hark-lib/node.h"
#include "hark-lib/network.h"
#include "hark-lib/input.h"

#include "hark-lib/node/Constant.h"
#include "hark-lib/node/InputStream.h"
#include "hark-lib/node/MultiFFT.h"
#include "hark-lib/node/AudioStreamFromWave.h"
#include "hark-lib/node/Synthesize.h"
#include "hark-lib/node/SaveWavePCM.h"
#include "hark-lib/node/VADZC.h"

#include <stdlib.h>
#include <string.h>
#include <exception>
#include <iostream>
#include <fstream>

using namespace hark;

class Recording: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    Recording(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_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_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 Main: public hark::NetworkDef
{
public:
    std::map<std::string, std::string> _args;
public:
    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", "test_sb.wav");

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

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

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

};

int
process(int argc, char *argv[])
{
    std::map<std::string, std::string> args;
    std::shared_ptr<Network> network(hark::Network::create<Main>("Main", args));
    network->execute();
    return 0;
}

int
main(int argc, char *argv[])
{
    try{
        process(argc, argv);
    }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;
}
