/* 
 * Directory.java (Implements Directory System).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 * This file implements all the functionalities of the directory.
 * As this class extends from components it allows composite pattern
 * access to file and directory without using any special mechanism
 * or identification system.
 *
 * ASSUMPTIONS :
 *
 * 1. This program does not handle single line multi-level change 
 *    directory. (e.g. cd <dir-name> ... allowed, but
 *                     cd <dir-name1>/<dir-name2> ... not allowed.
 *
 * 2. All the operations that are done will be done in the
 *    directory pointed by currentDir.
 *
 * 3. The file/directory to be deleted should be owned by "me". If
 *    I don't own the file, then I cannot delete them.
 *
 * 4. The file or directory that you are thinking of deleting should
 *    be present in the current directory.
 *
 * 5. During recursive deletion of directory if there is any file or
 *    directory that is owned by some one else, the operation of 
 *    recursive deletion is aborted.
 *
 * 6. The permissions and owner of root cannot be changed.
 *
 * Portions copyright(c) 2001 to School of Electrical Engineering and 
 * Computer Science, UCF, Orlando.                   
 *                                    
 * Use and distribution of this source code are strictly governed by 
 * terms and conditions set by the authors.
 * 
 * $Id : Directory.java, 03/26/2001. $
 *            
 * Revision History:
 *
 * 1. Created basic structure           Nitin,        v1.0.0  04/02/2001.
 * 2. Added Documentation.              Nitin,        v1.0.1  04/02/2001.
*/

import java.io.*;
import java.util.*;

/* Implements all the functionality of directory.*/
class Directory extends Component{ 

 /* Default constructor used to create directory.*/
 public Directory(String szDirName){ 
  _first = null; 
  this.szDirectoryName = szDirName;
  szTime = formatTime(System.currentTimeMillis());
  szPermissions = "drwxr_x__x";
  szOwner = "me";
  szGroup = "us";
 } /* End of Directory.*/

 /* Returns the owner of this directory.*/
 public String getOwner(){
  return szOwner;
 }/* End of getOwner.*/

 /* Gets the permission of this file.*/
 public String getPermissions(){
  return szPermissions;
 }/* End of getPermissions.*/

 /* This function can add file or directory.*/
 public void add(Component cFile){ 
  cFile.setchild( _first );
 _first = cFile; 
 }/* End of add.*/

 /* Removes the file from the directory.*/
 public boolean removeFile(Component cFile){ 
  Component tFile;
  if (_first == cFile && (cFile.getName()).equals("me")){
   _first = cFile.getchild();
   cFile.setchild(null);
   return true;
  }else{
    for (tFile=_first; tFile != null; tFile=tFile.getchild()) {
     if(tFile.getchild() == cFile) break; 
    }/* End for.*/
    if(tFile!=null && (tFile.getName()).equals("me")) { 
     tFile.setchild( cFile.getchild() );
     cFile.setchild(null);
     return true;
    }/* End if.*/
  }/* End if.*/
  return false;
 }/* End of removeFile.*/

 /* Removes directory using component object.*/
 public void rmdir(Component cFile){ 
  Component tFile;
  if (_first == cFile){
   _first = cFile.getchild();
   cFile.setchild(null);
  }else{
    for (tFile=_first; tFile != null; tFile=tFile.getchild()) {
     if(tFile.getchild() == cFile) break; 
    }/* End for.*/
    if(tFile!=null) { 
     tFile.setchild( cFile.getchild() );
     cFile.setchild(null);
    }/* End if.*/
  }/* End if.*/
 }/* End of removeDirectory.*/

 /* This function lists only one directory.*/
 public void lss(){
  ListSingleDirectory(this);
 }/* End of lss.*/

