package edu.brown.benchmark.tpce.generators;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import edu.brown.benchmark.tpce.util.EGenDate;
import java.lang.reflect.*;
public class TimerWheel {
private GregorianCalendar baseTime;
private WheelTime lastTime;
private WheelTime currentTime;
private WheelTime nextTime;
private TWheelConfig wheelConfig;
private ArrayList<LinkedList< TimerWheelTimer>> timerWheel;
private int numberOfTimers;
private int period;
private int resolution;
private Object expiryData;
private Object expiryObject;
private Method expiryFunction;
public static final int NO_OUTSTANDING_TIMERS = -1;
public TimerWheel(Object expiryData, Object expiryObject, Method expiryFunction, int period, int resolution){
wheelConfig = new TWheelConfig(( period * ( EGenDate.MsPerSecond / resolution )), resolution );
this.period = period;
this.resolution = resolution;
baseTime = new GregorianCalendar();
lastTime = new WheelTime( wheelConfig, 0, 0 );
currentTime = new WheelTime( wheelConfig, 0, 0 );
nextTime = new WheelTime( wheelConfig, TWheelConfig.MaxWheelCycles, ( period * ( EGenDate.MsPerSecond / resolution )) - 1 );
numberOfTimers = 0;
timerWheel = new ArrayList<LinkedList< TimerWheelTimer>>(period * ( EGenDate.MsPerSecond / resolution )) ;
this.expiryData = expiryData;
this.expiryObject = expiryObject;
this.expiryFunction = expiryFunction;
}
public boolean empty(){
return( numberOfTimers == 0 ? true : false );
}
public int startTimer( double Offset){
GregorianCalendar Now = new GregorianCalendar();
WheelTime RequestedTime = new WheelTime( wheelConfig , baseTime, Now, (int) (Offset * ( EGenDate.MsPerSecond / resolution )));
TimerWheelTimer pNewTimer = new TimerWheelTimer( expiryObject, expiryFunction, expiryData );
currentTime.set( baseTime, Now );
expiryProcessing();
timerWheel.get(RequestedTime.getIndex()).add( pNewTimer );
numberOfTimers++;
if( RequestedTime.getCycles() == nextTime.getCycles() ? (RequestedTime.getIndex() < nextTime.getIndex()) : ( RequestedTime.getCycles() < nextTime.getCycles() )){
nextTime = RequestedTime;
}
return( nextTime.offset( currentTime ));
}
public int processExpiredTimers(){
GregorianCalendar Now = new GregorianCalendar();
currentTime.set( baseTime, Now );
return( expiryProcessing() );
}
private int expiryProcessing(){
while( lastTime.getCycles() < currentTime.getCycles() ? ( lastTime.getIndex() < currentTime.getIndex() ) : ( lastTime.getCycles() < currentTime.getCycles() )){
lastTime.add(1);
if( ! timerWheel.get( lastTime.getIndex()).isEmpty() ){
processTimerList( timerWheel.get( lastTime.getIndex()) );
}
}
return( setNextTime() );
}
private void processTimerList( LinkedList<TimerWheelTimer> pList ){
ListIterator<TimerWheelTimer> ExpiredTimer = pList.listIterator();
while (ExpiredTimer.hasNext()){
try{
ExpiredTimer.next().getExpiryFunction().invoke(expiryObject, expiryData);
ExpiredTimer.remove();
numberOfTimers--;
}catch(Exception e){
e.printStackTrace();
}
}
pList.clear();
}
private int setNextTime(){
if( 0 == numberOfTimers ){
nextTime.set( TWheelConfig.MaxWheelCycles, ( period * ( EGenDate.MsPerSecond / resolution )) - 1 );
return( NO_OUTSTANDING_TIMERS );
}
else{
nextTime = currentTime;
while( timerWheel.get(nextTime.getIndex()).isEmpty() ){
nextTime.add(1);
}
return( nextTime.offset( currentTime ));
}
}
}