/*
   HARK Library
   Copyright (C) 2021 Honda Research Institute Japan Inc.
 */

#include "hark-lib/node/PublishData.h"

#include "hark-lib/internal/lock.h"
#include "hark-lib/internal/mutex.h"
#include "hark-lib/internal/condition_variable.h"

#include <condition_variable>

namespace hark
{
namespace node
{
    PublishData::PublishData():
        NodeDef("PublishData"), _closed(false), _mutex(new Mutex()), _condvar(new ConditionVariable())
    {
        *this
            >> Terminal::out("OUTPUT");
    }

    void
    PublishData::reset()
    {
        this->_closed = false;
        this->_buffer.clear();
    }

    bool
    PublishData::operator () (size_t count, InputDataBundle &input, OutputDataBundle &output)
    {
        data value;
        {
#if defined(VERBOSE_DEBUG)
                {
                    std::stringstream ss;
                    ss << "PublishData::operator ()" << std::endl;
                    std::cout << ss.str();
                }
#endif /* #if defined(VERBOSE_DEBUG) */
            UniqueLock lock(this->_mutex.get());
            //std::unique_lock<std::mutex> lock(this->_mutex);

            while(!this->_closed && this->_buffer.empty()){
#if defined(VERBOSE_DEBUG)
                {
                    std::stringstream ss;
                    ss << "PublishData::operator (): wait" << std::endl;
                    std::cout << ss.str();
                }
#endif /* #if defined(VERBOSE_DEBUG) */
                this->_condvar->wait(lock);
#if defined(VERBOSE_DEBUG)
                {
                    std::stringstream ss;
                    ss << "PublishData::operator (): notified" << std::endl;
                    std::cout << ss.str();
                }
#endif /* #if defined(VERBOSE_DEBUG) */
            }
            if(this->_closed){
    //            std::cout << "PublishData::operator (): return false" << std::endl;
                return false;
            }

            value = this->_buffer.front();
            this->_buffer.pop_front();
        }

        output["OUTPUT"].push(value);

#if defined(VERBOSE_DEBUG)
                {
                    std::stringstream ss;
                    ss << "PublishData::operator (): return true" << std::endl;
                    std::cout << ss.str();
                }
#endif /* #if defined(VERBOSE_DEBUG) */
        return true;
    }

    void
    PublishData::push(data input)
    {
        UniqueLock lock(this->_mutex.get());
        //std::unique_lock<std::mutex> lock(this->_mutex);

        this->_buffer.push_back(input);
#if defined(VERBOSE_DEBUG)
        {
            std::stringstream ss;
            ss << "PublishData::push: buffer-size=" << this->_buffer.size() << std::endl;
            std::cout << ss.str();
        }
#endif /* #if defined(VERBOSE_DEBUG) */

        this->_condvar->notify_one();
    }

    void
    PublishData::close()
    {
        this->_closed = true;
        this->_condvar->notify_one();
    }
}
}

/* end of file */
