
// MultWorkerCell.java
// Andrew Davison, ad@coe.psu.ac.th, May 2023

/* In this version of the problem, each worker carries
   out multiple tasks until the matrix multiplication is
   completed. 

   As in MatrixMultRow.java, n rows of the first matrix 
   are added to the space as tuples of the form:
     ("ROW", row-id, int[])
  
   The n columns of the second matrix are added to the 
   space as tuples of the form:
     ("COLUMN", col-id, int[])

   The new data are n*n TASK tuples of the form:
      ("TASK", row-id, col-id)
 
   These are the tasks for all the workers. A worker *removes* a
   TASK tuple, and then *reads* in copies of the corresponding 
   row and column arrays.
  
   The result (a single integer value) is put into the space in
   a tuple of the form:
       ("RESULT", row-id, col-id, result)

   When there are no TASK tuples left, MatrixMultCell will issue a 
   ("DIE") tuple, which is used by the workers to terminate.

  Usage:
    > compile.bat MultWorkerCell.java

    Part of the application made up of:
       * MatrixMultCell.java
       * MultWorkerCell.java
*/

import org.jspace.*;


public class MultWorkerCell implements Runnable
{
  private Space space;
  private PrintAreas pas;
  private int id;


  public MultWorkerCell(int id, PrintAreas pas, Space space)
  {
    this.space = space;
    this.pas = pas;
    this.id = id;
    pas.setTitle(id, "W-"+id);
  }


  public void run()
  {
    try {
      while(true) {     // keep doing tasks
        Object[] res = space.queryp(new ActualField("DIE"));
             // if there's a DIE, then terminate
        if (res != null) {
          pas.println(id, "Terminating");
          break;
        }
  
        // otherwise, get any TASK calculation
        Object[] cell = 
            space.getp( new ActualField("TASK"),
                       new FormalField(Integer.class),  // row
                       new FormalField(Integer.class)); // col
        if (cell != null)  // will be null if no tasks left
          calcItem((int)cell[1], (int)cell[2]);
        SpaceUtils.pause(10);  
      }
    }
    catch (InterruptedException e) 
    {  System.out.println("W-" + id + " error: " + e);  }
  } /* run */


  private void calcItem(int row, int col)
                    throws InterruptedException
  /* a row*col calculation uses the corresponding
     row and column tuple data. The result is added
     to the space as a RESULT tuple.
  */
     
  {
    Object[] rowObj =   // read in row of first matrix
        space.query( new ActualField("ROW"),
                   new ActualField(row),             // index
                   new FormalField(Object.class));   // array
    int[] rowArr = (int[])rowObj[2];
 
    Object[] colObj =   // read in column of second matrix
        space.query( new ActualField("COLUMN"),
                   new ActualField(col), // index
                   new FormalField(Object.class));  // array
    int[] colArr = (int[])colObj[2];

    int result = 0;  // multiply together
    for (int i=0; i< rowArr.length; i++)
      result += rowArr[i]*colArr[i];

    // another cell calculation finished
    space.put("RESULT", row, col, result);
    pas.println(id, "Calculation of (" +
             row + ", " + col + ") = " + result);
  } // end of calcItem()


}  // end of MultWorkerCell class
