package counter;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;

public class Controller {

  @FXML
  public TextField counterAField, counterBField, computedSumField, arithSumField;

  @FXML
  private Button startA, startB, pauseButton;

  private int counterSum = 0;
  public int getCounterSum() { return counterSum; }
  public void setCounterSum(int newval) { counterSum = newval; }

  private UpCounterA upA;
  private UpCounterB upB;
  private Thread counterAThread, counterBThread;
  private boolean paused = false;
  private static int PAUSE_LOOP_WAIT = 100;
  private Object pause_lock = new Object();
  public static int COMPUTE_SUM_TIME = 1; // same for both threads

  public final Object sum_update_lock = new Object();

  public Controller() {
  }

  // simulate doing work for a number of milliseconds
  //    Early termination of the sleep is ignored
  public void doWorkFor(int milliseconds) {
    try {
      Thread.sleep(milliseconds);
    } catch (InterruptedException e) {
      // do nothing
    }
  }

  // thread-safe setting way to set a field on the screen
  public void setTo(TextField target, int value) {
    Platform.runLater(() -> target.setText(value + ""));
    // causes crash:
    //target.setText(value + "");
  }

  @FXML
  public void startUpCounterA() {
    if (upA == null) {
      upA = new UpCounterA(this);
      counterAThread = new Thread(upA);
      // force shutting down the thread when exit the program - this is not a
      //    clean way to quit threads, but works fine in this case
      counterAThread.setDaemon(true);
      counterAThread.start();
      startA.setDisable(true);
      pauseButton.setDisable(false);
      if ( startB.isDisable() )
        pauseButton.requestFocus();
      else
        startB.requestFocus();
    }
  }

  @FXML
  public void startUpCounterB() {
    if (upB == null) {
      upB = new UpCounterB(this);
      counterBThread = new Thread(upB);
      // force shutting down the thread when exit the program - this is not a
      //    clean way to quit threads, but works fine in this case
      counterBThread.setDaemon(true);
      counterBThread.start();
      startB.setDisable(true);
      pauseButton.setDisable(false);
      if ( startA.isDisable() )
        pauseButton.requestFocus();
      else
        startB.requestFocus();
    }
  }

  @FXML
  public void clickPause() {
    synchronized(pause_lock) {
      paused = !paused;
      Platform.runLater(() -> pauseButton.setText(paused ? "Resume" : "Pause"));
      if (!paused) {
        Platform.runLater(() -> arithSumField.setText(""));
        pause_lock.notifyAll(); // wake any waiting processes so they can recheck pause_lock
      } else {
        Platform.runLater(() -> arithSumField.setText((upA.getCount() + upB.getCount()) + ""));
      }
    }
  }

  public void checkPaused() {
    synchronized (pause_lock) {
      while (paused) {
        try {
          pause_lock.wait(PAUSE_LOOP_WAIT);
        } catch (InterruptedException e) {
          // early termination; this is ignored and the job just re-waits if paused is still true
        }
      }
    }
  }
}
