/* 
 * BoundedBufferSem.java (Implements Producer and Consumer Using Semaphores).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 *
 * This file implements producer using semaphores.This puts the data 
 * into the buffer and other side which is consumer removes from it.
 * The buffer has finite size so the producer has to wait when it's
 * full, and the consumer has to wait when it's empty. And, of course
 * all elements added to the queue by the producer must be seen by 
 * the consumer exactly once.
 * 
 * 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 : BoundedBufferSem.java, v1.0.0 02/07/2001. $
 *
 * Revision History Revisited:
*/

import java.util.*;
import java.lang.*;

/* Start of BoundedBufferSem.*/
public class BoundedBufferSem{
     int nNumberOfProducers;            /* Tracks # of Producers.*/
     int nNumberOfConsumers;            /* Tracks # of Consumers.*/
     int nNumberOfSlots;                /* Number of Free Slots in Buffer */
     boolean bEndCondition;             /* End Condition for it.*/
     int nEvents;                       /* Basically # of items to be 
                                           produced.*/

     long lStartTime,lStopTime;         /* Timers used to print messages
                                           during simulation.*/
     int nItem;
     int nNumberOfItemsProduced;        /* Tracks Events.*/
     int nNumberOfItemsConsumed;        /* Tracks Completed Events.*/

     /* Synchronization Mechanism.*/
     Semaphore Mutex;                   /* This is basically used to
                                           protect the database.*/
     Semaphore Empty;                   /* Used to check buffer empty.*/
     Semaphore Full;                    /* Trigger when buffer full.*/
     Semaphore Block;                   /* Block Consumer piece of code.*/
     Semaphore WBlock;

     BoundedBufferPSem Producer[];      /* Array of Producers.*/
     BoundedBufferCSem Consumer[];      /* Array of Consumers.*/

     
     /* 
      * This function is constructor for this class.
      */
     public BoundedBufferSem(int nNumberOfProducer,
                             int nNumberOfConsumer,
                             int nNumberOfSlots,
                             int nEvents,
                             long lStartTime){

       /* Store them within this P/C controller.*/
       this.nNumberOfProducers = nNumberOfProducer;
       this.nNumberOfConsumers = nNumberOfConsumer;
       this.nNumberOfSlots    = nNumberOfSlots;
       this.nEvents           = nEvents;  
       this.lStartTime        = lStartTime;   

       /* Initialise Synchronization Mechanism.*/
       Mutex = new Semaphore(1);
       Empty = new Semaphore(nNumberOfSlots);
       Full  = new Semaphore(0);
       Block = new Semaphore(1);
       WBlock = new Semaphore(1);

       /* Initialise Items.*/
       nItem = 0;
       nNumberOfItemsProduced = 0;
       nNumberOfItemsConsumed = 0;

     }/* End of BoundedBufferSem.*/

     /*
      * This program is heart of this                            
      */
      public void Start(){
        /* Create all the producers and consumers.*/
        Producer = new BoundedBufferPSem[nNumberOfProducers];
        Consumer = new BoundedBufferCSem[nNumberOfConsumers];

        /* Print the Start Time.*/
        long lInterStartTime = System.currentTimeMillis();
        TimeFormat Time = new TimeFormat();
        System.out.println("Started using Semaphores at time " + 
                           Time.formatTime(lInterStartTime - lStartTime));

        for(int nIndex=0; nIndex < nNumberOfConsumers; nIndex++){
         Consumer[nIndex] = new BoundedBufferCSem(nIndex+1,this);
         Consumer[nIndex].start();
        }/* End For.*/

        /* Initialise their Environment.*/
        for(int nIndex=0; nIndex < nNumberOfProducers; nIndex++){
         Producer[nIndex] = new BoundedBufferPSem(nIndex+1,this);
         Producer[nIndex].start();
        }/* End for.*/

        boolean bAllDead = true;
        while(bAllDead == false){
         bAllDead = true;
         for(int nIndex=0; nIndex < nNumberOfProducers; nIndex++){
          if(Producer[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/

         for(int nIndex=0; nIndex < nNumberOfConsumers; nIndex++){
          if(Consumer[nIndex].isAlive() == true){ 
           bAllDead = false;
           break;
          }/* End if.*/
         }/* End for.*/
        }/* End While.*/

        lStopTime = System.currentTimeMillis();
        System.out.println("Completed using Semaphores at time " + 
                           Time.formatTime(lStopTime - lStartTime));

      }/* End of Start.*/

      /*
       * Produce and item needed by the Producer. The item is basically
       * a count which has unqiue ID.
      */
      public int ProduceItem(BoundedBufferPSem pThis){

       /* PRODUCE AN ITEM.*/
       WBlock.P();
       if(nNumberOfItemsProduced >= nEvents){
        pThis.SetEndCondition(false);
        WBlock.V();
        return -1;
       }/* End if.*/

       /* Produce an item and update global items produced by all
          the producers.*/
       nItem++;
       nNumberOfItemsProduced++;
       WBlock.V();
       return (1);
      }/* End ProduceItem.*/

      /*
       * Inserts an item into the Shared Buffer.
       */
       public void InsertItem(int nItem){

        /* INSERT AN ITEM IN THE SHARED BUFFER.*/

        /* NOTE : This part is just simulated. Here there is nothing 
                  has been inserted into the buffer. But, it'a all
                  ready to insert any item in the shared buffer.*/


       }/* End of InsertItem.*/

       /*
        * Gets an Item from the shared Buffer.
        */
        public int GetItem(){

         /* REMOVE AN ITEM FROM THE SHARED BUFFER.*/
         /* NOTE: There is nothing that is removed from here, just
                  counts are updated. */
         return 1;
        }/* End of GetItem.*/

       /*
        * Consume Item will just display the ID.
        */
        public void ConsumeItem(int nItem,BoundedBufferCSem cThis){

          /* Makes a check on number of items to be consumed is
             equal to the total number of events that were produced.*/
          if(nNumberOfItemsConsumed == nEvents){
           cThis.SetEndCondition(false);
          }else{

                 /* CONSUME AN ITEM.*/
                 /* NOTE : This piece of code simulates Cosume Item
                           for the cosumer.*/
                 nNumberOfItemsConsumed++;
          }/* End if.*/
          
        }/* End of ConsumeItem.*/

        /*
         *
         */
         public boolean ConsumeCheck(){
          if(nNumberOfItemsConsumed == nEvents)
           return true;
          else
           return false;
         }/* End of ConsumeCheck.*/

}/* End of BoundedBufferSem.*/


