package org.yamcs.yarch;
import java.util.ArrayList;
import java.util.List;
import org.yamcs.yarch.streamsql.WindowSpecification;
public abstract class WindowProcessor {
List<CompiledAggregateExpression> aggList;
List<Tuple> windowTuples=new ArrayList<>();
boolean noOverlap; //if there is no overlap between the windows, some optimizations are possible
TupleDefinition aggOutputDef;
final private List<Tuple> emptyReturn=new ArrayList<>(0);
public TupleDefinition aggInputDef;
public static WindowProcessor getInstance(WindowSpecification spec, TupleDefinition aggInputDef, List<CompiledAggregateExpression> aggList, TupleDefinition aggregateOutputDef) {
WindowProcessor wp;
switch(spec.type) {
case FIELD:
DataType ft=spec.getFieldType();
if(ft==DataType.TIMESTAMP)
wp=new LongFieldBasedWP(spec);
else if (ft==DataType.INT)
wp=new IntFieldBasedWP(spec);
else
throw new IllegalArgumentException("datatype "+ft+" not supported for field based windows");
break;
case TIME:
case TUPLES:
default:
throw new IllegalArgumentException(spec.type+"not implemented");
}
wp.aggList=aggList;
wp.aggOutputDef=aggregateOutputDef;
wp.aggInputDef=aggInputDef;
wp.noOverlap=(spec.size.compareTo(spec.advance)<=0);
return wp;
}
/**
* When windows closes, returns a list with the tuples to be emitted, otherwise returns null
*/
public List<Tuple> newData(Tuple tuple) {
List<Tuple> ret=emptyReturn;
if(windowTuples.isEmpty()) {
setFirstTuple(tuple);
} else if(isOutsideWindow(tuple)) {
//windows closed
if(aggList!=null) {
Object[] v=new Object[aggList.size()];
for(int i=0;i<aggList.size();i++) {
v[i]=aggList.get(i).getValue();
}
ret=new ArrayList<Tuple>(1);
ret.add(new Tuple(aggOutputDef,v));
} else {//TODO
throw new IllegalStateException("not implemented");
}
if(noOverlap) {
if(aggList!=null) {
for(CompiledAggregateExpression cae:aggList) {
cae.clear();
}
} else {
ret=windowTuples;
}
windowTuples=new ArrayList<Tuple>();
setFirstTuple(tuple);
} else {//TODO
throw new IllegalStateException("not implemented");
}
}
windowTuples.add(tuple);
if(aggList!=null) {
for(CompiledAggregateExpression cae:aggList) {
cae.newData(tuple);
}
}
return ret;
}
abstract protected void setFirstTuple(Tuple tuple);
abstract protected boolean isOutsideWindow(Tuple tuple);
}
class LongFieldBasedWP extends WindowProcessor {
final long size,advance;
long firstValue;
final String field;
public LongFieldBasedWP(WindowSpecification spec) {
this.size=spec.size.longValue();
this.advance=spec.advance.longValue();
this.field=spec.field;
}
@Override
protected boolean isOutsideWindow(Tuple tuple) {
long nv=(Long)tuple.getColumn(field);
return nv>=firstValue+size;
}
@Override
protected void setFirstTuple(Tuple tuple) {
firstValue=(Long)tuple.getColumn(field);
}
}
class IntFieldBasedWP extends WindowProcessor {
final int size, advance;
int firstValue;
final String field;
public IntFieldBasedWP(WindowSpecification spec) {
this.size=spec.size.intValue();
this.advance=spec.advance.intValue();
this.field=spec.field;
}
@Override
protected boolean isOutsideWindow(Tuple tuple) {
int nv=(Integer)tuple.getColumn(field);
return nv>=(firstValue+size);
}
@Override
protected void setFirstTuple(Tuple tuple) {
firstValue=(Integer)tuple.getColumn(field);
}
}