#include "bugtree.h"

void bugtree::prtFile(string file)
{
   printBugs(root, file);
}

void bugtree::prtAll()
{
   printBugs(root, "");
}

void bugtree::prtBug(string name, string desc, string file)
{
   cout << name << "(" << file << "): " << desc;
}

bugtree::bugtree()
{
   root = nullptr;
   numBugs = 0;
}

bugtree::~bugtree()
{
   deallocate(root);
}

bugtree::bug* bugtree::create(string name, string desc, string file)
{
   bug* b = new bug;
   b->name = name;
   b->desc = desc;
   b->file = file;
   b->left = nullptr;
   b->right = nullptr;
   return b;
}

bool bugtree::lookup(string name, string &desc, string &file)
{
   bug* b = getByName(name, root);
   if (b) {
      desc = b->desc;
      file = b->file;
      return true;
   }
   return false;
}


bugtree::bug* bugtree::getByName(string name, bug* b)
{
   // can't find anything if the tree is empty
   if (!b) {
      return nullptr;
   }

   // see if b is the one we're looking for
   else if (name == b->name) {
      return b;
   }

   // if name < b's name then what we're looking for can only be in left subtree
   else if (name < b->name) {
      return getByName(name, b->left);
   }

   // otherwise name > b's name so can only be in right subtree
   else {
      return getByName(name, b->right);
   }
}

void bugtree::deallocate(bug* &b)
{
   if (b) {
      // recursively deallocate b's subtrees then delete b itself
      deallocate(b->left);
      deallocate(b->right);
      delete b;
      b = nullptr;
   }
}

bool bugtree::insert(string name, string desc, string file, bug* &b)
{
   if (!b) {
      // b is null, we've reached the insertion point
      b = create(name, desc, file);
      numBugs++;
      return true;
   }

   // make sure the name isn't a duplicate
   else if (name == b->name) {
      return false;
   }

   // recurse on either the left or right subtree, based on the name and b's name
   else if (name < b->name) {
      return insert(name, desc, file, b->left);
   }

   else {
      return insert(name, desc, file, b->right);
   }
}

void bugtree::printBugs(bug* b, string file)
{
   if (b) {
      // print any the lesser-named bugs first
      printBugs(b->left, file);

      // print the current bug if we're printing all (file is "")
      //    or if b's file matches the specified file
      if ((file == "") || (file == b->file)) {
         prtBug(b->name, b->desc, b->file);
         cout << endl;
      }

      // print any greater-named bugs after
      printBugs(b->right, file);
   }
}

bool bugtree::insert(string name, string desc, string file)
{
   // fails if there is already a bug with that name
   bug* b = getByName(name, root);
   if (b) {
      cerr << "Error: cannot insert bugs with duplicate names," << endl;
      cerr << "   conflicts with ";
      cerr << name << "(" << file << "): " << desc;
      cerr << "" << endl;
      return false;
   }

   // use the protected insert routine to do the work
   return insert(name, desc, file, root);
}

