/*
 * 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;

import java.util.Collection ;
import java.util.HashSet ;
import java.util.Set ;

import org.apache.jena.query.SortCondition ;
import org.apache.jena.sparql.algebra.OpVars ;
import org.apache.jena.sparql.algebra.walker.Walker ;
import org.apache.jena.sparql.core.Var ;

public class ExprVars
{
    interface Action<T> { void var(Collection<T> acc, Var var) ; }

    public static Set<Var> getVarsMentioned(Expr expr)
    {
        Set<Var> acc = new HashSet<>() ;
        varsMentioned(acc, expr) ;
        return acc ;
    }

    public static Set<Var> getVarsMentioned(ExprList exprs)
    {
        Set<Var> acc = new HashSet<>() ;
        for ( Expr expr : exprs )
            varsMentioned(acc, expr) ;    
        return acc ;
    }

    public static void varsMentioned(Collection<Var> acc, Expr expr)
    {
        ExprVars.Action<Var> action =
            new ExprVars.Action<Var>(){
                @Override
                public void var(Collection<Var> acc, Var var)
                {
                    acc.add(var) ;
                }
            } ;
        ExprVarsWorker<Var> vv = new ExprVarsWorker<>(acc, action) ;
        Walker.walk(expr, vv) ;
    }
    
    public static void nonOpVarsMentioned(Collection<Var> acc, Expr expr)
    {
        ExprVars.Action<Var> action =
                new ExprVars.Action<Var>(){
                    @Override
                    public void var(Collection<Var> acc, Var var)
                    {
                        acc.add(var) ;
                    }
                } ;
        ExprNoOpVarsWorker<Var> vv = new ExprNoOpVarsWorker<>(acc, action) ;
        Walker.walk(expr, vv) ;
    }
    
    public static Set<String> getVarNamesMentioned(Expr expr)
    {
        Set<String> acc = new HashSet<>() ;
        varNamesMentioned(acc, expr) ;
        return acc ;
    }
    
    public static void varNamesMentioned(Collection<String> acc, Expr expr)
    {
        ExprVars.Action<String> action =
            new ExprVars.Action<String>(){
                @Override
                public void var(Collection<String> acc, Var var)
                {
                    acc.add(var.getVarName()) ;
                }
            } ;
        ExprVarsWorker<String> vv = new ExprVarsWorker<>(acc, action) ;
        Walker.walk(expr, vv) ;
    }
    
    
    public static Set<Var> getVarsMentioned(SortCondition sortCondition) {
        Set<Var> acc = new HashSet<>() ;
        varsMentioned(acc, sortCondition) ;
        return acc ;
    }
    
    public static Set<Var> getVarsMentioned(Collection<SortCondition> sortConditions) {
        Set<Var> acc = new HashSet<>() ;
        varsMentioned(acc, sortConditions) ;
        return acc ;
    }

    public static  void varsMentioned(Collection<Var> acc, SortCondition sortCondition) {
        sortCondition.getExpression().varsMentioned(acc) ;
    }

    public static void varsMentioned(Collection<Var> acc, Collection<SortCondition> sortConditions) {
        for (SortCondition sc : sortConditions )
            varsMentioned(acc, sc) ;
    }

    static class ExprVarsWorker<T> extends ExprVisitorBase
    {
        final Collection<T> acc ;
        final Action<T> action ;
        
        public ExprVarsWorker(Collection<T> acc, Action<T> action)
        { this.acc = acc ; this.action = action ; }
        
        @Override
        public void visit(ExprVar nv)
        { action.var(acc, nv.asVar()) ; }
        
        @Override
        public void visit(ExprFunctionOp funcOp)
        { 
            Collection<Var> vars = OpVars.visibleVars(funcOp.getGraphPattern()) ;
            
            for ( Var v : vars )
                action.var(acc, v) ;
        }
        
    }
    
    static class ExprNoOpVarsWorker<T> extends ExprVarsWorker<T>
    {
        public ExprNoOpVarsWorker(Collection<T> acc, Action<T> action) {
            super(acc, action);
        }

        @Override
        public void visit(ExprFunctionOp funcOp) {
            // As for ExprVarsWorker except don't include the vars in the
            // the algebra exprssion of an ExprFunctionOp
            return;
        }
    }
}

@@ -1692,221 +1692,31 @@
 on =
-%0A            new ExprVars.Action%3CVar%3E()%7B%0A                @Override%0A                public void var(Collection%3CVar%3E acc, Var var)%0A                %7B%0A                    acc.add(var) ;%0A                %7D%0A            %7D
+ (a, var) -%3E a.add(var)
  ;%0A 
@@ -1947,249 +1947,31 @@
 on =
-%0A                new ExprVars.Action%3CVar%3E()%7B%0A                    @Override%0A                    public void var(Collection%3CVar%3E acc, Var var)%0A                    %7B%0A                        acc.add(var) ;%0A                    %7D%0A                %7D
+ (a, var) -%3E a.add(var)
  ;%0A 
@@ -2398,240 +2398,44 @@
 on =
-%0A            new ExprVars.Action%3CString%3E()%7B%0A                @Override%0A                public void var(Collection%3CString%3E acc, Var var)%0A                %7B%0A                    acc.add(var.getVarName()) ;%0A                %7D%0A            %7D
+ (a, var) -%3E a.add(var.getVarName())
  ;%0A 

Use lambdas