/* 
 * PagingAlgorithm.java (Implements Paging Algorithm System for all type of
 *                       page replacement algorithms.).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 *
 * 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 : PagingAlgorithm.java, v1.0.0 03/01/2001. $
 *
 * ASSUMPTION : If the page that it is trying to read is "FREE", then
 *              it will report "overwriting -1" in the output.
 *
 * Revision History:
 *
 * 1. Created basic structure           Nitin,        v1.0.0  03/01/2001.
 * 2. Added Documentation.              Nitin,        v1.0.1  03/01/2001.
*/

/* Import some of the libraries.*/
import java.lang.*;
import java.util.*;
import java.io.*;


abstract public class PagingAlgorithm{
 public Vector FrameList;           /* Contains the frame list that are in
				       Memory.*/
 public Vector ProgramList;         /* Keeps Pages tables and other 
				       information for currently loaded
				       program.*/
 public int    nNoOfFrames;         /* Gives the total number of frames.*/
 public int    nCurrentPrograms;    /* Count of no of programs in memory.*/    
 public int    nCurrentPagesInMem;  /* Number of Pages that are in the     
				       frames.*/ 
 public boolean bDebug;             /* Tells whether Debug is on/off.*/    
 public int    nPageFault;          /* Counts number of page faults.*/
 public int nGlobalCount;           /* Used for LRU.*/
 

 /* This function is used from the derived class that 
    implements this. This is made so that derived class
    can change the implementation of this function but,
    the base behaviour of the system remains same.*/
 abstract public int getVictim(int nProgName);

 /* This function is called from the Derived class to construct
    this object completely in it's constructor.*/
 public void Create(){
  FrameList = new Vector();         /* Create a new Vector List.*/    
  ProgramList = new Vector();       /* Create a new Program List.*/
  nCurrentPrograms = 0;             /* # of pg. in memory is RESET.*/
  nPageFault = 0;                   /* # of page faults is reset.*/    
  nCurrentPagesInMem = 0;           /* current loaded programs.*/    
  nGlobalCount = 0;
  __CreateFrameStructure();         /* Create all the frames in mem.*/
 }/* End of Constructor.*/

 /* This function creates frame objects as many specified in nNoOfFrames
    and updates it in FrameList.*/
 private void __CreateFrameStructure(){
  
  for(int nIndex=0; nIndex < nNoOfFrames; nIndex++){
   Frame newFrame = new Frame(); 
   FrameList.insertElementAt(newFrame,nIndex);
  }/* End of for.*/

 }/* End of __CreateFrameStructure.*/


 /* Execute "Load" Instruction. When load instruction is called a 
    Program structure is created and added to Program list. It will
    stay in list till it is not unloaded from the memory.*/
 public void load(int nProgName, int nProgSize,int nPageSize){
  int nPages;
  ProgramStruct newProg = new ProgramStruct(nProgName,nProgSize,nPageSize);
  ProgramStruct tempProg;

  /* Before adding check if the program is already in the memory.
     If so, print an error message indicating that reload not
     possible of the program structures.*/
  for(int nIndex=0; nIndex < nCurrentPrograms; nIndex++) {
   tempProg = (ProgramStruct)ProgramList.elementAt(nIndex);   
   if(tempProg.nProgName == nProgName){
    System.out.println("Loading failed : Program already in memory.");
    return;
   }/* End if.*/
  }/* End for.*/

  ProgramList.insertElementAt(newProg,nCurrentPrograms);
  nCurrentPrograms++;
  int nPageInFrame = (int)((nNoOfFrames - nCurrentPagesInMem) * 0.15);
  if(nPageInFrame == 0) nPageInFrame = 1;
  if(nPageInFrame > (int)(nProgSize/nPageSize))
   nPageInFrame = (int)(nProgSize/nPageSize);

  /* Will load as many pages as 10% of current frames are going to be.*/
  if(nProgSize/1000 == 0){
   if(bDebug)
    System.out.println("Loading P"+nProgName+":"+nPageInFrame+" pages in working set,"+
			nProgSize+ " of memory space.");
  }/* End if.*/
  else   
   if(bDebug)
    System.out.println("Loading P"+nProgName+":"+nPageInFrame+" pages in working set,"+
			nProgSize/1000 + "k of memory space.");
  
  int nFrameIndex;
  for(int nIndex=0; nIndex < nPageInFrame; nIndex++){

   /* Write to working set.*/
   __WriteWorkingSet(nProgName,nIndex);

   /* Get the victim page and based on it's interpretation form a opinion.*/
   nFrameIndex = getVictim(nIndex);

   /* Get the current frame status.*/
   Frame actFrame = new Frame();
   actFrame = (Frame)FrameList.elementAt(nFrameIndex);

   /* Add the page to the Dirty List.*/
   if(actFrame.bFrameStatus == true){
    if(actFrame.bDirtyBit == true){
     /* Save the Page in DirtySet for this program.*/
     __SavePage(nProgName,nFrameIndex);
     __DelFromWorkingSet(nProgName,nFrameIndex);
    }/* End if.*/
   }/* End if.*/

   /* Add the page to the Frame List.*/
   actFrame.nProgHolding = nProgName;
   actFrame.nPageHolding = nIndex;
   actFrame.bFrameStatus = true;
   actFrame.bDirtyBit = false;
   actFrame.nAccessFreq = 0;
   actFrame.lTimeStamp = nGlobalCount;
   nCurrentPagesInMem++;
  }/* End for.*/
  nGlobalCount++;
 }/* End of load.*/

