/* 
 * Bankers.java (Implements Bankers Algorithm).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 * This file implements routines to collect the data from input file,
 * process command line and also process request as given in the input
 * file. The parsing of input file makes no exceptions of the order
 * in which the data is acquired.
 *
 * (ASSUMPTION : The input file in syntax is similar to the one given
 *               in specs. You can insert as many linefeeds and comments.)
 *               
 * Portions copyright(c) 2000 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 : Bankers.java, v1.4.5 02/23/2001. $
 *            
 * Revision History:
 *
 * 1. Created basic structure           Nitin,        v1.0.0  02/15/2001.
 * 2. Added Documentation.              Nitin,        v1.0.1  02/15/2001.
 * 3. Added Command Line integrity.     Nitin,        v1.1.1  02/16/2001.  
 * 4. Added ProcessCommandLine.         Nitin,        v1.2.1  02/16/2001.    
 *    (Processes the input file, parses for number of processes, resources,
 *     allocation matrix, maximum matrix and to be processed requests.)
 * 5. Modified Documentation.           Nitin,        v1.2.2  02/17/2001.   
 * 6. To Back Data for processing
 *    new requests.                     Nitin,        v1.3.2  02/18/2001.    
 * 7. Added kbhit().                    Nitin,        v1.4.2  02/18/2001.  
 * 8. Final Documentation Check.        Nitin,        v1.4.3  02/19/2001.  
 * 9. Final Variable Name Check.        Nitin,        v1.4.4  02/20/2001.          
 * 10.Final Functionality Check.        Nitin,        v1.4.5  02/21/2001.          
*/

/* Import some of the libraries.*/
import java.lang.*;
import java.util.*;
import java.io.*;

/*****************************************************************************
 * This class simulates the working of bankers algorithm for predefined set
 * of processors, resources and requests for allocation during run time.
 * In this simulation we will be deciding whether we will allocating the
 * requested resource will led us to the any one of the following states:
 * 1. The system will not deadlock,
 * 2. The system is in a safe state, sequence <#1,#2> will terminate,
 * 3. The system is in a unsafe state and
 * 4. The system is in deadlock.
 * 
 * All the new requests will be granted against the initial system 
 * configuration.
 * Max number of processors and resources will be less than 10.
 *
 * This will pick inputs from the file <anyfile.txt>. The file is
 * passed as parameter on the command line.
 ****************************************************************************/

public class Bankers{
  /* stores the name of the file.*/
  public  static  String szFileName;

  /* Multi- and Single- Dimensional storage area.*/
  private static  int[][] Allocation;           /* Stores Allocation.*/
  private static  int[][] tAllocation;          /* Backup- Allocation.*/
  private static  int[][] Max;                  /* Max Resources.*/
  private static  int[]   Reserve;              /* Current available res.*/
  private static  int[]   tReserve;             /* Backed up resource.*/
  private static  int[][] Request;              /* Request Matrix.*/
  private static  int     nProcesses;           /* # of processes.*/
  private static  int     nResources;           /* # of resources.*/
  private static  int[][] Need;                 /* Need = Max - Allocation.*/
  private static  int[][] tNeed;                /* Backed up.*/
  private static  int[]   MaxRes;               /* Maximum Resource.*/
  private static  int     nMaxRequests;         /* # of request.*/
  
