package speedytools.clientside.userinput; /** * Manages the state of a "Power up" object (eg for animation purposes) * - start of charging up, progress of charge, release of charge * Usage: * (1) initiate() to begin the powerup; supply the current time and the duration of the powerup * The first call to pollState() will return INITIATING, subsequent calls return POWERINGUP * (2) updateHolddownTime periodically, to inform as the charge builds up * (3) release() to stop the powerup * The first call to pollState() will return RELEASING, subsequent calls return IDLE * The state of the powerup can be read: * (1) The current state is available using peekState or pollState. * (2) The current time in a state from getTimeSpentInThisState * (3) the percentage completion (0 - 100) from getPercentComplete */ public class PowerUpEffect { public enum State { IDLE, INITIATING, POWERINGUP, RELEASING // INITIATING and RELEASING are transient, to inform the caller that the state has changed. } /** start the powerup * @param new_initiationTime the time (in ns) when the powerup started * @param new_completionTime the time (in ns) when the powerup will be complete * @param new_initialHoldDuration the length of time (in ns) that the button had been held down, when the powerup started */ public void initiate(long new_initiationTime, long new_completionTime, long new_initialHoldDuration) { initiationTime = new_initiationTime; expectedCompletionTime = new_completionTime; assert (expectedCompletionTime > initiationTime); assert (initialHoldDuration >= 0); initialHoldDuration = new_initialHoldDuration; currentHoldDuration = 0; state = State.INITIATING; } public void release(long new_releaseTime) { releaseTime = new_releaseTime; state = State.RELEASING; } public void abort() { releaseTime = initiationTime; state = State.RELEASING; } /** * update the duration of the hold * @param lengthOfHold total time in ns that the button has been held down */ public void updateHolddownTime(long lengthOfHold) { if (state != State.INITIATING && state != State.POWERINGUP) return; if (lengthOfHold < initialHoldDuration) { // the hold time is shorter than the start value, so presumably there was a fast click_up and then click_down again initialHoldDuration = lengthOfHold; // in this case - reset the initial hold duration to be now. } currentHoldDuration = lengthOfHold; } /** returns the current state without affecting it * @return */ public State peekState() {return state;} /** returns the current state and advances to the next state as appropriate * @return */ public State pollState() { State retval = state; if (state == State.INITIATING) state = State.POWERINGUP; if (state == State.RELEASING) state = State.IDLE; return retval; } public boolean isIdle(){return (state == State.IDLE || state == State.RELEASING);} /** returns the time spent in this state * @param timeNow the current time in ns * @return duration in ns, or 0 if not available. */ public long getTimeSpentInThisState(long timeNow) { switch (state) { case RELEASING: case IDLE: { if (releaseTime == 0) return 0; assert (timeNow > releaseTime); return (timeNow - releaseTime); } case INITIATING: case POWERINGUP: { assert (initiationTime != 0 && timeNow > initiationTime); return (timeNow - initiationTime); } default: assert false: "Invalid state:" + state; } return 0; } /** * returns the percentage of the powerup completed; either the current one (if currently powering up) or the most-recently-completed one. * @return */ public double getPercentCompleted() { switch (state) { case RELEASING: case IDLE: { if (releaseTime == 0) return 0; double fraction = (releaseTime - initiationTime); fraction /= (expectedCompletionTime - initiationTime); fraction *= 100.0; fraction = Math.min(100.0, fraction); assert (fraction >= 0.0 && fraction <= 100.0); return fraction; } case INITIATING: case POWERINGUP: { if (currentHoldDuration == 0) return 0; double fraction = currentHoldDuration - initialHoldDuration; fraction /= (expectedCompletionTime - initiationTime); fraction *= 100.0; fraction = Math.min(100.0, fraction); assert (fraction >= 0.0 && fraction <= 100.0); return fraction; } default: assert false: "Invalid state:" + state; } return 0.0; } private State state = State.IDLE; private long initiationTime = 0; private long initialHoldDuration = 0; // the duration the button had been held down when powerup started private long currentHoldDuration = 0; // the duration the button had currently been held down private long expectedCompletionTime = 0; private long releaseTime = 0; }