package stateandbehavior;

public class StopWatch {

  private int totalTicks = 0;
  private int totalTime = 0;
  private int lapTimeOffset = 0;        // amount of ticks at end of last lap
  private int lastLapTimeOffset = -1;   // amount of ticks at start of last lap
  private boolean hasBeenStarted = false;
  private boolean hasBeenStopped = false;

  /** returnerer true om klokken har blitt startet eller false om den ikke har blitt startet */
  public boolean isStarted() {
    return this.hasBeenStarted;
  }
  
  /** returnerer true om klokken har blitt stoppet eller false om den ikke har blitt stoppet. Merk at her snakker vi om at klokken har blitt stoppet, ikke om klokken går eller ikke. */
  public boolean isStopped() {
    return this.hasBeenStopped;
  }
  
  /** returnerer det totale antall tikk (millisekunder) som har gått i levetiden til klokken uavhengig om klokken har vært startet eller stoppet. */
  public int getTicks() {
    return this.totalTicks;
  }
  
  /** returnerer antall tikk som har gått under tidtakningen. Hvis tidtakningen ikke har startet returner -1. Merk at hvis klokken er startet, men ikke stoppet, skal metoden returnere antall tikk som har gått siden klokken ble startet til nå. Hvis klokken er stoppet skal metoden returnere antall tikk som har gått fra klokken ble startet til klokken ble stoppet. */
  public int getTime() {
    return this.hasBeenStarted ? totalTime : -1;
  }
  
  /** returnerer antall tikk som har gått under nåværende rundetid til nå. Hvis tidtakningen ikke har startet returner -1. */
  public int getLapTime() {
    return this.hasBeenStarted ? totalTime - lapTimeOffset : -1;
  }
  
  /** returnerer lengden på forrige avsluttede rundetid. Hvis det ikke er noen tidligere rundetider returner -1. */
  public int getLastLapTime() {
    return this.lastLapTimeOffset != -1
      ? lapTimeOffset - lastLapTimeOffset
      : -1;
  }
  
  /** forteller klokken at ticks antall tikk har gått. */
  public void tick(int ticks) {
    // this.totalTicks += ticks;
    if (this.hasBeenStarted ^ this.hasBeenStopped)
      this.totalTime += ticks;
  }
  
  /** starter klokken. */
  public void start() {
    this.hasBeenStarted = true;
  }
  
  /** avslutter nåværende rundetid og starter en ny. */
  public void lap() {
    this.lastLapTimeOffset = this.lapTimeOffset;
    this.lapTimeOffset = this.totalTime;
  }
  
  /** stopper klokken. */
  public void stop() {
    if (this.hasBeenStarted) {
      this.lap();
      this.hasBeenStopped = true;
    }
  }

  public String toString() {
    return String.format(
    """
    {
      id:          %d
      ticks:       %d
      time:        %d
      currentLap:  %d
      lastLap:     %d
      hasStarted:  %b
      hasStopped:  %b
    }
    """
    , this.hashCode()
    , this.totalTicks
    , this.getTime()
    , this.getLapTime()
    , this.getLastLapTime()
    , this.hasBeenStarted
    , this.hasBeenStopped
    );
  }

  public static void main(String[] args) {
    StopWatch sw = new StopWatch();
    System.out.println(sw);
    sw.tick(1);
    System.out.println(sw);
    sw.start();
    System.out.println(sw);
    sw.tick(3);
    System.out.println(sw);
    sw.lap();
    System.out.println(sw);
    sw.tick(2);
    System.out.println(sw);
    sw.stop();
    System.out.println(sw);
    sw.tick(2);
    System.out.println(sw);
  }
}
