#include "profinet_pipes.hpp"
#include "CreatePipes.h"
#include "json_rpc_handler.hpp"

#include <iostream>
#include <string>

ProfinetPipes::ProfinetPipes() : p_input_stream_{nullptr}, 
                                 p_output_stream_{nullptr},
                                 listen_thread_stop_{false}
{
}

ProfinetPipes::~ProfinetPipes()
{
    ///Остановка потока
    listen_thread_stop_.store(true, std::memory_order_relaxed);
    if (listen_thread_.joinable())
    {
        listen_thread_.join(); 
    }
}

void ProfinetPipes::Init( ProfinetPipesSettings& sett ) 
{ 
    enable_ = sett.enable;
    if (!enable_)
        return;
    
    std::filesystem::path _input_path{sett.inp_pipe_name};
    std::filesystem::path _output_path{sett.out_pipe_name};

    auto streams = itr::create_pipes( _input_path, _output_path, std::cout );
    
    p_input_stream_ = std::move( std::get<0>( streams ) ) ;
    p_output_stream_ = std::move( std::get<1>( streams ) );
}

void ProfinetPipes::listen_pipe(ProfinetIface * p_profinet) 
{
    std::string request_str;

    try{
        while(!listen_thread_stop_.load(std::memory_order_relaxed)) 
        {
            std::string answer_str;
            std::getline( *p_input_stream_.get(), request_str);
            //std::cout << "Request: " << request_str << std::endl;
            if (json_rpc_handler(request_str, answer_str, p_profinet))
            {
                //std::cout << "Answer: " << answer_str << std::endl;
                *p_output_stream_ << answer_str << std::endl;
            }
            else
            {
                if (!request_str.empty())
                {
                    std::cout << "Wrong request: " << request_str << std::endl;
                }
                else
                {
                    /**
                     * @brief При отключении стороннего приложения от приемного fifo, в старом линуксе постоянно приходят пустые строки.
                     * Нужно решить что в этом случае делать.
                     * В новом линуксе вызывается исключение и прога закрывается.
                     */
                    throw std::runtime_error("listen_pipe: Profinet client was disconnected from profinet server output pipe, application closing...");
                }
                
            }
        }
    }
    catch ( const std::exception &ex ){
        auto answer_str = ex.what();
        std::cout << answer_str << std::endl;
        //*p_output_stream_ << answer_str << std::endl;
        throw std::runtime_error("listen_pipe: Critical Error!");
        //listen_thread_stop_.store(true, std::memory_order_relaxed);
    }
 }

 void ProfinetPipes::Start(ProfinetIface * p_profinet)
 {
    if (!enable_)
        return;
    
    listen_thread_ = std::move(std::thread(&ProfinetPipes::listen_pipe, this, p_profinet));
 }