/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses 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 org.apache.jena.sparql.expr.aggregate;

import org.apache.jena.sparql.engine.binding.Binding ;
import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.sparql.expr.ExprLib ;
import org.apache.jena.sparql.expr.NodeValue ;
import org.apache.jena.sparql.function.FunctionEnv ;

/** Accumulator that passes down every value of an expression */
abstract class AccumulatorExpr implements Accumulator
{
    private long count = 0 ;
    protected long errorCount = 0 ; 
    private final Expr expr ;
    
    protected AccumulatorExpr(Expr expr)
    {
        this.expr = expr ;
    }
    
    @Override
    final public void accumulate(Binding binding, FunctionEnv functionEnv)
    {
        NodeValue nv = ExprLib.evalOrNull(expr, binding, functionEnv) ;
        if ( nv != null ) {
            accumulate(nv, binding, functionEnv) ;
            count++ ;
        } else {
            accumulateError(binding, functionEnv) ;
            errorCount++ ;
        }
    }
    
    // COUNT(?v) is different : errors of the expression/variable do not cause an aggregate eval error. 
    // SAMPLE is different : it treats errors as "just another value" and tries to return a defined value if any have been seen. 
    
    @Override
    public NodeValue getValue()
    {
        if ( errorCount == 0 )
            return getAccValue() ;  
        return null ;
    }

    protected long getErrorCount() { return errorCount ; }
    
    /** Called if no errors to get the accumulated result */
    protected abstract NodeValue getAccValue() ; 

    /** Called when the expression beeing aggregated evaluates OK.
     * Can throw ExprEvalException - in which case the accumulateError is called */
    protected abstract void accumulate(NodeValue nv, Binding binding, FunctionEnv functionEnv) ;
    /** Called when an evaluation of the expression causes an error
     * or when the accumulation step throws ExprEvalException  
     */
    protected abstract void accumulateError(Binding binding, FunctionEnv functionEnv) ;
}

@@ -945,16 +945,71 @@
 .Expr ;%0A
+import org.apache.jena.sparql.expr.ExprEvalException ;%0A
 import o
@@ -1648,16 +1648,38 @@
 ull ) %7B%0A
+            try %7B%0A    
         
@@ -1733,16 +1733,20 @@
         
+    
 count++ 
@@ -1759,21 +1759,116 @@
     
-%7D else
+        return ;%0A            %7D catch (ExprEvalException ex)
  %7B
+%7D
 %0A    
+        // Drop to error case.%0A        %7D%0A
     
@@ -1919,20 +1919,16 @@
         
-    
 errorCou
@@ -1934,26 +1934,16 @@
 unt++ ;%0A
-        %7D%0A
     %7D%0A  

Handle error from accumulate().