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

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

namespace hark
{
    NodeDef::NodeDef(const std::string &name):
        _name(name)
    {
    }

    NodeDef::~NodeDef()
    {
    }

    const std::string &
    NodeDef::name() const
    {
        return this->_name;
    }

    NodeDef &
    NodeDef::addInput(const Terminal &terminal)
    {
        // std::cout << "NodeDef::addInput" << std::endl;
        this->_input_terminals.insert({terminal.name(), terminal});
        // terminal.connectNode(*this);
        return *this;
    }

    NodeDef &
    NodeDef::addOutput(const Terminal &terminal)
    {
        this->_output_terminals.insert({terminal.name(), terminal});
        // terminal.connectNode(*this);
        return *this;
    }

    NodeDef &
    // NodeDef::operator << (const Terminal &terminal)
    operator << (NodeDef &nodedef, const Terminal &terminal)
    {
        nodedef.addInput(terminal);
        return nodedef;
    }

    NodeDef &
    // NodeDef::operator >> (const Terminal &terminal)
    operator >> (NodeDef &nodedef, const Terminal &terminal)
    {
        nodedef.addOutput(terminal);
        return nodedef;
    }

    const std::map<std::string, Terminal> &
    NodeDef::input_terminals() const
    {
        return this->_input_terminals;
    }

    const std::map<std::string, Terminal> &
    NodeDef::output_terminals() const
    {
        return this->_output_terminals;
    }

    void
    NodeDef::initialize()
    {
    }

    void
    NodeDef::finalize()
    {
    }

