/* 
 * ReaderWriterObs.java (Implements Readers/Writers Using 
 *                       Event Notification).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 * 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 : ReaderWriterObs.java, v1.0.0 02/12/2001. $
 *
 * Revision History:
 *
 * 1. Created Basic Structure.       Nitin,        v1.0.0  02/07/2001.
 * 2. Documentation Added,           Nitin,        v1.0.1  02/07/2001.        
 * 3. Final Documentation Check      Nitin
 * 4. Final Variable Name Check      Nitin
 * 5. Final Functionality Check      Nitin
 * 6. Note: All Readers/Writers were created on the same day.
*/

import java.util.*;
import java.lang.*;

/* Start of ReaderWriterObs.*/
public class ReaderWriterObs extends Observable{
     int nNumberOfWriters;              /* Tracks # of Writers.*/
     int nNumberOfReaders;              /* Tracks # of Readers.*/
     boolean bEndCondition;             /* End Condition for it.*/
     int nEvents;                       /* Basically # of writes.*/
     long lStartTime,lStopTime;         /* Timers used to print messages
                                           during simulation.*/
     int nReads;                        /* # of read events.*/
     int nWrites;                       /* # of write events.*/
     int nTok;                          /* current token number.*/
     int nInsRead;                      /* # of readers read.*/
     boolean bSet;                      /* to allow one writer.*/

     /* Synchronization Mechanism.*/
     Semaphore Block;                   /* Block piece of code.*/
     Semaphore WBlock;                  /* Same here.*/
     
     ReaderWriterWObs Writer[];      /* Array of Writers.*/
     ReaderWriterRObs Reader[];      /* Array of Readers.*/
     ObsState State;                 /* State of the Observable.*/   

     
     /* 
      * This function is constructor for this class.
      */
     public ReaderWriterObs( int nNumberOfWriter,
                             int nNumberOfReader,
                             int nEvents,
                             long lStartTime){

       /* Store them within this P/C controller.*/
       this.nNumberOfWriters = nNumberOfWriter;
       this.nNumberOfReaders = nNumberOfReader;
       this.nEvents           = nEvents;  
       this.lStartTime        = lStartTime;   

       /* Initialise Synchronization Mechanism.*/
       Block   = new Semaphore(1);
       WBlock  = new Semaphore(1);
       
       bSet       = false;
       nReads     = 0;
       nWrites    = 0;
       nTok       = 0;
       nInsRead   = 0;
       State = new ObsState();
     }/* End of BoundedBufferSem.*/

     /*
      * This program is heart of this                            
      */
      public void Start(){
        /* Create all the producers and consumers.*/
        Writer = new ReaderWriterWObs[nNumberOfWriters];
        Reader = new ReaderWriterRObs[nNumberOfReaders];

        /* Print the Start Time.*/
        long lInterStartTime = System.currentTimeMillis();
        TimeFormat Time = new TimeFormat();
        System.out.println("Started using Event Notification at time " + 
                           Time.formatTime(lInterStartTime - lStartTime));
        
        for(int nIndex=0; nIndex < nNumberOfReaders; nIndex++){
         Reader[nIndex] = new ReaderWriterRObs(nIndex+1,this);
         addObserver(Reader[nIndex]);
         Reader[nIndex].start();
        }/* End For.*/
        
        /* Initialise their Environment.*/
        for(int nIndex=0; nIndex < nNumberOfWriters; nIndex++){
         Writer[nIndex] = new ReaderWriterWObs(nIndex+1,this);
         addObserver(Writer[nIndex]);
         Writer[nIndex].start();
        }/* End for.*/

        boolean bAllDead = false;
        while(bAllDead == false){
         bAllDead = true;
         for(int nIndex=0; nIndex < nNumberOfWriters; nIndex++){
          if(Writer[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/

         for(int nIndex=0; nIndex < nNumberOfReaders; nIndex++){
          if(Reader[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/
        }/* End While.*/

        lStopTime = System.currentTimeMillis();
        System.out.println("Completed using Event Notification at time " + 
                           Time.formatTime(lStopTime - lStartTime));
       }/* End of Start.*/

       /*
        * Locks Everything to read in the database.
        */
        public synchronized void Read(){

          nReads++;
          nInsRead++;
          
          if(nReads == nEvents*nNumberOfReaders){
            /* Send message when all events are completed to reader.*/
            State.Set(3);
            setChanged();
            notifyObservers((Object)State);
            return;
          }/* End if.*/

          if(nInsRead == nNumberOfReaders){
           /* All readers read send message to writer to write.*/
           nInsRead = 0;
           bSet = false;
           State.Set(4);
           setChanged();
           notifyObservers((Object)State);
          }/* End if.*/
          return;
        }/* End StartRead.*/

        /* Starts Writing of database.*/
         public synchronized void Write(){

           /* If one writer wrote then don't allow other writers to
              get in.*/
           if(bSet == true) return;
          
          /* SIMULATE CREATE DATABASE RECORD.*/
          /* Create a Record and notify all readers to read in the
             value.*/

             nTok++;
             nWrites++;
             bSet = true;

             if(nWrites == nEvents){ 
              /* Send write complete to all Writers, so that they will
                 terminate.*/
              State.Set(2);
              setChanged();
              notifyObservers((Object)State);
              return;
             }/* End if.*/

             /* Notify saying that new token has been written to shared
                location.*/
             State.Set(1);
             setChanged();
             notifyObservers((Object)State);

             return;
         }/* End of StartWrite.*/
}/* End of ReaderWriterObs.*/

