/*
 *  @author Ranides Atterwim <ranides@gmail.com>
 *  @copyright Ranides Atterwim
 *  @license WTFPL
 *  @url http://ranides.net/projects/assira
 */

package net.ranides.assira.events;

import net.ranides.assira.annotations.Meta;

/**
 * Implementacja zwracana przez {@link EventLock#unsafeLock}
 * @author ranides
 */
@Meta.Unsafe
public class EventLockUnsafe extends EventLock implements EventListener<Event> {
    
    private final Class<? extends Event> observed;
    private final EventRouter router;
    private volatile Event hit;
    
    EventLockUnsafe(Class<? extends Event> event, EventRouter router) {
            super();
            this.observed = event;
            this.router = router;
        }

    @Override
    public void handleEvent(Event event) {
        synchronized (this) {
            hit = event;
            this.notifyAll();
        }
    }
    
    @Override
    public Event waitForEvent() throws InterruptedException {
        synchronized (this) {
            while (hit==null) { this.wait(); }
            Event result = hit;
            hit = null;
            return result;
        }
    }

    @Override
    public Event waitForEvent(long timeout) throws InterruptedException {
        long end = System.currentTimeMillis() + timeout;
        long rem = timeout;
        synchronized (this) {
            while (hit==null && rem>0) {
                this.wait(rem);
                rem = end - System.currentTimeMillis();
            }
            Event result = hit;
            hit = null;
            return result;
        }
    }

    @Override
    public <T extends Event> T waitForEvent(Class<T> event) throws InterruptedException {
        synchronized (this) {
            while( !event.isInstance(hit) ) { this.wait(); }
            Event ret = hit;
            hit = null;
            return event.cast(ret);
        }
    }
    
    @Override
    public <T extends Event> T waitForEvent(Class<T> event, long timeout) throws InterruptedException {
        long end = System.currentTimeMillis() + timeout;
        long rem = timeout;
        synchronized (this) {
            while( !event.isInstance(hit) && rem>0) {
                this.wait(rem);
                rem = end - System.currentTimeMillis();
            }
            Event ret = hit;
            hit = null;
            return event.cast(ret);
        }
    }
    
    @Override
    public void reset() {
        hit = null;
    }

    @Override
    public void release() {
        router.removeEventListener(observed, this);
    }
    
    @Override
    public EventListener<Event> listener() {
        return this;
    }
    
}
