/
codebase/src/net/sourceforge/pain/admin/console/command/
codebase/src/net/sourceforge/pain/data/role/
codebase/src/net/sourceforge/pain/network/console/telnet/
codebase/src/net/sourceforge/pain/network/guitool/
codebase/src/net/sourceforge/pain/plugin/
codebase/src/net/sourceforge/pain/util/
db/src/net/sourceforge/pain/util/
gui/
gui/lib/
gui/src/net/sourceforge/pain/tools/guitool/dbbrowse/
gui/src/net/sourceforge/pain/tools/guitool/dialog/
gui/src/net/sourceforge/pain/tools/guitool/menu/
gui/src/net/sourceforge/pain/tools/guitool/resources/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/
gui/src/net/sourceforge/pain/tools/guitool/resources/images/explorer/
mudlibs/tinylib/
mudlibs/tinylib/area/
mudlibs/tinylib/etc/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/prototype/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/data/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/affect/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/deploy/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/event/guitool/event/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/fn/util/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/logic/trigger/impl/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/command/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/reset/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/shutdown/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/plugin/social/
mudlibs/tinylib/src/net/sourceforge/pain/tinylib/util/
tests/
tests/src/
tests/src/net/sourceforge/pain/db/data/
package net.sourceforge.pain.data;

import net.sourceforge.pain.*;
import net.sourceforge.pain.db.*;
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 = Codebase.getPulse().currentTime();
        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 Codebase.getCodebaseData().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 = Codebase.getCodebaseData().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();
    }

}