#include "node.h"
#include "cdo_output.h"

namespace Parser
{
Node::Node(std::vector<std::string>::iterator p_iter, std::string p_oper, std::string args, int p_numMaxChildren, int p_numOut = 1)
    : iter(p_iter), oper(p_oper), arguments(args), numMaxChildren(p_numMaxChildren), numOut(p_numOut), isFile(false),
      isOutFile(false)
{
}

Node::Node(std::vector<std::string>::iterator p_iter, bool p_isOutFile = false)
    : iter(p_iter), oper(*p_iter), arguments(""), numMaxChildren(p_isOutFile ? 1 : 0), numOut(p_isOutFile ? 0 : 1), isFile(true),
      isOutFile(p_isOutFile)
{
}

Node::Node(Node *node_ptr)
    : iter(node_ptr->iter), oper(node_ptr->oper), arguments(node_ptr->arguments), numMaxChildren(node_ptr->numMaxChildren),
      numOut(node_ptr->numOut), isFile(node_ptr->isFile), isOutFile(node_ptr->isOutFile)
{
}

bool
Node::has_missing_input()
{
  if (children.size() == 0 && numMaxChildren != 0) return true;
  if (isFile || children.size() == (size_t) numMaxChildren || numMaxChildren == -1) return false;
  return true;
}

bool
Node::is_done()
{
  bool done = false;
  if (isFile && !isOutFile)
    {
      done = true;
    }
  else if ((int) children.size() == numMaxChildren)
    {
      done = true;
    }
  Debug("%s is done: %s", oper, done ? "true" : "false");
  return done;
}

void
Node::append(std::shared_ptr<Node> &node)
{

  Debug(CDO_NODE, "appending  %s to %s", node->oper, oper);
  if (isFile && !isOutFile && node->isFile)
    {
      throw NodeAttachException(node, "File to File not allowed");
    }
  if (isOutFile && is_done())
    {
      throw NodeAttachException(node, "Could not be assigned, leftover input");
    }
  if (numMaxChildren >= 0 && (int) children.size() == numMaxChildren)
    {
      throw NodeAttachException(iter, "To many inputs");
    }
  if (node->numOut == 0)
    {
      throw NodeAttachException(node, "operator has no output, cannot be used with pipes unless used first");
    }
  children.push_back(node);
}

void
Node::append(std::vector<std::shared_ptr<Node>> &n)
{
  for (auto &x : n) append(x);
}

bool
Node::is_temporary_leaf()
{
  return (children.size() != (size_t) numMaxChildren) && !isFile && (numMaxChildren != 0);
}

void
Node::add_leaf(std::shared_ptr<Node> &new_node)
{
  Debug(CDO_NODE, "add_leaf of node: %s", new_node->oper);
  if (is_temporary_leaf())
    {
      Debug(CDO_NODE, "adding leaf to %s", oper);
      children.push_back(new_node);
    }
  else
    {
      for (auto &c : children)
        {
          c->add_leaf(new_node);
        }
    }
}
std::shared_ptr<Node>
Node::copy()
{
  auto copiedNode = std::make_shared<Node>(this);
  copiedNode->children.clear();
  for (auto &child : children)
    {
      copiedNode->children.push_back(child->copy());
    }
  return copiedNode;
}

std::string
Node::to_string()
{
  std::string r = oper;
  if (!arguments.empty())
    {
      r += "," + arguments;
    }
  if (children.size() > 0) r += " [";
  for (auto &c : children)
    {
      r += " " + c->to_string();
    }
  if (children.size() > 0) r += " ]";
  return r;
}
}  // namespace Parser
