/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package jlibs.xml.sax.dog.expr.nodset; import jlibs.core.util.LongTreeMap; import jlibs.xml.sax.dog.expr.Evaluation; import jlibs.xml.sax.dog.expr.EvaluationListener; import jlibs.xml.sax.dog.expr.Expression; import jlibs.xml.sax.dog.path.PositionalPredicate; import jlibs.xml.sax.dog.sniff.Event; /** * @author Santhosh Kumar T */ public final class PositionMatches extends EvaluationListener{ final Expression predicate; final int positionListenerCount; final LongTreeMap<PositionalListeners> map = new LongTreeMap<PositionalListeners>(); PositionMatches next; PositionalEvaluation lastListenerHead, lastListenerTail; PositionMatches(PositionalPredicate positionalPredicate){ predicate = positionalPredicate.predicate; positionListenerCount = positionalPredicate.position; } PositionalListeners listeners; public void addEvaluation(Event event){ Object result = event.evaluate(predicate); if(result!=null) listeners = new PositionalListeners(event.order(), (Boolean)result, positionListenerCount); else{ listeners = new PositionalListeners(event.evaluation, positionListenerCount); event.evaluation.addListener(this); } map.put(event.order(), listeners); } public void startEvaluation(){ if(listeners.evaluation!=null) listeners.evaluation.start(); else finished(listeners.order, listeners.result); } private int position = 0; private boolean expired; public void expired(){ expired = true; if(lastListenerHead!=null) checkLast(); } private void checkLast(){ if(expired && map.isEmpty()){ Double last = (double)position; for(PositionalEvaluation eval=lastListenerHead; eval!=null; eval=eval.next) eval.setResult(last); lastListenerHead = lastListenerTail = null; } } @Override public void finished(Evaluation evaluation){ finished(evaluation.order, (Boolean)evaluation.getResult()); } private void finished(long order, boolean accept){ if(accept) map.get(order).result = Boolean.TRUE; else map.remove(order).setPosition(Double.NaN); while(!map.isEmpty()){ LongTreeMap.Entry<PositionalListeners> entry = map.firstEntry(); if(entry.value.result==Boolean.TRUE){ position++; map.deleteEntry(entry); entry.value.setPosition((double)position); }else return; } if(lastListenerHead!=null) checkLast(); } public void dispose(){ for(LongTreeMap.Entry<PositionalListeners> entry=map.firstEntry(); entry!=null; entry=entry.next()) entry.value.evaluation.removeListener(this); map.clear(); } } final class PositionalListeners{ Evaluation evaluation; public long order; public Boolean result; private final PositionalEvaluation posListeners[]; private int listenerCount; PositionalListeners(Evaluation evaluation, int listenerCount){ posListeners = new PositionalEvaluation[listenerCount]; order = evaluation.order; this.evaluation = evaluation; } PositionalListeners(long order, Boolean result, int listenerCount){ posListeners = new PositionalEvaluation[listenerCount]; this.order = order; this.result = result; } public void addListener(PositionalEvaluation listener){ posListeners[listenerCount++] = listener; } public void removeListener(PositionalEvaluation listener){ for(int i=0, len=listenerCount; i<len; i++){ if(posListeners[i]==listener){ posListeners[i] = null; return; } } } public void setPosition(Double position){ for(int i=0; i<listenerCount; i++){ PositionalEvaluation peval = posListeners[i]; if(peval!=null && !peval.disposed) peval.setResult(position); } } }