package de.duehl.basics.datetime.time.watch;

/*
 * Copyright 2021 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.io.Serializable;

import de.duehl.basics.datetime.time.TimeHelper;

/**
 * Eine Klasse zur Zeitmessung.
 *
 * @version 1.01     2021-03-17
 * @author Christian Dühl
 */

public class StopWatch implements WatchBase, Serializable {

    private static final long serialVersionUID = 1L;

    /** Startzeit in Millisekunden. */
    private long startTime;

    /** Gibt an, ob die Uhr angehalten wurde. */
    private boolean stopped;

    /** Anzahl der gelaufenen Sekunden, wenn die Uhr angehalten wurde. */
    private long stopTime;

    /** Konstruktor. Startet die Stoppuhr automatisch. */
    public StopWatch() {
        start();
    }

    /** Copy-Konstruktor. */
    public StopWatch(StopWatch that) {
        this.startTime = that.startTime;
        this.stopped = that.stopped;
        this.stopTime = that.stopTime;
    }

    /** Startet die Stoppuhr. */
    public void start() {
        startTime = TimeHelper.getCurrentTimeInMilliseconds();
        stopped = false;
    }

    /**
     * Liest die Zeit auf der Stoppuhr ab. Wenn die Stoppuhr mit stop()
     * angehalten wurde, wird die angehaltene Zeit zurückgegeben, ansonsten
     * die Zeit, die vom Start bis jetzt vergangen ist.                                  <br/><br/>
     *
     * Die Zeit wird in einem von Menschen lesbarem Format erzeugt.
     *
     * @return Zwischenzeit der Stoppuhr im Format HH:MM:SS.
     */
    @Override
    public String getTime() {
        return TimeHelper.secondsToHoursMinutesSeconds(getTimeInSeconds());
    }

    /** Gibt die Zwischenzeit in Sekunden zurück. */
    @Override
    public long getTimeInSeconds() {
        return getTimeInMilliSeconds() / 1000;
    }

    /** Gibt die Zwischenzeit in Millisekunden zurück. */
    long getTimeInMilliSeconds() {
        if (stopped) {
            return stopTime - startTime;
        }
        else {
            return TimeHelper.getCurrentTimeInMilliseconds() - startTime;
        }
    }

    /** Hält die Stoppuhr beim ersten Aufruf von stop() an, weitere Aufrufe sind wirkungslos. */
    public void stop() {
        if (!stopped) {
            stopTime = TimeHelper.getCurrentTimeInMilliseconds();
            stopped = true;
        }
    }

    /**
     * Falls die Stoppuhr bereits läuft, passiert nichts. Wurde die Stoppuhr vorher angehalten,
     * läuft sie nun vom bisherigen Stand (nicht von null, dafür müsste start() gewählt werden) aus
     * weiter.
     */
    public void restart() {
        if (stopped) {
            long newStartTime = TimeHelper.getCurrentTimeInMilliseconds();
            long oldStoppWatchTimeInMillies = getTimeInMilliSeconds();
            startTime = newStartTime - oldStoppWatchTimeInMillies;
            stopped = false;
            stopTime = 0;
        }
    }

    /** Gibt an, ob die Uhr angehalten wurde. */
    public boolean isStopped() {
        return stopped;
    }

    /** Stringrepräsentation. */
    @Override
    public String toString() {
        return "StopWatch [" + getTime() + "]";
    }

}