 /* Saves the Dirty Page in Dirty Set for the program.*/
 private void __SavePage(int nProgName, int nPageIndex){
  ProgramStruct pgStruct = new ProgramStruct();
  boolean bFound = false;
  int nIndex;

  for(nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName) break;
  }/* End of for.*/

  for(nIndex=0; nIndex < pgStruct.nDirtySetCount; nIndex++)
   if(pgStruct.nDirtySet[nIndex] == nPageIndex){ 
    bFound = true;
    break;
   }/* End if.*/

  if(bFound == true) return;
  pgStruct.nDirtySet[pgStruct.nDirtySetCount++] = nPageIndex;
  
 }/* End of __SavePage.*/

 /* Writes to working set. If it is not present in the working set
    it will write else it will leave it as it is.*/
 private void __WriteWorkingSet(int nProgName, int nPageIndex){
  ProgramStruct pgStruct = new ProgramStruct();
  boolean bFound = false;
  int nIndex;

  for(nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName) break;
  }/* End of for.*/

  for(nIndex=0; nIndex < pgStruct.nWorkingSetCount; nIndex++){
   if(pgStruct.WorkingSet[nIndex] == nPageIndex){ 
    bFound = true;
    break;
   }/* End if.*/
  }/* End for.*/

  if(bFound == true) return;
  pgStruct.WorkingSet[pgStruct.nWorkingSetCount] = nPageIndex;
  pgStruct.nWorkingSetCount++;
 }/* End of __WriteWorkingSet.*/

 /* This function deletes a page for from the working set for the
    given program structure.*/
 private void __DelFromWorkingSet(int nProgName, int nPageIndex){
  ProgramStruct pgStruct = new ProgramStruct();
  boolean bFound = false;
  int nIndex;

  for(nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName) break;
  }/* End of for.*/

  for(nIndex=0; nIndex < pgStruct.nWorkingSetCount; nIndex++)
   if(pgStruct.WorkingSet[nIndex] == nPageIndex){ 
    bFound = true;
    break;
   }/* End if.*/

  if(bFound == false) return;
  for(;nIndex < pgStruct.nWorkingSetCount-1; nIndex++){
   pgStruct.WorkingSet[nIndex] = pgStruct.WorkingSet[nIndex+1];
  }/* End for.*/
  pgStruct.nWorkingSetCount--;
 }/* End of __DelFromWorkingSet.*/



 /* This function performs read operation on the memory, if there
    is page fault it will use the method to find a victim in the page
    and continue reading.
    ASSUMPTION : If the page that it is trying to read is "FREE", then
		 it will report "overwriting -1" in the output.
    */
 public void read(int nProgName, int nPageIndex,int nAddress){
  ProgramStruct pgStruct = new ProgramStruct();
  boolean bFound = false;
  int nIndex;

  nGlobalCount++;
  for(nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName){ 
    bFound = true;
    break;
   }/* End if.*/
  }/* End of for.*/

  boolean bDirty = false;

  if(bFound == false){
   if(bDebug)
    System.out.println("Access Violation P"+nProgName);
   return;
  }/* End if.*/

  /* Check if it is access violation.*/
  if(nAddress > pgStruct.nTotSize){
   if(bDebug)
    System.out.println("Access violation P"+nProgName);
   return;
  }/* End if.*/

  Frame thisFrame;
  if(__SearchInWorkingSet(pgStruct,nPageIndex) == false){
   nPageFault++;
   if(__SearchInDirtySet(pgStruct,nPageIndex) == true) bDirty = true;
    __WriteWorkingSet(nProgName,nPageIndex);
    int nFrameIndex = getVictim(nPageIndex);
    thisFrame = (Frame)FrameList.elementAt(nFrameIndex);

    if(thisFrame.bDirtyBit == true){
     /* Save the Page in DirtySet for this program.*/
     __SavePage(nProgName,nFrameIndex);
     if(bDebug)
     System.out.println("Page fault P"+nProgName+", saving page " + 
			 thisFrame.nPageHolding);
    }else{
     /* If the page is not dirty, then we need not save it.*/
     if(bDirty == false){
       if(bDebug == true)
	System.out.println("Page Fault P"+nProgName+", overwriting page " +
			   thisFrame.nPageHolding);
     }else{
      if(bDebug)
       System.out.println("Page Fault P"+nProgName+", reloading page " +
			   nPageIndex);
     }/* End if.*/
    }/* End else.*/
    __DelFromWorkingSet(thisFrame.nProgHolding,thisFrame.nPageHolding); 
    thisFrame.nProgHolding = nProgName;
    thisFrame.nPageHolding = nPageIndex;
    thisFrame.nAccessFreq  = 0;
    thisFrame.lTimeStamp = nGlobalCount;
    thisFrame.bFrameStatus = true;
    thisFrame.bDirtyBit = false;
   }/* End if.*/
   else
    /* This section only performs "hit".*/
   __UpdatePage(nProgName,nPageIndex,false);
 }/* End of read.*/

 /* Search for a page in the Working set for a given program.*/
 /* Return true if found else false.*/
 private boolean __SearchInWorkingSet(ProgramStruct pgStruct, int nPageIndex){
  for(int nIndex=0; nIndex < pgStruct.nWorkingSetCount; nIndex++){
   if(pgStruct.WorkingSet[nIndex] == nPageIndex) return true;
  }/* End of for.*/
  return false;
 }/* End of __SearchInWorkingSet.*/

 /* Search for a page in the DirtySet for a given program.*/
 /* Return true if found else false.*/
 private boolean __SearchInDirtySet(ProgramStruct pgStruct, int nPageIndex){
  for(int nIndex=0; nIndex < pgStruct.nDirtySetCount; nIndex++){
   if(pgStruct.nDirtySet[nIndex] == nPageIndex) return true;
  }/* End of for.*/
  return false;
 }/* End of __SearchInDirtySet.*/

 /* Updates the page with necessary data. If the bStat is true then it
    will update the dirty bit or else leave it as it is.*/
 private void __UpdatePage(int nProgName, int nPageIndex,boolean bStat){
  Frame thisFrame = new Frame();
  for(int nIndex=0; nIndex < nNoOfFrames; nIndex++){
   thisFrame = (Frame)FrameList.elementAt(nIndex);
   if(thisFrame.nProgHolding == nProgName && 
      thisFrame.nPageHolding == nPageIndex &&
      thisFrame.bFrameStatus == true){
      thisFrame.nAccessFreq++;
      thisFrame.lTimeStamp = nGlobalCount;
      if(bStat == true) thisFrame.bDirtyBit = true;
      else thisFrame.bDirtyBit = false;
      break;
   }/* End if.*/
  }/* End for.*/
 }/* End of __UpdatePage.*/

 /* This function tries to execute write for program and page specified.*/
 public void write(int nProgName, int nPageIndex,int nAddress){
  ProgramStruct pgStruct = new ProgramStruct();
  boolean bFound = false;
  int nIndex;

  nGlobalCount++;
  for(nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName){ 
    bFound = true;
    break;
   }/* End if.*/
  }/* End of for.*/

  boolean bDirty = false;
  if(bFound == true){ 
   /* Check if it is access violation.*/
   if(nAddress > pgStruct.nTotSize){
    if(bDebug)
    System.out.println("Access violation P"+nProgName);
    return;
   }/* End if.*/

   if(__SearchInWorkingSet(pgStruct,nPageIndex) == false){
    nPageFault++;
    if(__SearchInDirtySet(pgStruct,nPageIndex) == true) bDirty = true;
    __WriteWorkingSet(nProgName,nPageIndex);
    int nFrameIndex = getVictim(nPageIndex);
    Frame thisFrame = new Frame();
    thisFrame = (Frame)FrameList.elementAt(nFrameIndex);
    __DelFromWorkingSet(thisFrame.nProgHolding,thisFrame.nPageHolding);
    if(thisFrame.bDirtyBit == true){
     /* Save the Page in DirtySet for this program.*/
     __SavePage(nProgName,nFrameIndex);
     if(bDebug)
     System.out.println("Page fault P"+nProgName+", saving page " +
			 thisFrame.nPageHolding);

    }else{
     if(bDirty == false){
       if(bDebug)
       System.out.println("Page Fault P"+nProgName+", overwriting page " +
			    thisFrame.nPageHolding);
     }else{
       if(bDebug)
       System.out.println("Page Fault P"+nProgName+", reloading page " +
			   nPageIndex);
     }/* End if.*/
    }/* End if.*/
    thisFrame.nProgHolding = nProgName;
    thisFrame.nPageHolding = nPageIndex;
    thisFrame.nAccessFreq  = 0;
    thisFrame.lTimeStamp = nGlobalCount;
    thisFrame.bFrameStatus = true;
    thisFrame.bDirtyBit = true;
   }/* End if.*/
    else
    /* This section only performs "hit".*/
    __UpdatePage(nProgName,nPageIndex,false);
  }else{
   if(bDebug)
    System.out.println("Access Violation P"+nProgName);
  }/* End if.*/
 }/* End of write.*/

 /* Unloads the program from the memory.It also frees all the frames
    that it was holding in the memory.*/
 public void unload(int nProgName){
  ProgramStruct pgStruct;
  Frame         thisFrame;
  boolean bStat = false;

  for(int nIndex=0; nIndex < nCurrentPrograms; nIndex++){
   pgStruct = (ProgramStruct)ProgramList.elementAt(nIndex);
   if(pgStruct.nProgName == nProgName){
    bStat = true;
    for(int nIndexi=0; nIndexi < pgStruct.nWorkingSetCount; nIndexi++){
     for(int nIndexj=0; nIndexj < nNoOfFrames; nIndexj++){
      thisFrame = (Frame)FrameList.elementAt(nIndexj);      
      if(thisFrame.nProgHolding == nProgName &&
	 thisFrame.nPageHolding == pgStruct.WorkingSet[nIndexi] &&
	 thisFrame.bFrameStatus == true){
	 thisFrame.bFrameStatus = false;
	 thisFrame.nProgHolding = -1;
	 thisFrame.bDirtyBit    = false;
	 thisFrame.nPageHolding = -1;
	 thisFrame.nAccessFreq  = 0;
	 thisFrame.lTimeStamp   = 0;
      }/* End if.*/
     }/* End for.*/
     __DelFromWorkingSet(nProgName,pgStruct.WorkingSet[nIndexi]);
    }/* End for.*/
    if(bDebug)
     System.out.println("P"+nProgName+" terminated.");
    ProgramList.removeElementAt(nIndex);
    nCurrentPrograms--;
    return;
   }/* End if.*/
  }/* End for.*/
  if(bStat == false)
   if(bDebug)
   System.out.println("P"+nProgName+" cannot be terminated.");
 }/* End of unload.*/
}/* End of PagingAlgorithm.*/
				 

