text: /**
   * Copyright 2017-2020 Stefan Ascher
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   * of the Software, and to permit persons to whom the Software is furnished to do
   * so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  
  #pragma once
  
  #include <vector>
  #include <memory>
  #include <stdint.h>
  #include <string>
  #include "AiDefines.h"
  #include "Factory.h"
  #include <functional>
  #include <sa/IdGenerator.h>
  #include <sa/Iteration.h>
  #include <CleanupNs.h>
  
  namespace AI {
  
  class Node;
  class Condition;
  class Agent;
  
  typedef std::vector<std::shared_ptr<Node>> Nodes;
  
  using NodeFactory = AbstractFactory<Node>;
  
  #define NODE_CLASS(NodeName)                                                        \
  public:                                                                             \
      class Factory final : public NodeFactory                                        \
      {                                                                               \
      public:                                                                         \
          std::shared_ptr<Node> Create(const ArgumentsType& arguments) const override \
          {                                                                           \
              std::shared_ptr<Node> res = std::make_shared<NodeName>(arguments);      \
              return res;                                                             \
          }                                                                           \
      };                                                                              \
      static const Factory& GetFactory()                                              \
      {                                                                               \
          static Factory sFactory;                                                    \
          return sFactory;                                                            \
      }                                                                               \
  private:                                                                            \
      NodeName(const NodeName&) = delete;                                             \
      NodeName& operator=(const NodeName&) = delete;                                  \
      NodeName(NodeName&&) = delete;                                                  \
      NodeName& operator=(NodeName&&) = delete;                                       \
      const char* GetClassName() const override { return ABAI_STRINGIFY(NodeName); }
  
  class Node
  {
  private:
      // Autogenerated Node IDs
      static sa::IdGenerator<Id> sIDs;
  public:
      enum class Status
      {
          Unknown,
          CanNotExecute,
          Running,
          Finished,
          Failed,
  
          _Count_
      };
  protected:
      // Node ID managed by the library.
      Id id_;
      std::string name_;
      std::shared_ptr<Condition> condition_;
      // Store the result in the Agent's context and return it.
      Node::Status ReturnStatus(Agent& agent, Node::Status value);
      explicit Node(const ArgumentsType& arguments);
  public:
      virtual ~Node();
      Id GetId() const { return id_; }
  
      virtual const char* GetClassName() const = 0;
      const std::string& GetName() const { return name_; }
      void SetName(const std::string& value) { name_ = value; }
      virtual bool AddNode(std::shared_ptr<Node> node);
      virtual void VisitChildren(const std::function<Iteration(const Node&)>&) const { }
      void SetCondition(std::shared_ptr<Condition> condition);
      const Condition* GetCondition() const { return condition_.get(); }
      virtual Node::Status Execute(Agent& agent, uint32_t timeElapsed);
  };
  
  void ForEachChildNode(const Node& parent, const std::function<Iteration(const Node& parent, const Node& child)>&);
  
  }
  