  /* Process the command line and simulates the requests for processors.*/
  public static void main(String[] szArgs){
   
   /* Process command line and perform integrity check.*/
   if(szArgs.length == 0){
    System.out.println("** ERROR : No Input file specified.");
    System.out.println("Usage : Bankers <input file>");
    return;
   }/* End if.*/

   /* Store file name.*/
   szFileName = szArgs[0];

   /* Process command line. Will return object containing set of
      parameters that will be used during simulation after parsing
      the input.*/
   ProcessCommandLine();

   System.out.print("Press any key to continue...");
   kbhit();

   /* Read each Request and process the request.*/
   CheckBanker Bank = new CheckBanker();


   for(int nRequestCount=0; nRequestCount <= nMaxRequests; nRequestCount++){
    /* Print the request vector.*/
    System.out.print("Reqest P" + Request[nRequestCount][0] + " <");      
    for(int nRes=1; nRes <= nResources; nRes++){
     if(nRes == nResources) 
      System.out.println(Request[nRequestCount][nRes] + ">");
     else
      System.out.print(Request[nRequestCount][nRes] + ",");
     }/* End if.*/

     /* Process the Request.*/
     /* NOTE : In java single/multi dimensional arrays are passed by 
               reference so these matrix will be destroyed after they
               return back from the call. So we will be updating them
               from the backed storage for processing the next request.
               This is in accordance with the specs to have start 
               configuaration while processing new request.*/
     Bank.ProcessRequest(nProcesses, 
                         nResources,
                         Allocation, 
                         Max, 
                         Need,
                         Reserve,
                         Request,
                         nRequestCount          /* Current Request.*/
     );

     /* After processing the request reset the state.*/
     /* NOTE : We reload from the backed up store.*/
     for(int nIndexI=0; nIndexI<nProcesses; nIndexI++)
      for(int nIndexJ=0; nIndexJ<nResources; nIndexJ++){
       Allocation[nIndexI][nIndexJ] = tAllocation[nIndexI][nIndexJ];
       Need[nIndexI][nIndexJ] = tNeed[nIndexI][nIndexJ];
       if(nIndexI == 0)
        Reserve[nIndexJ] = tReserve[nIndexJ];
      }/* End for.*/

      if(nRequestCount < nMaxRequests){
       System.out.print("Press any key to continue...");
       kbhit();
      }/* End if.*/
     }/* End main for.*/
    }/* End main.*/



  /* This function parses the input file and fills in the data structure
     will properties that are required to run the simulation.
     The parameters are returned as class which extends Object.*/
  private static void ProcessCommandLine(){
   /* Buffer to store the line.*/
   String szLineBuffer;
   String szLowerCaseLine;

   /* Track Line #.*/
   int nLineCount;

   /* Store all the delimters in the string for processing input.*/
   String szDelimiter = new String(":, ");

   /* Current Token.*/
   String szToken;              /* Current Token that is being proceesed.*/        

   int nIn;                     /* The Current Input token which in int.*/
   int nState = 1;              /* FSA State Mode.*/
   int nCount = 0;              /* Temporary Count.*/
   int nValue =0;               /* Temp Scratch Pad.*/
   int nCurrentPro=0;

     
   try{
    /* Open the Input file.*/
    BufferedReader In = new BufferedReader(new FileReader(szFileName));

    /* Initialise Line count.*/
    nLineCount  = 0;
    System.out.println("Initial allocation:");

    /* Read each line and process it.*/
    while((szLineBuffer = In.readLine()) != null){
     /* Check if first line of the character is EOL.
        if so then skip.*/
     if(szLineBuffer.length() == 0) continue;
      /* Increment Line count.*/
      nLineCount++;

      /* Check if the Line is comment or no, if yes then
         it useless to continue tokenizing the string.*/
      if(szLineBuffer.length() >= 2)
       if(szLineBuffer.charAt(0) == '/') 
        if(szLineBuffer.charAt(1) == '/') continue;
        else {
         System.out.println(szFileName + ": Line: " +
         nLineCount + " Improper commenting. (skipping)");
         continue;
        }/* End if.*/

       /* Turn the line into lower case.*/
       szLowerCaseLine = szLineBuffer.toLowerCase();
       
       /* Tokenize all the Objects in the string.*/
       StringTokenizer Tokens = new StringTokenizer(szLowerCaseLine,
                                                    szDelimiter);
       while(Tokens.hasMoreTokens()){
        try{
         nIn = Integer.parseInt(Tokens.nextToken());
         switch(nState){
          case 1:
                 System.out.println("Number of Processes: " + nIn);
                 nState = 2;
                 nProcesses = nIn;
                 break;

          case 2:
                 System.out.print("Number of Resources: " + nIn + " (");
                 nState = 3;
                 nResources = nIn;
                 nValue = nIn;
                 /* Allocation space for structures.*/
                 Allocation = new int[nProcesses][nResources];
                 tAllocation = new int[nProcesses][nResources];
                 Max        = new int[nProcesses][nResources];
                 Need       = new int[nProcesses][nResources];
                 tNeed       = new int[nProcesses][nResources];
                 Reserve    = new int[nResources];
                 tReserve    = new int[nResources];
                 MaxRes     = new int[nResources];
                 /* Request we don't know how much we will be having
                    so we will use MAX_REQUEST.*/
                 Request    = new int[1000][nResources+1];
                 break;

          case 3:
                 nCount++;
                 if(nCount == nValue){
                  nState = 4;
                  MaxRes[nCount-1] = nIn;
                  nCount = -1;
                  System.out.println(nIn + ")");
                 }else{
                  System.out.print(nIn + ",");
                  MaxRes[nCount-1] = nIn;
                 }/* End if.*/
                 break;

          case 4:
                 nCount++;
                 if(nCount == 0){
                  System.out.print("Process "+nIn+":"+" Allocation:");
                  nCurrentPro = nIn;
                  break;
                 }/* End if.*/

                 if(nCount == nValue+1){
                  System.out.print(" Max: ");
                 }/* End if.*/

                 if(nCount <= nValue){
                  Allocation[nCurrentPro-1][(nCount-1)%nResources] = nIn;
                  tAllocation[nCurrentPro-1][(nCount-1)%nResources] = nIn;
                 }else{
                  Max[nCurrentPro-1][(nCount-1)%nResources] = nIn;
                 }/* End if.*/

                 if(nCount == nValue*2){
                  nCount = -1;
                  nCurrentPro = -1;
                  System.out.println(nIn);
                 }else{
                  if(nCount == nValue)
                   System.out.print(nIn);
                  else
                   System.out.print(nIn+",");
                 }/* End if.*/
                 break;

          case 5:
                 nCount++;
                 if(nCount == 0){
                  nCurrentPro++;
                  Request[nCurrentPro][0] = nIn;
                  break;
                 }/* End if.*/

                 if(nCount == nValue){
                  Request[nCurrentPro][nCount] = nIn;
                  nCount = -1;
                 }else{
                  Request[nCurrentPro][nCount] = nIn;
                 }/* End if.*/
                 break;

         }/* End of switch.*/
        }/* End of try.*/
        catch(NumberFormatException e){
         /* As all the characters that come here are not 
            actual integers which can be converted, we will
            just negelect that and just keep track of what
            we are currently inputing from the file.*/
            if(nState == 4){ 
               nState = 5;
               nCount = -1;
            }/* End if.*/
        }/* End of catch.*/
       }/* End of while.*/
    }/* End of while.*/
    In.close();
   }catch(Exception e){
    System.out.println("** ERROR : Input file " + szFileName + " not found.");
    System.out.println("Abnormal Termination.");
    System.exit(-1);
   }/* End of try catch Block.*/

   Compute();
   nMaxRequests = nCurrentPro;
  }/* End of ProcessCommandLine.*/

