/* This file contains the declaration for class DecisionTree.

---------------------------------------------------------------*/

#ifndef DECISION_TREE
#define DECISION_TREE

#include <iostream>    // istream, ostream, <<, >>, ...
#include <string>      // string
using namespace std;

class DecisionTree
{
public:
  DecisionTree(const string& fileName);
  ~DecisionTree();

  int descend();

 private:
  DecisionTree(const DecisionTree&);            // disable copying
  DecisionTree& operator=(const DecisionTree&); // disable assignment
  
  void read(const string& fileName);
  void write(const string& fileName);

  struct Node
  {
    Node(const string& question);
    Node(const string& question, Node* leftChild, Node* rightChild);
    ~Node();
    
    string myQuestion;    // the question I store
    Node*  myYesChild;    // where to go if the answer is 'y'
    Node*  myNoChild;     // where to go if the answer is 'n'

  };

  typedef Node* NodePtr;

  void buildTree(istream& InF, NodePtr& NPtr);
  int  descendTree(NodePtr& NPtr);
  void learnSomething(NodePtr& NPtr);
  void writeTree(ostream& OutF, NodePtr NPtr);

  NodePtr myRoot;
  string  myDataFile;
};

/* Explicit-value constructor
 * Receive: fileName, a string.
 * PRE: fileName is the name of a text file containing DecisionTree data.
 * POST: I am a DecisionTree containing the data found in fileName.
 */
inline DecisionTree::DecisionTree(const string& fileName) 
{ 
  myRoot = 0;             // just in case fileName is empty...
  read(fileName);         // build myself using data from fileName
  myDataFile = fileName;  // save for use by destructor
}

/* Destructor
 * PRE: my lifetime is over
 * POST: my data (including anything I have learned) has been saved to myDataFile.
 */
inline DecisionTree::~DecisionTree() 
{ 
  write(myDataFile);      // write myself back to data file
  delete myRoot;          // delete root node (recursively deleting everything)
  myRoot = 0;             // unnecessary, but ...
}

/* Node constructor
 * Receive: A question for the DecisionTree
 * POST: I am a DecisionTree::Node containing question
 *       && myYesChild == 0 && myNoChild == 0.
 */
inline DecisionTree::Node::Node(const string& question)
{
   myQuestion = question;
   myYesChild = 0;
   myNoChild = 0;
}

inline DecisionTree::Node::Node(const string& question,
                                DecisionTree::NodePtr left,
                                DecisionTree::NodePtr right)
{
  myQuestion = question;
  myYesChild = left;
  myNoChild = right;
}

/* Node destructor
 * PRE: my lifetime is over (someone has used 'delete' on my handle)
 * POST: both of my subtrees have been deleted
 */
inline DecisionTree::Node::~Node()
{
    delete myYesChild;    // delete yes subtree (recursively)
    delete myNoChild;     // delete no subtree (recursively)
}

/* method to 'walk' the tree from its root to a leaf
 *  (really just a wrapper for the recursive method).
 * return: 1 if the answer to the leaf-node's question was 'yes'
 *         0 if the answer at the leaf-node's question was 'no'
 * Relies on the recursive method descendTree()
 */
inline int DecisionTree::descend()
{
  return descendTree(myRoot);
}


#endif

