package iqq.im.event.future;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import iqq.im.QQActionListener;
import iqq.im.QQException;
import iqq.im.QQException.QQErrorCode;
import iqq.im.event.QQActionEvent;
import iqq.im.event.QQActionEvent.Type;
import iqq.im.event.QQActionFuture;
public abstract class AbstractActionFuture implements QQActionFuture, QQActionListener {
private QQActionListener proxyListener;
private BlockingQueue<QQActionEvent> eventQueue;
private volatile boolean isCanceled;
private volatile boolean hasEvent;
public AbstractActionFuture(QQActionListener proxyListener) {
this.hasEvent = true;
this.proxyListener = proxyListener;
this.eventQueue = new LinkedBlockingQueue<QQActionEvent>();
}
@Override
public QQActionEvent waitEvent() throws QQException {
if( !hasEvent ) {
return null;
}
try {
QQActionEvent event = eventQueue.take();
hasEvent = !isFinalEvent(event);
return event;
} catch (InterruptedException e) {
throw new QQException(QQErrorCode.WAIT_INTERUPPTED, e);
}
}
@Override
public QQActionEvent waitEvent(long timeoutMs) throws QQException {
QQActionEvent event = null;
if( !hasEvent ) {
return null;
}
try {
event = eventQueue.poll(timeoutMs, TimeUnit.MICROSECONDS);
} catch (InterruptedException e) {
throw new QQException(QQErrorCode.WAIT_INTERUPPTED, e);
}
if(event == null){
throw new QQException(QQErrorCode.WAIT_TIMEOUT);
}else{
hasEvent = !isFinalEvent(event);
return event;
}
}
@Override
public QQActionEvent waitFinalEvent() throws QQException {
QQActionEvent event = null;
while( (event = waitEvent()) != null){
if( isFinalEvent(event) ){
return event;
}
}
throw new QQException(QQErrorCode.UNKNOWN_ERROR);
}
@Override
public QQActionEvent waitFinalEvent(long timeoutMs) throws QQException {
QQActionEvent event = null;
long start = System.currentTimeMillis();
while( (event = waitEvent(timeoutMs)) != null){
long end = System.currentTimeMillis();
if( isFinalEvent(event) ){
return event;
}else{
timeoutMs -= end - start;
start = System.currentTimeMillis();
}
}
throw new QQException(QQErrorCode.UNKNOWN_ERROR);
}
private boolean isFinalEvent(QQActionEvent event){
QQActionEvent.Type type = event.getType();
return type==Type.EVT_CANCELED
|| type==Type.EVT_ERROR
|| type==Type.EVT_OK;
}
@Override
public void onActionEvent(QQActionEvent event) {
if (proxyListener != null){
proxyListener.onActionEvent(event);
}
eventQueue.add(event);
}
@Override
public boolean isCanceled() {
return isCanceled;
}
public void setCanceled(boolean isCanceled){
this.isCanceled = isCanceled;
}
public void notifyActionEvent(QQActionEvent.Type type, Object target){
onActionEvent(new QQActionEvent(type, target, this));
}
/**
* @return the proxyListener
*/
public QQActionListener getProxyListener() {
return proxyListener;
}
}