#include "test5.h"

int main()
{
   debugtree b;

   // do some checking after one insert
   cout << "\nCHECK #1" << endl;
   b.insert("bug1", "the first bug inserted", "somefile");
   b.showRoot();
   int errs = b.checkStructure();
   if (errs) cerr << "Errors (" << errs << ") detected!" << endl;
   else cout << "Looks ok so far" << endl;

   // check again after another insert
   cout << "\nCHECK #2" << endl;
   b.insert("bug2", "the second bug inserted", "anotherfile");
   b.showRoot();
   errs = b.checkStructure();
   if (errs) cerr << "Errors (" << errs << ") detected!" << endl;
   else cout << "Looks ok so far" << endl;

   // check again after a third insert
   cout << "\nCHECK #3" << endl;
   b.insert("anotherbug", "the third bug inserted", "somefile");
   b.showRoot();
   errs = b.checkStructure();
   if (errs) cerr << "Errors (" << errs << ") detected!" << endl;
   else cout << "Looks ok so far" << endl;

   // print the tree, just to see
   cout << "\nCHECK #4" << endl;
   b.prtAll();


   // try variety of searches
   cout << "\nCHECK #5" << endl;
   string checks[7] = { "anotherbug", "bug1", "bug2", "aaa", "bug", "bug11", "ccc" };
   for (int i = 0; i < 7; i++) {
       cout << "\nTrying a search for " << checks[i] << endl;
       string d, f;
       if (b.lookup(checks[i], d, f)) {
          cout << "found desc " << d << ", file " << f << endl;
       } else {
          cout << "No match found" << endl;
       }
   }

   // try prints for specific files
   cout << "\nCHECK #6" << endl;
   for (int i = 0; i < 4; i++) {
       cout << "\nBugs matching file " << checks[i] << endl;
       b.prtFile(checks[i]);
   }

   // try some inserts with names already present
   cout << "\nCHECK #7" << endl;
   for (int i = 0; i < 3; i++) {
       cout << "\nTrying to insert a duplicate name: " << checks[i] << endl;
       if (b.insert(checks[i], "should not insert this case", "xfile")) {
          cout << "Insert incorrectly thinks that should  have worked" << endl;
       } else {
          cout << "Insert correctly flagged that as an error" << endl;
       }
   }

   // one last round of checks after those insert attempts
   cout << "\nCHECK #8" << endl;
   b.showRoot();
   errs = b.checkStructure();
   if (errs) cerr << "Errors (" << errs << ") detected!" << endl;
   else cout << "Structure looks ok" << endl;

   // print the tree, just to see
   cout << "\nCHECK #9" << endl;
   b.prtAll();
}

void debugtree::showRoot()
{
   if (root) {
      cout << "Root node  is: ";
      prtBug(root->name, root->desc, root->file);
      cout << endl;
   } else {
      cout << "Root is null" << endl;
   }
}

int debugtree::countNodes(bug* t)
{
   if (t) {
      return (countNodes(t->left) + countNodes(t->right) + 1);
   } else {
      return 0;
   }
}

// checks all nodes have non-empty strings,
//     names of nodes in subtrees are >=minname and < maxname,
//     and for root node only (minname == maxname == "")
//         also checks if numBugs == CountNodes(root)
// returns number of errors found
int debugtree::checkStructure(bug* n, string minname, string maxname)
{
   // no errors in an empty true
   if (n == nullptr) {
      return 0;
   }

   int numErrors = 0; // counts total errors found

   // if n is the root then check numBugs vs CountNodes
   if ((minname == "") && (maxname == "")) {
      int count = countNodes(root);
      if (count != numBugs) {
         numErrors++;
         cerr << "Error: numBugs (" << numBugs << ") != count of nodes (";
         cerr << count << ")" << endl;
      }
   }

   // check this node's name is >=  minname and < maxname ("" indicates no current min/max)
   if ((minname != "") && (n->name < minname)) {
      cerr << "Error: bug name " << n->name << " < " << minname;
      cerr << ", appears to be in wrong subtree" << endl;
      numErrors++;
   }
   if ((maxname != "") && (n->name >= maxname)) {
      cerr << "Error: bug name " << n->name << " >= " << maxname;
      cerr << ", appears to be in wrong subtree" << endl;
      numErrors++;
   }

   // check left subtree, all it's names must be >= minname and < this node's name
   numErrors += checkStructure(n->left, minname, n->name);

   // check right subtree, all it's names must be >= this node's name and < maxname
   numErrors += checkStructure(n->right, n->name, maxname);

   return numErrors;
}

