#ifndef CDO_NODE_HPP
#define CDO_NODE_HPP

#include <vector>
#include <string>
#include <memory>
#include <iostream>

namespace Parser
{
class Node
{
public:
  const std::vector<std::string>::iterator iter;
  const std::string oper;
  const std::string arguments;
  const int numMaxChildren = 0;
  const int numOut = 0;
  const bool isFile = false;
  const bool isOutFile = false;
  std::vector<std::shared_ptr<Node>> children = {};

  Node(std::vector<std::string>::iterator p_iter, std::string p_operName, std::string p_args, int p_numMaxChildren, int p_numOut);
  Node(std::vector<std::string>::iterator p_iter, bool p_isOutFile);
  explicit Node(Node *p_nodePtr);
  std::shared_ptr<Node> copy();

  // Ready to be returned and process
  bool has_missing_input();
  // Done in terms of beein on the stack
  bool is_done();
  bool is_temporary_leaf();
  bool is_leaf();

  void add_leaf(std::shared_ptr<Node> &p_newNode);
  void append(std::vector<std::shared_ptr<Node>> &p_node);
  void append(std::shared_ptr<Node> &p_node);

  std::string to_string();
};

struct NodeAttachException : public std::invalid_argument
{
  const std::vector<std::string>::iterator iter;
  NodeAttachException(std::shared_ptr<Parser::Node> p_node, const std::string &p_msg) : std::invalid_argument(p_msg), iter(p_node->iter){};
  NodeAttachException(std::vector<std::string>::iterator p_iter, const std::string &p_msg) : std::invalid_argument(p_msg), iter(p_iter){};
};

struct MissingOutFileException : public std::invalid_argument
{
  explicit MissingOutFileException(const std::string &p_msg) : std::invalid_argument(p_msg) {}
};

struct CdoSyntaxError : public std::invalid_argument
{
  std::vector<std::string>::iterator iter;
  CdoSyntaxError(std::vector<std::string>::iterator p_iter, const std::string &p_msg) : std::invalid_argument(p_msg), iter(p_iter){};
};

}  // namespace Parser
#endif