    // BaseNode::BaseNode(NodeDef *nodedef):
    //     BaseNode(nodedef, _create_default_name(nodedef))
    // {
    // }
    //
    // BaseNode::BaseNode(NodeDef *nodedef, const std::string &name):
    //     _nodedef(nodedef),
    //     _name(name)
    // {
    //     this->build_proxies(nodedef);
    // }
    //
    // Node::~Node()
    // {
    //     // std::cout << "Node::dtor()" << std::endl;
    // }
    //
    // void
    // Node::build_proxies(const NodeDef *nodedef)
    // {
    //     // std::cout << "Node[" << this->_name << "]: build_proxies" << std::endl;
    //
    //     auto &input_terminals = nodedef->input_terminals();
    //     for(const auto &it: input_terminals){
    //         // std::cout << "InputTerminal: node-name=" << this->_name << ", terminal-name=" << it.first << std::endl;
    //         this->_input_datasinks->add(it.first);
    //     }
    //
    //     auto &output_terminals = nodedef->output_terminals();
    //     for(const auto &it: output_terminals){
    //         // std::cout << "OutputTerminal: node-name=" << this->_name << ", terminal-name=" << it.first << std::endl;
    //         this->_output_datasources->add(it.first);
    //     }
    // }
    //
    // const std::string &
    // Node::type() const
    // {
    //     return this->_nodedef->name();
    // }
    //
    // std::vector<std::string>
    // Node::output_names() const
    // {
    //     return this->_output_datasources->names();
    // }
    //
    // std::vector<std::string>
    // Node::input_names() const
    // {
    //     return this->_input_datasinks->names();
    // }
    //
    // DataSink &
    // Node::output(std::string &name)
    // {
    //     return this->_output_datasources->query(name);
    // }
    //
    // DataSource &
    // Node::output_provided(std::string &name)
    // {
    //     return this->_output_datasources->query(name);
    // }
    //
    // std::vector<DataSink *> &
    // Node::output_connected(std::string &name)
    // {
    //     return this->_output_datasources->query(name).down_streams();
    // }
    //
    // const DataSink &
    // Node::output(std::string &name) const
    // {
    //     return this->_output_datasources->query(name);
    // }
    //
    // const DataSource &
    // Node::output_provided(std::string &name) const
    // {
    //     return this->_output_datasources->query(name);
    // }
    //
    // std::vector<DataSink *>
    // Node::output_connected(std::string &name) const
    // {
    //     return this->_output_datasources->query(name).down_streams();
    // }
    //
    // DataSource &
    // Node::input(std::string &name)
    // {
    //     return this->_input_datasinks->query(name);
    // }
    //
    // DataSink &
    // Node::input_listening(std::string &name)
    // {
    //     return this->_input_datasinks->query(name);
    // }
    //
    // DataSource *
    // Node::input_connected(std::string &name)
    // {
    //     return this->_input_datasinks->query(name).up_stream();
    // }
    //
    // const DataSource &
    // Node::input(std::string &name) const
    // {
    //     return this->_input_datasinks->query(name);
    // }
    //
    // const DataSink &
    // Node::input_listening(std::string &name) const
    // {
    //     return this->_input_datasinks->query(name);
    // }
    //
    // const DataSource *
    // Node::input_connected(std::string &name) const
    // {
    //     return this->_input_datasinks->query(name).up_stream();
    // }
    //
    // // DataSource &
    // // Node::operator [] (const std::string &name)
    // // {
    // //     return this->data_source_from_name(name);
    // // }
    //
    // DataSource &
    // Node::operator [] (const std::string &name)
    // // Node::data_source_from_name(const std::string &name)
    // {
    //     // std::cout << "Node[]: " << name << std::endl;
    //     // DataSource &v = this->_output_datasources->as_datasource_map().query(name);
    //     // std::cout << "Node[]: " << name << ": " << v.name() << std::endl;
    //     // return v;
    //     return this->_output_datasources->as_datasource_map().query(name);
    // }
    //
    // Node &
    // Node::add_input(Input &&input)
    // {
    //     DataProxy &proxy = this->_input_datasinks->query(input.name());
    //
    //     DataSource *source = nullptr;
    //     const std::string *value = nullptr;
    //     if((source = input.source()) != nullptr){
    //         source->connect_to(&proxy);
    //     }else if((value = input.value()) != nullptr){
    //         proxy.set_static(*value);
    //     }else{
    //         throw "";
    //     }
    //
    //     return *this;
    // }
    //
    // Node &
    // operator << (Node &node, Input &&input){
    //     node.add_input(std::move(input));
    //     return node;
    // }
    //
    // bool
    // Node::try_process()
    // {
    //     if(this->is_input_data_ready()){
    //         std::cout << "try_process: true" << std::endl;
    //         NodeDef &nodedef = *this->_nodedef;
    //         nodedef(*this->_input_data_bundle, *this->_output_data_bundle);
    //         return true;
    //     }else{
    //         std::cout << "try_process: false" << std::endl;
    //         return false;
    //     }
    // }
    //
    // bool
    // Node::is_input_data_ready() const
    // {
    //     size_t s1 = this->_input_datasinks->count_ready();
    //     size_t s2 = this->_input_datasinks->count();
    //     // std::cout << "s1: " << s1 << ", s2: " << s2 << std::endl;
    //     return s1 == s2;
    // }
    //
    // void
    // Node::initialize()
    // {
    //     // this->_input_data_bundle.reset(new DataBundle());
    //     // this->_output_data_bundle.reset(new DataBundle());
    //     //
    //     // for(auto &name: this->_input_datasinks->names()){
    //     //     this->_input_data_bundle->add_datastream(name, new DataStream());
    //     // }
    //     // for(auto &name: this->_output_datasources->names()){
    //     //     this->_output_data_bundle->add_datastream(name, new DataStream());
    //     // }
    // }
    //
    // void
    // Node::dump_graph(std::ostream &os, bool with_headers) const
    // {
    //     os << this->name() << std::endl;
    //
    //     for(auto &output_name: this->_output_datasources->names()){
    //         auto children = this->output_connected(output_name);
    //         // std::cout << "child-count: " << children.size() << std::endl;
    //         for(auto *sink: children){
    //             auto child = sink->parent();
    //             os << this->name() << " -> " << child->name() << std::endl;
    //             // child->dump_graph(os);
    //         }
    //     }
    // }

}

/* end of file */
