
// Smoker.java
// Andrew Davison, ad@coe.psu.ac.th, May 2023

/* The Cigarette smokers problem:
  https://en.wikipedia.org/wiki/Cigarette_smokers_problem

  Each smoker has an infinite 
  supply of one ingredient — tobacco, paper, or matches,
  and must obtain the other two ingredients from the table
  when they are both added at the same time by the agent.

  This is implemented by the thread repeatedly looking for
  a tuple of the form:
     ("SUPPLIES", supplyNo, ingredient1.value + ingredient2.value)

  The 'supplyNo' argument isn't needed by the algorithm. It just
  records how many times the agent had put ingredients on the table.

  The looking is done in two stages -- first a query() examines
  the supplies, and if they match this smoker's needs then a get()
  removes the tuple.

  When the smoker has finished making a cigarette, he notifies
  the agent by placing a tuple into the space:
          ("FIN", smoker name, supplyNo)

  Usage:
    > compile.bat Smoker.java

    Part of the application made up of:
       * CigSmokers.java
       * Smoker.java
       * Agent.java
       * Supplies.java
*/

import java.util.*;

import org.jspace.*;


public class Smoker implements Runnable
{
  private Supplies owns, needs1, needs2;
    /* this smoker has the 'owns' ingredient, and needs
       ingredients 'needs1' and 'needs2' */

  private int pasID;
  private PrintAreas pas;
  private Space table;


  public Smoker(Supplies owns, Supplies n1, Supplies n2,
                PrintAreas pas, int pasID, Space s)
  {
    this.owns = owns;
    needs1 = n1; needs2 = n2;

    this.pas = pas;
    this.pasID = pasID;
    pas.setTitle(pasID, "Smoker with " + owns);
    table = s;
  }  // end of Smoker()


  public void run ()
  {
    int supplies = needs1.getValue() + needs2.getValue();
            /* instead of examining supply strings, 
               test for the sum of their values  */
    try {
      while (true) {
        // examine the supplies
        Object[] supplyObj = table.query( 
                new ActualField("SUPPLIES"), 
                new FormalField(Integer.class),   
                          // supplyNo; not needed by the algorithm
                new FormalField(Integer.class));  // supplies value

        if (((int)supplyObj[2]) == supplies) { // matches the needs?
          int supplyNo =  (int)supplyObj[1];
          // remove the supplies
          table.get( new ActualField("SUPPLIES"), 
                     new FormalField(Integer.class),
                     new FormalField(Integer.class));

          pas.println(pasID, "Got " + needs1 + ", " + needs2 +
                            " from s" + supplyNo);
          SpaceUtils.pause(2000);  // take time to make cigarette

          // report finish of this smoking task
          table.put("FIN", "Smoker with " + owns, supplyNo);
        }
      }
    }
    catch (InterruptedException e) 
    {  pas.println(pasID, "Error: " + e);  }
  } /* run */

}  // end of Smoker class
