package de.fau.cs.mad.fly.game;
import java.util.ArrayList;
import java.util.List;
import de.fau.cs.mad.fly.game.GameController.GameState;
/**
* Manages the time in the game and calls listener if time in seconds has
* changed or the game time is over.
*
* @author Lukas Hahmann <lukas.hahmann@gmail.com>
*
*/
public class TimeController implements GameStateListener {
private int initTimeInMilliSeconds;
private int currentTimeInMilliSeconds;
private float timeSinceStartInMilliSeconds;
private long initTimeStampInMilliSeconds;
private boolean paused;
private float pauseTimeInSeconds;
private long pauseTimeStampInMilliSeconds;
private int bonusTimeInSeconds;
private List<IntegerTimeListener> integerTimeListeners;
private List<TimeIsUpListener> timeIsUpListeners;
private int size;
public TimeController() {
initTimeInMilliSeconds = 0;
integerTimeListeners = new ArrayList<IntegerTimeListener>();
timeIsUpListeners = new ArrayList<TimeIsUpListener>();
}
/**
* Sets the time to a certain second value.
*
* @throws IllegalArgumentException
* for negative parameter.
*/
public void initAndStartTimer(int seconds) {
if (seconds < 0) {
throw new IllegalArgumentException("TimeController.initTimer(" + seconds + ") got a negative parameter.");
}
initTimeInMilliSeconds = seconds * 1000;
initTimeStampInMilliSeconds = System.currentTimeMillis();
currentTimeInMilliSeconds = initTimeInMilliSeconds;
timeSinceStartInMilliSeconds = 0f;
pauseTimeStampInMilliSeconds = 0;
pauseTimeInSeconds = 0;
bonusTimeInSeconds = 0;
paused = false;
integerTimeChanged();
}
/**
* Adds the delta to the current time.
* <p>
*
* If time is up, {@link #timeIsUp()} is called,
* <p>
* if the integer of the time changes (ceiled) {@link #integerTimeChanged()}
* is called. Time will never be below 0.
*/
public void checkTime() {
if (!paused) {
int timeBeforeInSeconds = currentTimeInMilliSeconds / 1000;
timeSinceStartInMilliSeconds = System.currentTimeMillis() - initTimeStampInMilliSeconds - pauseTimeInSeconds;
currentTimeInMilliSeconds = (int) (initTimeInMilliSeconds - (System.currentTimeMillis() - initTimeStampInMilliSeconds) + pauseTimeInSeconds * 1000f + bonusTimeInSeconds * 1000f);
if (currentTimeInMilliSeconds < 1) {
currentTimeInMilliSeconds = 0;
timeIsUp();
}
if (timeBeforeInSeconds != (int) Math.ceil(currentTimeInMilliSeconds / 1000f)) {
integerTimeChanged();
}
}
}
/**
* Adds bonus time in seconds to the bonus time.
*
* @param bonusTime
* The bonus time in seconds to add.
*/
public void addBonusTime(float bonusTime) {
this.bonusTimeInSeconds += bonusTime;
}
/**
* Pauses the {@link TimeController} until {@link #resume()} is called.
* <p>
* If the {@link TimeController} is already paused, nothing happens.
*/
public void pause() {
if (!paused) {
paused = true;
pauseTimeStampInMilliSeconds = System.currentTimeMillis();
}
}
/**
* Restarts the {@link TimeController} after {@link #pause()} was called.
* <p>
* If {@link #resume()} is called, without the {@link TimeController} being
* paused, nothing happens.
*/
public void resume() {
if (paused) {
paused = false;
pauseTimeInSeconds += (System.currentTimeMillis() - pauseTimeStampInMilliSeconds) / 1000;
pauseTimeStampInMilliSeconds = 0;
}
}
/**
* Getter for the current integer time in seconds.
*
* @return Current integer time in seconds.
*/
public int getIntegerTime() {
return (int) Math.ceil(currentTimeInMilliSeconds/1000f);
}
/**
* More exact method to get the remaining time, compared to
* {@link #getIntegerTime()}
*
* @return exact remaining time as float
*/
public float getCurrentTimeInMilliSeconds() {
return currentTimeInMilliSeconds;
}
/**
* Getter for the integer time since the start in seconds.
*
* @return Integer time since the start in seconds.
*/
public int getIntegerTimeSinceStart() {
return (int) Math.ceil(timeSinceStartInMilliSeconds/1000);
}
/** Notifies all {@link TimeIsUpListener}s. */
private void timeIsUp() {
size = timeIsUpListeners.size();
for (int i = 0; i < size; i++) {
if (timeIsUpListeners.get(i).timeIsUp()) {
removeTimeIsUpListener(timeIsUpListeners.get(i));
size--;
i--;
}
}
}
/** Notifies all {@link IntegerTimeListener} */
private void integerTimeChanged() {
size = integerTimeListeners.size();
int integerTime = getIntegerTime();
int integerTimeSinceStart = getIntegerTimeSinceStart();
for (int i = 0; i < size; i++) {
if (integerTimeListeners.get(i).integerTimeChanged(integerTime, integerTimeSinceStart)) {
removeIntegerTimeListener(integerTimeListeners.get(i));
size--;
i--;
}
}
}
/** Register a new {@link IntegerTimeListener} */
public void registerIntegerTimeListener(IntegerTimeListener newListener) {
integerTimeListeners.add(newListener);
}
/** Register a new {@link TimeIsUpListener} */
public void registerTimeIsUpListener(TimeIsUpListener newListener) {
timeIsUpListeners.add(newListener);
}
/** Removes the registered {@link IntegerTimeListener} */
public void removeIntegerTimeListener(IntegerTimeListener newListener) {
integerTimeListeners.remove(newListener);
}
/** Removes the registered {@link TimeIsUpListener} */
public void removeTimeIsUpListener(TimeIsUpListener newListener) {
timeIsUpListeners.remove(newListener);
}
public void gameStateChanged(GameState newGameState) {
switch (newGameState) {
case RUNNING:
resume();
break;
default:
pause();
break;
}
}
}