 /* List only single directory.*/
 private void ListSingleDirectory(Component cFile){
  Component tFile;
  boolean bStatus = false;
  int nCount=0;
  for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
   tFile.operation();  
   bStatus = true;
   nCount++;
  }/* End of for.*/
  if(bStatus == false){
   System.out.println("\tNo file(s) found in this directory.");
  }else{
   System.out.println("\tFound " + nCount + " files/directory.");
  }
 }/* End of ListSingleDirectory.*/

 /* Displays information of the directory.*/
 public void operation(){
  System.out.println(szPermissions + "\t" + szOwner + "\t" + szGroup +
                     "\t" + szDirectoryName + "/");
 }/* End of operation.*/

 /* Lists the directory recursively.*/
 public void ls(){ 
  operation(this);
 }/* End of ls.*/

 /* Finds Directory.*/
 public Directory FindDirectory(String szDir){
  return(FindDirectory(szDir, this));
 }/* End of FindDirectory.*/

 public Directory FindCurrentDir(String szDir,Component cFile){
  Component tFile; 
  
  for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
   if(tFile.DirectoryDetect() != 0){
    if((((Directory)tFile).szDirectoryName).equals(szDir)) 
     return (Directory)tFile;
   }/* End if.*/
  }/* End for.*/
  return null;
 }/*End of FindCurrentDir.*/

 /* Finds the directory using Component Object.*/
 public Directory FindDirectory(String szDir,Component cFile){ 
  Component tFile;
  Component t1File; 

  if(cFile.DirectoryDetect()!=0){
   if((((Directory) cFile).szDirectoryName).equals(szDir)) 
        return (Directory)cFile;
   else{
    for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()){
     if((t1File=FindDirectory(szDir,tFile)) != null) return (Directory)t1File;
    }/* End of for.*/
   }/* End if.*/
  }/* End if.*/
  return null;
 }/* End of FindDirectory.*/

 /* Opens a file based on permission available for file.*/
 public void open(String szFile){
   Component tFile;

   /* Check if file exists or no.*/
   if((tFile = FindFile(szFile,this)) == null){
    System.out.println("Cannot open file " + szFile + 
                       " file does not exists.");
   }else{
     String szPerm = tFile.getPermissions();
     
     if((szPerm.charAt(1) == 'r' && (tFile.getOwner()).equals("me")) 
        || (szPerm.charAt(4) == 'r') || (szPerm.charAt(7) == 'r')) 
        System.out.println("File " + szFile + " opened successfully.");
     else
        System.out.println("File " + szFile + " open failed no rights.");
    }/* End if.*/
 }/* End open.*/

 /* Finds a file in the currentDir. if yes return true else false.*/
 public File FindFile(String szFile){
  return FindFile(szFile,this);
 }/* End of FindFile.*/

 /* returns the name of the file.*/
 public String getName(){
  return szDirectoryName;
 }/* End of getName.*/

 /* Finds the file in the current directory*/
 public File FindFile(String szFile,Component cFile){ 
  Component tFile;
  Component t1File; 

  for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
   if(tFile.DirectoryDetect() == 0){
      if((tFile.getName()).equals(szFile)) return (File)tFile;
   }/* End if.*/
  }/* End of for.*/
  return null;
 }/* End of FindDirectory.*/

 /* recursively lookups if there are any violation in the deletion
    of directory recursively. this is explained in ASSUMPTION 5.*/
 public void recursiveLook(Component cFile,String szOwner){ 
  Component tFile;

  for (int nIndex=0; nIndex<level;nIndex++) System.out.print(" ");

  cFile.operation();
  if(((cFile.getOwner()).equals(szOwner)) == false){ 
   System.out.println("founf mismatch");
   bDelStatus = false;
  }/* End if.*/
  if(cFile.DirectoryDetect()!=0) {
   level++;
   for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
    recursiveLook(tFile,szOwner);
   }/* End for.*/
   level--;
  }/* End if.*/
 }/* End of operation.*/

 /* This is simple recursive operation.*/
 
 public void operation(Component cFile){ 
  Component tFile;

  for (int nIndex=0; nIndex<level;nIndex++) System.out.print(" ");

  cFile.operation();
  if(cFile.DirectoryDetect()!=0) {
   level++;
   for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
    operation(tFile);
   }/* End for.*/
   level--;
  }/* End if.*/
 }/* End of operation.*/
 
 /* Changes the ownership of the file.*/
 public boolean chown(String szNewOwn,String szName){
  if(szDirectoryName.equals(szName) && szOwner.equals("me")){
    szOwner = szNewOwn; 
    return true;
  }/* End if.*/
  return false;
 }/* End of chown.*/

 /* Changes the mode of the file.*/
 public boolean chmod(String szMode,String szName){
  if(szDirectoryName.equals(szName) && szOwner.equals("me")){
    szPermissions = "d"; 
    szPermissions = szPermissions + szMode;
    return true;
  }/* End if.*/
  return false;
 }/* End of chown.*/

 /* Removes a file from the directory.*/
 public boolean rm(String szFile){
  Component t1;
  if((t1=FindFile(szFile)) != null) return removeFile(t1);
  else return false;
 }/* End of rm.*/

 /* Changes the owner of the file.*/
 public void chowner(String szNewOwn,String szName){
  Component tFile;
  Component cFile = this;

  System.out.println("Changing owner of file " + szName + " to " +
                      szNewOwn);
  for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
   if(tFile.chown(szNewOwn,szName) == true){ 
     System.out.println("Changing owner of file " + szName + " to " +
                         szNewOwn);
     return;
   }/* End if.*/
  }/* End of for.*/
  System.out.println("Unallowable Action: chown have no permissions or file/dir " +
                     "not present");
 }/* End of chowner.*/

 /* Changes the mode of the file.*/
 public void chmode(String szMode,String szName){
  Component tFile;
  Component cFile = this;

  for(tFile=((Directory)cFile)._first; tFile!=null; tFile=tFile.getchild()) {
   if(tFile.chmod(szMode,szName) == true){
     System.out.println("Changing access rights of file " + szName + " to "
                         + szMode);
     return;
   }/* End if.*/
  }/* End of for.*/
  System.out.println("Unallowable Action: chmod have no permissions or file/dir " +
                     "not present");
 }/* End of chowner.*/

 /* Used to check if object is directory or file.*/
 public int DirectoryDetect() { return(1); }

 public Component _first;
 private static int level = 0;
 private String szDirectoryName;
 private String szTime;
 private String szOwner;
 private String szGroup;
 private String szPermissions;
 public  boolean bDelStatus;
}/* End of Directory.*/


