/* 
 * DirectoryStructure.java (Implements Directory structure).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 * This file collects all the request from file and dispatches them
 * to respective functions with parameters. It also performs sanity
 * check on the size of the file name. This file dispatches to functions
 * like touch, ls, ch, chown,chmod, rmdir, mkdir and open.
 *
 * 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.
 *
 *
 * 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 : DirectoryStructure.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.*;

/* This section implements directory structure.*/
class DirectoryStructure{ 
 Directory currentDir;          /* This always points to current dir.*/
 Vector dirStack;               /* Stack used to store foward cd.*/
 int    nHeadPointer;           /* Points to the End of Stack.*/

 /* Implements default constructor.*/
 public DirectoryStructure(){
 }/* End of constructor.*/

 /* This is the function that dispatches all the requests.*/
 public void Start(String[][] szRequest, int nRequest){ 
  System.out.println("Creating File System.");
  currentDir = new Directory("root");

  dirStack = new Vector();       /* Allocate space for stack.*/
  nHeadPointer = -1;             /* Initialise pointer.*/

  /* Process all the request.*/
  for(int nIndex=0; nIndex < nRequest; nIndex++){
   if(szRequest[nIndex][0].equals("mkdir"))
    mkdir(szRequest[nIndex][1]);

   if(szRequest[nIndex][0].equals("rmdir"))
    rmdir(szRequest[nIndex][1]);

   if(szRequest[nIndex][0].equals("cd"))
    cd(szRequest[nIndex][1]);

   if(szRequest[nIndex][0].equals("ls")){ 
    if(szRequest[nIndex][1] == null) ls();
    else ls(szRequest[nIndex][1]);
   }

   if(szRequest[nIndex][0].equals("touch"))
    touch(szRequest[nIndex][1]);

   if(szRequest[nIndex][0].equals("rm"))
    rm(szRequest[nIndex][1]);

   if(szRequest[nIndex][0].equals("chmod"))
    chmod(szRequest[nIndex][1],szRequest[nIndex][2]);

   if(szRequest[nIndex][0].equals("chown"))
    chown(szRequest[nIndex][1],szRequest[nIndex][2]);

   if(szRequest[nIndex][0].equals("open"))
    open(szRequest[nIndex][1]);
  }/* End if.*/
 }/* End of main.*/

 /* This pushes component object onto the stack during forward directory
    change.*/
 private void push(Directory dObject){
  nHeadPointer++;
  dirStack.insertElementAt((Object)dObject,nHeadPointer);
 }/* End of push.*/

 /* This retrievs the parent directory from current directory. The parent
    directory from current is placed on the top of the stack.*/
 private Directory top(){
  Directory temp;
  temp = (Directory)dirStack.elementAt(nHeadPointer);
  return temp;  
 }/* End top.*/

 /* This function constructs the complete path by moving from lower
    stack to higher end.*/
 private String getPath(){
  int nStackPoin =1;
  String szPath = "root";

  /* If there is nothing in stack.*/
  if(nHeadPointer == -1) return (szPath);

  while(nStackPoin <= nHeadPointer){
   szPath += "/" + ((Directory)dirStack.elementAt(nStackPoin)).getName();
   nStackPoin++;
  }/* End of while.*/
  return szPath+"/"+currentDir.getName();
 }/* End getPath.*/

 /* This retrievs the parent directory from current directory. The parent
    directory from current is placed on the top of the stack. It deletes
    the content from the top.*/
 private Directory pop(){
  Directory temp;
  temp = (Directory)dirStack.elementAt(nHeadPointer);
  dirStack.removeElementAt(nHeadPointer);
  nHeadPointer--;       /* Update the stack pointer.*/
  return temp;
 }/* End of pop.*/

 /* This function changes the mode of the file, it will change only when
    the owner is changing the mode of the file.*/
 public void chmod(String szChmod,String szName){
  int nMode = Integer.parseInt(szChmod);
  int nNum;
  char szPermissions[] = {'_','_','_','_','_','_','_','_','_'};
  String szPerm;
  int nSize = 8;
  while(nMode != 0){
   nNum = nMode%10;
   nMode = nMode/10;
   if((nNum & 1) == 1) szPermissions[nSize] = 'x';
   nSize--;
   if(((nNum & 2) >> 1) == 1) szPermissions[nSize] = 'w';
   nSize--;
   if(((nNum & 4) >> 2) == 1) szPermissions[nSize] = 'r';
   nSize--;
  }/* End while.*/
  szPerm = new String(szPermissions);
  currentDir.chmode(szPerm,szName);
 }/* End of chmod.*/

 /* Changes the owner ship of a file or directory. The owner ship
    can be changed only when the file/directory is owned by me.*/
 public void chown(String szOwn,String szName){
  currentDir.chowner(szOwn,szName);
 }/* End of chown.*/

 /* List the contents of "currentDir". It does not display a recursive
    directory. Only the current dir listing is given.*/
 public void ls(){
  System.out.println("Listing file(s) in directory :" + getPath());
  currentDir.lss();  
 }/* End of ls.*/

 /* This lists the files/directory in the directory presented to it.*/
 public void ls(String szDir){
  Directory tempDir;
  System.out.println("Listing file(s) in directory :" + getPath()
                     + szDir);
  if((tempDir = currentDir.FindDirectory(szDir)) != null){
   tempDir.lss();
  }else{
   System.out.println("Unallowable Action:Directory " + szDir + " not found.");
  }/* End if.*/
 }/* End of ls.*/

