// CS2604 : Data Structures
// Hussein Suleman
// 22 July 1999

// ---------------------------------------------------------------------

#include <iostream.h>
#include <string.h>
#include <stdlib.h>

#include "dir.h"

// ---------------------------------------------------------------------

class Node
{
public:
   Node ( char *s );
   virtual ~Node ();
   char *data;
   Node *next, *directory;
};

Node::Node ( char *s )
{
   data = (char *)malloc(strlen (s)+1);
   strcpy (data, s);
}

Node::~Node ()
{
   free (data);
}

// ---------------------------------------------------------------------

class Directory
{
public:
   Node *head;
   Directory ( char *dir );
   ~Directory ();
   void Erase ( Node *root );
   Node *Build ( char *dir );
   void Print ();
   void Print2 ( Node *xhead, int level );
   Node *Find ( char *s, char *output );
   Node *Find2 ( char *s, Node *xhead, char *output );
};

// ---------------------------------------------------------------------

Directory::Directory ( char *dir )
{
   head = Build (dir);
}

Directory::~Directory ()
{
   Erase (head);
}

void Directory::Erase ( Node *root )
{
   while (root != NULL)
   {
      Node *p = root;
      root = root->next;
      Erase (p->directory);
      delete p;
   }
}

Node *Directory::Build ( char *dir )
{
   char s[2048];
   int state;
   Node *xhead = NULL;

   DirectoryReader A (dir);
   while ((state = A.GetName (s, sizeof (s))))
   {
      if ((strcmp (s, ".") != 0) && (strcmp (s, "..") != 0))
      {
         Node *p = new Node (s);
         p->next = xhead;
         xhead = p;
         if (state == 2)
            p->directory = Build (s);
         else
            p->directory = NULL;            
      }
   }
   return xhead;
}

void Directory::Print ()
{
   Print2 (head, 0);
}

void Directory::Print2 ( Node *xhead, int level )
{
   Node *p = xhead;
   while (p != NULL)
   {
      for ( int i=0; i<=level; i++ )
         cout << "---";
      cout << p->data << "\n";
      if (p->directory != NULL)
         Print2 (p->directory, level+1);
      p = p->next;
   }
}

Node *Directory::Find ( char *s, char *output )
{
   return Find2 (s, head, output);
}

Node *Directory::Find2 ( char *s, Node *xhead, char *output )
{
   Node *p = xhead;
   while (p!=NULL)
   {
      if (strcmp (s, p->data) == 0)
      {
         strcpy (output, s);
         return p;
      }
      else if (p->directory != NULL)
      {
         char output2[2048];
         Node *d = Find2 (s, p->directory, output2);
         if (d)
         {
            strcpy (output, p->data);
            strcat (output, "/");
            strcat (output, output2);
            return d;
         }
      }   
      p = p->next;
   }
   return NULL;
}

// ---------------------------------------------------------------------

class DirectorySearch
{
public:
   Directory *dy;
   char Result[2048];
   DirectorySearch ( char *s );
   char *Locate ( char *s );
   void Print ();
};

DirectorySearch::DirectorySearch ( char *s )
{
   dy = new Directory (s);
}

char *DirectorySearch::Locate ( char *s )
{
   strcpy (Result, "");
   Node *n = dy->Find (s, Result);
   if (n)
      return Result;
   else
      return "Not Found";
}

void DirectorySearch::Print ()
{
   dy->Print ();
}

// ---------------------------------------------------------------------

int main ()
{
   cout << "File Listing:\n\n";
   DirectorySearch ds ("..");
   ds.Print ();

   cout << "\nSearch:\n\n";
   cout << "Searching for [Makefile] : " << ds.Locate ("Makefile") << "\n"; 
   cout << "Searching for [main.cc] : " << ds.Locate ("main.cc~") << "\n";
   cout << "Searching for [test.cc] : " << ds.Locate ("test.cc") << "\n";
   cout << "Searching for [dir.o] : " << ds.Locate ("dir.o") << "\n";

   return 0;
}