/*
* Copyright or © or Copr. Amaury Carrade (2014 - 2016)
*
* http://amaury.carrade.eu
*
* This software is governed by the CeCILL-B license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-B
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-B license and that you accept its terms.
*/
package eu.carrade.amaury.UHCReloaded.timers;
import eu.carrade.amaury.UHCReloaded.events.TimerEndsEvent;
import eu.carrade.amaury.UHCReloaded.events.TimerStartsEvent;
import fr.zcraft.zlib.components.i18n.I;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.UUID;
/**
* Represents a timer.
*
* @author Amaury Carrade
*/
public class UHTimer
{
private static final NumberFormat formatter = new DecimalFormat("00");
private UUID id = null;
private String name = null;
private Boolean registered = false;
private Boolean running = false;
private Boolean displayed = false;
private Long startTime = 0l;
private Integer duration = 0; // seconds
// Cached values
private Integer hoursLeft = 0;
private Integer minutesLeft = 0;
private Integer secondsLeft = 0;
// Old values, used by the scoreboard to reset the scores.
private Integer oldHoursLeft = -1;
private Integer oldMinutesLeft = -1;
private Integer oldSecondsLeft = -1;
// Pause
private Boolean paused = false;
private Long pauseTime = 0l;
// Display this timer following the format "hh:mm:ss"?
private Boolean displayHoursInTimer = false;
public UHTimer(String name)
{
Validate.notNull(name, "The name cannot be null");
this.id = UUID.randomUUID(); // only used as a hashCode.
this.name = name;
}
/**
* Sets the duration of the timer, in seconds.
*
* @param seconds The duration.
*/
public void setDuration(int seconds)
{
this.duration = seconds;
this.hoursLeft = (int) Math.floor(this.duration / 3600);
this.minutesLeft = (int) (Math.floor(this.duration / 60) - (this.hoursLeft * 60));
this.secondsLeft = this.duration - (this.minutesLeft * 60 + this.hoursLeft * 3600);
this.displayHoursInTimer = (this.hoursLeft != 0);
}
/**
* Starts this timer.
*
* If this is called while the timer is running, the timer is restarted.
*/
public void start()
{
this.running = true;
this.startTime = System.currentTimeMillis();
Bukkit.getServer().getPluginManager().callEvent(new TimerStartsEvent(this));
}
/**
* Stops this timer.
*/
public void stop()
{
stop(false);
}
/**
* Stops this timer.
*
* @param wasUp If true, the timer was stopped because the timer was up.
*/
private void stop(boolean wasUp)
{
TimerEndsEvent event = new TimerEndsEvent(this, wasUp);
Bukkit.getServer().getPluginManager().callEvent(event);
if (isRegistered())
{
if (event.getRestart())
{
start();
}
else
{
this.running = false;
this.startTime = 0l;
this.hoursLeft = 0;
this.minutesLeft = 0;
this.secondsLeft = 0;
this.oldHoursLeft = 0;
this.oldMinutesLeft = 0;
this.oldSecondsLeft = 0;
}
}
}
/**
* Updates the timer.
*/
public void update()
{
if (running && !paused)
{
oldHoursLeft = hoursLeft;
oldMinutesLeft = minutesLeft;
oldSecondsLeft = secondsLeft;
long timeSinceStart = System.currentTimeMillis() - this.startTime; // ms
if (timeSinceStart >= getDuration() * 1000)
{
stop(true);
}
else
{
Integer countSecondsLeft = (int) (getDuration() - Math.floor(timeSinceStart / 1000));
secondsLeft = countSecondsLeft % 60;
minutesLeft = (countSecondsLeft % 3600) / 60;
hoursLeft = (int) Math.floor(countSecondsLeft / 3600);
}
}
}
/**
* Pauses (or restarts after a pause) the timer.
* <p>
* If the timer is not running, nothing is done.
*
* @param pause If true the timer will be paused.
*/
public void setPaused(boolean pause)
{
if (this.running)
{
// The pause is only set once (as example if the user executes /uh freeze all twice).
if (pause && !this.paused)
{
this.paused = true;
this.pauseTime = System.currentTimeMillis();
}
if (!pause && this.paused)
{
// We have to add to the time of the start of the episode the elapsed time
// during the pause.
this.startTime += (System.currentTimeMillis() - this.pauseTime);
this.pauseTime = 0l;
this.paused = false;
}
}
}
/**
* Checks if the timer is registered in the TimerManager.
*
* @return true if the timer is registered.
*/
public Boolean isRegistered()
{
return registered;
}
/**
* Marks a timer as registered, or not.
*
* @param registered true if the timer is now registered.
*/
protected void setRegistered(Boolean registered)
{
this.registered = registered;
}
/**
* Returns the name of the timer.
*
* @return The name.
*/
public String getName()
{
return name;
}
/**
* Returns the display name of the timer.
* <p>
* The display name is the name with all &-based color codes replaced by §-based ones.
*
* @return The name.
*/
public String getDisplayName()
{
return ChatColor.translateAlternateColorCodes('&', name);
}
/**
* Checks if the timer is currently running.
*
* @return true if the timer is running.
*/
public Boolean isRunning()
{
return running;
}
/**
* Checks if the timer is currently displayed in the scoreboard.
*
* @return {@code true} if displayed.
*/
public Boolean isDisplayed()
{
return displayed;
}
/**
* Display or hide this timer in/from the scoreboard.
*
* @param displayed {@code true} to display, and {@code false} to hide.
*/
public void setDisplayed(Boolean displayed)
{
this.displayed = displayed;
}
/**
* Returns the duration of the timer, in seconds.
*
* @return The duration.
*/
public Integer getDuration()
{
return duration;
}
/**
* Returns the number of hours left until the end of this countdown.
*
* @return The number of hours left.
*/
public Integer getHoursLeft()
{
return hoursLeft;
}
/**
* Returns the number of minutes left until the end of this countdown.
*
* @return The number of minutes left.
*/
public Integer getMinutesLeft()
{
return minutesLeft;
}
/**
* Returns the number of seconds left until the end of this countdown.
*
* @return The number of seconds left.
*/
public Integer getSecondsLeft()
{
return secondsLeft;
}
/**
* Returns the number of hours left until the end of this countdown, before the last update.
* <p>
* Used by the scoreboard, to remove the old score.
*
* @return The old number of hours left, or -1 if the timer was never updated.
*/
public Integer getOldHoursLeft()
{
return oldHoursLeft;
}
/**
* Returns the number of minutes left until the end of this countdown, before the last update.
* <p>
* Used by the scoreboard, to remove the old score.
*
* @return The old number of minutes left, or -1 if the timer was never updated.
*/
public Integer getOldMinutesLeft()
{
return oldMinutesLeft;
}
/**
* Returns the number of seconds left until the end of this countdown, before the last update.
* <p>
* Used by the scoreboard, to remove the old score.
*
* @return The old number of seconds left, or -1 if the timer was never updated.
*/
public Integer getOldSecondsLeft()
{
return oldSecondsLeft;
}
/**
* Checks if this timer is paused.
*
* @return true if the timer is paused.
*/
public Boolean isPaused()
{
return paused;
}
/**
* Returns true if this timer is displayed as "hh:mm:ss" in the scoreboard.
*
* @return true if this timer is displayed as "hh:mm:ss" in the scoreboard.
*/
public Boolean getDisplayHoursInTimer()
{
return displayHoursInTimer;
}
@Override
public boolean equals(Object other)
{
return other instanceof UHTimer && ((UHTimer) other).getName().equals(this.getName());
}
@Override
public String toString()
{
return toString(displayHoursInTimer);
}
public String toString(boolean displayHours)
{
if (displayHours)
{
/// Timer. {0} = hours; {1} = minutes; {2} = seconds.
return I.t("{0}{gray}:{white}{1}{gray}:{white}{2}", formatter.format(hoursLeft), formatter.format(minutesLeft), formatter.format(secondsLeft));
}
else
{
/// Timer. {0} = minutes; {1} = seconds.
return I.t("{white}{0}{gray}:{white}{1}", formatter.format(minutesLeft), formatter.format(secondsLeft));
}
}
@Override
public int hashCode()
{
return id.hashCode();
}
}