package net.sourceforge.pain.data;
import net.sourceforge.pain.db.*;
import net.sourceforge.pain.*;
import net.sourceforge.pain.logic.*;
/*
Affect with information of its start and end time
time tracking routines are provided by codebase
*/
public class TimedAffectData extends AffectData {
private static int AFFECT_START_TIME = LAST_BASE_FIELD_INDEX + 1;
private static int AFFECT_END_TIME = LAST_BASE_FIELD_INDEX + 2;
private static int GREATER_END_TIME = LAST_BASE_FIELD_INDEX + 3;
private static int LOWER_END_TIME = LAST_BASE_FIELD_INDEX + 4;
private static int STARTED = LAST_BASE_FIELD_INDEX + 5;
protected static int TA_LAST_BASE_FIELD_INDEX = STARTED;
/**
* Class that will handle affect start and stop events
*/
private static int NFIELDS = TA_LAST_BASE_FIELD_INDEX + 1;
/**
* used on startup by db
*/
public TimedAffectData() {
}
public TimedAffectData(final PainDB db, Role role, Class affectImplClass, int affectTypeId, int duration) throws Exception {
super(db, role, affectImplClass, affectTypeId);
if (!TimedAffect.class.isAssignableFrom(affectImplClass)) {
throw new IllegalArgumentException("Illegal affect impl class!");
}
final int time = Core.getTime().getTime();
setInt(AFFECT_START_TIME, time);
if (duration < 0) {
setInt(AFFECT_END_TIME, -1);
} else {
setInt(AFFECT_END_TIME, time + duration);
}
addToOffQueue();
}
protected DbClassSchema provideSchema() {
byte types[] = new byte[NFIELDS];
String names[] = new String[NFIELDS];
fillSuperSchema(types, names);
return new DbClassSchema(types, names);
}
protected void fillSuperSchema(byte[] types, String[] names) {
super.fillSuperSchema(types, names);
types[AFFECT_START_TIME] = DbType.INT;
names[AFFECT_START_TIME] = "start_time";
types[AFFECT_END_TIME] = DbType.INT;
names[AFFECT_END_TIME] = "end_time";
types[GREATER_END_TIME] = DbType.REFERENCE;
names[GREATER_END_TIME] = "greater_end_affect";
types[LOWER_END_TIME] = DbType.REFERENCE;
names[LOWER_END_TIME] = "lower_end_affect";
types[STARTED] = DbType.BOOLEAN;
names[STARTED] = "started";
}
private void addToOffQueue() {
int off = getAffectOffTime();
//handling off time (-1 == never off -> do not add such affect to timer queue)
if (off == -1) {
return;
}
TimedAffectsQueue tq = getAffectsQueue();
TimedAffectData aff = tq.getLastOff();
while (aff != null && aff.getAffectOffTime() > off) {
aff = aff.getPrevOff();
}
if (aff != null) {
TimedAffectData nextOff = aff.getNextOff();
_setNextOff(nextOff);
_setPrevOff(aff);
if (nextOff != null) {
nextOff._setPrevOff(this);
} else { // lastOff
tq.setLastOff(this);
}
aff._setNextOff(this);
} else { // firstOff
final TimedAffectData firstOff = tq.getFirstOff();
_setNextOff(firstOff);
_setPrevOff(null);
tq.setFirstOff(this);
if (firstOff == null) {
tq.setLastOff(this);
} else {
firstOff._setPrevOff(this);
}
}
}
private TimedAffectsQueue getAffectsQueue() {
return Core.getWorld().getAffectsQueue();
}
private void _setPrevOff(TimedAffectData prevOff) {
setReference(LOWER_END_TIME, prevOff);
}
private void _setNextOff(TimedAffectData nextOff) {
setReference(GREATER_END_TIME, nextOff);
}
public final int getAffectOnTime() {
return getInt(AFFECT_START_TIME);
}
public final int getAffectOffTime() {
return getInt(AFFECT_END_TIME);
}
public final TimedAffectData getNextOff() {
return (TimedAffectData) getReference(GREATER_END_TIME);
}
public final TimedAffectData getPrevOff() {
return (TimedAffectData) getReference(LOWER_END_TIME);
}
public final void setAffectOffTime(int offTime) {
int oldOff = getAffectOffTime();
if (oldOff == offTime) {
return;
}
if (oldOff != -1) {
removeFromOffQueue();
}
setInt(AFFECT_END_TIME, offTime >= 0 ? offTime : -1);
if (offTime >= 0) {
addToOffQueue();
}
}
private void removeFromOffQueue() {
TimedAffectData nextOff = getNextOff();
TimedAffectData prevOff = getPrevOff();
TimedAffectsQueue tq = Core.getWorld().getAffectsQueue();
if (nextOff == null) {
tq.setLastOff(prevOff);
} else {
nextOff._setPrevOff(prevOff);
}
if (prevOff == null) {
tq.setFirstOff(nextOff);
} else {
prevOff._setNextOff(nextOff);
}
}
public void delete() {
if (getAffectOffTime() != -1) {
removeFromOffQueue();
}
super.delete();
}
}