package net.catpad.infobus.test.dinner;

import net.catpad.infobus.CannotExecuteCommQueueItemException;
import net.catpad.infobus.CommQueueItem;
import net.catpad.infobus.ServiceId;
import net.catpad.infobus.ServiceLauncher;

/**
 * This is where the whole logic of a philosopher's behavior 
 * is encapsulated
 */
public class WakeUpCommQueueItem extends CommQueueItem {

  // This is the philosopher who is served by the current service thread
  private Philosopher philosopher;
  
  public WakeUpCommQueueItem(ServiceLauncher serviceLauncher, Philosopher philosopher) {
    super(serviceLauncher);
    
    this.philosopher = philosopher;
  }

  @Override
  public void execute(ServiceId serviceId)
      throws CannotExecuteCommQueueItemException, InterruptedException {

    Table table = InfoBusTestDinner.table;    

    int leftFork = philosopher.getLeftFork();
    int rightFork = philosopher.getRightFork();

    // Try to take both forks from the table;
    // if it is impossible - do nothing
    if (table.takeForks(leftFork, rightFork)) {

      // Ok, we have both forks - let's eat!
      philosopher.eat();

      // After the meal return forks to the table
      table.returnFork(leftFork);
      table.returnFork(rightFork);

      Philosopher leftNeighbour  = philosopher.getLeftNeighbour();
      Philosopher rightNeighbour = philosopher.getRightNeighbour();

      // Notify our left neighbour that his right fork is available
      serviceLauncher.getInfoBus().postItem(leftNeighbour.getServiceId(),
          new WakeUpCommQueueItem(serviceLauncher,leftNeighbour));

      // Notify our right neighbor that his left fork is available
      serviceLauncher.getInfoBus().postItem(rightNeighbour.getServiceId(),
          new WakeUpCommQueueItem(serviceLauncher,rightNeighbour));

      // Think for a while (it does not hurt)
      philosopher.think();
    }

  }

}