/*
 *  Copyright (C) 2011-2012 The Animo Project
 *  http://animotron.org
 *  	
 *  This file is part of Animotron.
 *  
 *  Animotron is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as 
 *  published by the Free Software Foundation, either version 3 of 
 *  the License, or (at your option) any later version.
 *  
 *  Animotron is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *  
 *  You should have received a copy of 
 *  the GNU Affero General Public License along with Animotron.  
 *  If not, see <http://www.gnu.org/licenses/>.
 */
package org.animotron.statement.query;

import org.animotron.graph.index.Order;
import org.animotron.io.Pipe;
import org.animotron.manipulator.OnQuestion;
import org.animotron.manipulator.PFlow;
import org.animotron.manipulator.QCAVector;
import org.animotron.statement.operator.AN;
import org.animotron.statement.operator.Reference;
import org.animotron.statement.operator.Utils;
import org.animotron.statement.value.VALUE;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.IndexHits;

import javolution.util.FastSet;

/**
 * Query operator 'ALL'.
 * 
 * Return perfect 'all' USE.
 * 
 * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
 * @author <a href="mailto:gazdovsky@gmail.com">Evgeny Gazdovsky</a>
 */
public class ALL extends AbstractQuery implements Reference {
	
	public static final ALL _ = new ALL();
	
	private ALL() { super("all", "~~"); }

    public OnQuestion onCalcQuestion() {
        return new Calc();
    }
    
    class Calc extends OnQuestion {
        @Override
        public void act(final PFlow pf) {
			//System.out.println("ALL **************************");
            
        	Pipe pipe = Utils.getByREF(pf, pf.getVector());
        	QCAVector theVector;
        	
            while ((theVector = pipe.take()) != null) {
            	
            	Relationship the = theVector.getAnswer();

    			//check, maybe, result was already calculated
    			if (!Utils.results(the, pf)) {
    				
    				Node node = the.getEndNode();

    				FastSet<Node> uses = FastSet.newInstance();
    				FastSet<Node> weaks = FastSet.newInstance();
    				FastSet<Path> directed = FastSet.newInstance();

					try {
	    				getUSEs(pf, node, uses, weaks, directed);
						
						//System.out.println(uses);
						
						boolean underUSE = false;
						Node n = getClosestIntersection(directed);
	    				if (n != null) {
	    					node = n;
	    					underUSE = true;
	    				}
						
		        		Relationship res;
						if (underUSE 
								&& isLeaf(node) 
								&& (res = getThe(node)) != null  
								&& filtering(pf, res, uses, weaks))
							
			            	try {
			            		pf.sendAnswer( res );
			            	} catch (Exception e) {}
						
				        for (Path path : td_IS_leaf.traverse(node)) {
				        	
				        	//System.out.println(path);
	
				        	Relationship r = path.lastRelationship();
				        	if (!Utils.haveContext(r.getEndNode())) {
				        		
				        		//XXX: need better check, it can be reference from other then AN
				        		if (!isLeaf(r.getStartNode()))
				        			continue;
	
			        			try {
					        		res = getThe(r.getStartNode());
				        			if (filtering(pf, res, uses, weaks)) {
				        				pf.sendAnswer( res );
				        			}
			        			} catch (Exception e) {
			        				for (Path p : Utils.td_THE.traverse(r.getStartNode())) {
			        					res = p.lastRelationship();
					        			if (filtering(pf, res, uses, weaks)) {
					        				pf.sendAnswer( res );
					        			}
			        				}
								}
				        	} else {
				    			IndexHits<Relationship> hits = Order.context(r.getEndNode());
				    			try {
				    				for (Relationship rr : hits) {
				    					
				    					if (rr.isType(AN._) || rr.isType(VALUE._)) {
				    						if (filtering(pf, rr, r.getEndNode(), uses, weaks)) {
						        				pf.sendAnswer( rr );
				    						}
				    					}
				    				}
				    			} finally {
				    				hits.close();
				    			}
				        	}
				        }
					} finally {
						FastSet.recycle(uses);
						FastSet.recycle(weaks);
						FastSet.recycle(directed);
					}
    			}
            }
        }
    }
}
@@ -838,16 +838,64 @@
 query;%0A%0A
+import java.util.Arrays;%0Aimport java.util.Set;%0A%0A
 import o
@@ -2689,16 +2689,419 @@
 %09%0A%09%09%09%09%09%09
+Set%3CRelationship%3E list = getExpected(pf);%0A%09%09%09%09%09%09if (list !=null && !list.isEmpty()) %7B%0A%09%09%09%09%09%09%09System.out.println(%22after predicate %22+Arrays.toString(list.toArray()));%0A%09%09%09%09%09%09%09for (Relationship r : list) %7B%0A%09%09%09%09%09%09%09%09if (setFiltering(r.getEndNode(), uses, weaks))%0A%09%09%09%09%09%09%09%09%09//System.out.print(%22answered %22);%0A%09%09%09%09%09%09%09%09%09//Utils.debug(r);%0A%09%09%09        %09%09%09%09pf.sendAnswer( r );%0A%09%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09%09return;%0A%09%09%09%09%09%09%7D%0A%0A%09    %09%09%09%09
 boolean 

optimize ALL a bit