/*
 * proto-suff
 * Copyright (C) 2020  Univ. Artois & CNRS
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Node.hpp"
#include "Tree.hpp"
#include <cassert>
#include <iostream>

namespace protoss {

/**
 * @brief Construct a new Node object
 *
 * @param identifier is the node's id.
 */
Node::Node(int identifier)
    : m_identifier(identifier), m_falseBranch(nullptr), m_trueBranch(nullptr) {
} // constructor

/**
 * @brief Construct a new Node:: Node object
 *
 * @param identifier is the node's id.
 * @param falseBranch is a pointer on the false branch.
 * @param trueBranch is a pointer on the true branch.
 */
Node::Node(int identifier, Node *falseBranch, Node *trueBranch)
    : m_identifier(identifier), m_falseBranch(falseBranch),
      m_trueBranch(trueBranch) {} // constructor

/**
 * @brief Get the class regarding the input sub-example. As a side effect this
 * function collect the useful feature and update the vector usedToExplain.
 *
 * @param storedExample is the sub example we want to explain.
 * @param usedList is the list of feature we need to get the current class.
 * @param usedToExplain is a boolean vector that saves the feature we used.
 * @return int, the class of the current example (0 if undefined).
 */
int Node::getClass(std::vector<u_char> &storedExample,
                   std::vector<int> &usedList,
                   std::vector<bool> &usedToExplain) {
  if (m_identifier == BOTTOM || m_identifier == TOP)
    return m_identifier;

  assert(m_falseBranch && m_trueBranch);

  if (storedExample[m_identifier] == LIT_UNDEF) {
    int clFalse =
        m_falseBranch->getClass(storedExample, usedList, usedToExplain);
    if (!clFalse)
      return 0;

    int clTrue = m_trueBranch->getClass(storedExample, usedList, usedToExplain);

    if (!clFalse || (clTrue != clFalse))
      return 0;
    return clTrue;
  }

  if (!usedToExplain[m_identifier]) {
    usedList.emplace_back(m_identifier);
    usedToExplain[m_identifier] = true;
  }

  if (storedExample[m_identifier] == LIT_FALSE)
    return m_falseBranch->getClass(storedExample, usedList, usedToExplain);

  assert(storedExample[m_identifier] == LIT_TRUE);
  return m_trueBranch->getClass(storedExample, usedList, usedToExplain);
} // getClass

/**
 * @brief Display the tree following the preorder traversal.
 */
void Node::display() {
  std::cout << m_identifier << " ";

  if (m_falseBranch)
    m_falseBranch->display();
  if (m_trueBranch)
    m_trueBranch->display();
} // display

} // namespace protoss