  /* Computes the Reserve Matrix for from Allocation and Max.*/
  private static void Compute(){
     
   int nColumnSum = 0;
   System.out.print("Reserve :");
   for(int nIndexC=0; nIndexC < nResources; nIndexC++){
    nColumnSum = 0;
    for(int nIndexR=0; nIndexR < nProcesses; nIndexR++)
     nColumnSum += Allocation[nIndexR][nIndexC];
     
    Reserve[nIndexC] = MaxRes[nIndexC] - nColumnSum;
    tReserve[nIndexC] = Reserve[nIndexC];
    if(nIndexC == nResources-1)
     System.out.println(Reserve[nIndexC]);
    else
     System.out.print(Reserve[nIndexC] + ",");
   }/* End for.*/

   for(int nIndexR=0; nIndexR < nProcesses; nIndexR++){
    for(int nIndexC=0; nIndexC < nResources; nIndexC++){
     Need[nIndexR][nIndexC] = Max[nIndexR][nIndexC] - Allocation[nIndexR][nIndexC];
     tNeed[nIndexR][nIndexC] = Max[nIndexR][nIndexC] - Allocation[nIndexR][nIndexC];
    }/* End for.*/
   }/* End for.*/
  }/* End of ComputeReserve.*/

  /* Wait till <ENTER> key is pressed. Upon receiving that skip all
     the characters that were pressed before pressing enter. If these
     characters are not skipped then it will intefere when next
     read is generated.*/
  private static void kbhit(){
   try{
    System.in.read();
    System.in.skip(System.in.available());
   }catch(Exception e){
    e.printStackTrace();
   }/* End of try-catch block.*/
   System.out.println("");
  }/* End of kbhit.*/
}/* End of Bankers.*/