 /* Changes the directory based on access permission to the directory.*/
 public void cd(String szDir){
  Directory tempDir;
  
  /* If you are moving up in directory, u can move only to
     parent.*/
  if(szDir.equals("..")){
   if(nHeadPointer == -1){
    System.out.println("Unallowable Action:Cannot go higher you are in root.");
    return;
   }/* End if.*/
   currentDir = pop();
   System.out.println("Changing directory to : " + getPath());
   return;
  }/* End if.*/

  /* If moving forward, check if directory is present or no 
     before moving.*/
  if((tempDir = currentDir.FindDirectory(szDir)) != null){
   /* Means the directory exists so make a change of directory.*/
   /* We will put the current content of this on the stack.*/
   String szPerm = tempDir.getPermissions();
   if((szPerm.charAt(1) == 'r' && tempDir.getOwner().equals("me")) 
      || szPerm.charAt(4) == 'r' || szPerm.charAt(7) == 'r'){
    System.out.println("Changing directory to : " + getPath() + "/"+szDir);
    push(currentDir);
    currentDir = tempDir;
   }else{
    System.out.println("Unallowable Action:Directory " + szDir + 
                       " has no permissions.");
   }/* End if.*/
  }else{
   System.out.println("Unallowable Action:Directory " + szDir + 
                      " does not exists.");
  }/* End if.*/
 }/* End of cd.*/

 /* Removes the directory only when the owner of the directory is
    me.*/
 public void rmdir(String szDir){
  Directory tempDir;
  System.out.println("Recursive removal of directory :"+ szDir);
  if((tempDir = currentDir.FindDirectory(szDir)) != null){
   /* Means there exists the directory that needs to be
      terminated.*/
   if((tempDir.getOwner()).equals("me") == false){
    System.out.println("Unallowable Action:Failed to delete directory " + 
                        szDir + " permissions denied.");
    return;
   }/* End if.*/

   /* Display the deletion files recursively.*/
   currentDir.bDelStatus = true;
   currentDir.recursiveLook(tempDir,tempDir.getOwner());
   String szPerm = currentDir.getPermissions();

   if(currentDir.bDelStatus == true && ((szPerm.charAt(2)=='w' &&
      currentDir.getOwner().equals("me")) || szPerm.charAt(5)=='w' ||
      szPerm.charAt(8)=='w')){ 
    /* If there are files of different owners in the directory, then
       all the files in the directory are maintained.*/
    currentDir.rmdir(tempDir);
   }else{
    System.out.println("Unallowable Action:Failed to delete directory " + 
                        szDir + " permission denied.");
   }/* End if.*/
  }else{
   System.out.println("Unallowable Action:Failed to delete directory " + 
                      szDir + " directory does not exist.");
  }/* End if.*/
 }/* End of rmdir.*/

 /* Create a new directory. Check if directory is already present.*/
 /* The directory is created in the current directory.*/
 public void mkdir(String szDir){
  Directory tempDir;
  String szPerm = currentDir.getPermissions();
  if(((tempDir = currentDir.FindCurrentDir(szDir,currentDir)) == null)){
   if((szPerm.charAt(2)=='w' && currentDir.getOwner().equals("me")) || 
       szPerm.charAt(5)=='w' || szPerm.charAt(8)=='w'){ 
       /* Means the directory wanting to create does not exists.*/
       /* So create it now.*/
       System.out.println("Creating directory " + szDir);
       currentDir.add(new Directory(szDir));
   }else{
    System.out.println("Unallowable Action : permission denied to create.");
   }/* End if.*/
  }else{
   System.out.println("Unallowable Action: Directory " + 
                      szDir + " already exists.");
  }/* End if.*/
 }/* End of mkdir.*/

 /* Create a file in the current directory.*/
 public void touch(String szFile){
  System.out.println("Creating file " + szFile);
  if(szFile.length() > 255){
  System.out.println("Unallowable Action : File name too long. "+
                     "(should be within 255 characters)");
  }/* End if.*/

  /* Check if the files exists and you have the permission to 
     create file in this directory.*/
  if(currentDir.FindFile(szFile,currentDir) == null){
   String szPerm = currentDir.getPermissions();
   if((szPerm.charAt(2) == 'w' && currentDir.getOwner().equals("me")) ||
      szPerm.charAt(5) == 'w' || szPerm.charAt(8) == 'w'){
      File fTemp = new File(szFile,"1234");
      currentDir.add(fTemp);
   }else{
    System.out.println("Unallowable Action: don't have permission to create.");
   }/* End if.*/
  }else{
   System.out.println("Unallowable Action : File already present.");
  }/* End if.*/
 }/* End of touch.*/

 /* Removes file in the current directory.*/
 public void rm(String szFile){
  System.out.println("Removing " + szFile);
  if(currentDir.rm(szFile) == false){
   System.out.println("Unallowable Action :File " + szFile + 
                      " cannot be deleted.");
  }/* End if.*/
 }/* End of rm.*/

 /* Open file, check if it can be opened.*/
 public void open(String szFile){
  System.out.println("Opening " + szFile);
  currentDir.open(szFile);
 }/* End of open.*/

}/* End of DirectoryStructure*/

