/*
 * 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 com.hp.hpl.jena.sparql.algebra.optimize;

import com.hp.hpl.jena.sparql.algebra.Op;
import com.hp.hpl.jena.sparql.algebra.TransformCopy;
import com.hp.hpl.jena.sparql.algebra.Transformer;
import com.hp.hpl.jena.sparql.engine.binding.Binding;
import com.hp.hpl.jena.sparql.expr.*;

/**
 * An expression transform that simplifies expressions by constant folding
 * wherever possible
 */
public class ExprTransformConstantFold extends ExprTransformCopy {

    private Binding b = null;

    @Override
    public Expr transform(ExprFunction1 func, Expr expr1) {
        Expr transformed = func.copySubstitute(this.b, true);
        if (transformed.equals(func))
            return super.transform(func, expr1);
        return transformed;
    }

    @Override
    public Expr transform(ExprFunction2 func, Expr expr1, Expr expr2) {
        Expr transformed = func.copySubstitute(this.b, true);
        if (transformed.equals(func))
            return super.transform(func, expr1, expr2);
        return transformed;
    }

    @Override
    public Expr transform(ExprFunction3 func, Expr expr1, Expr expr2, Expr expr3) {
        Expr transformed = func.copySubstitute(this.b, true);
        if (transformed.equals(func))
            return super.transform(func, expr1, expr2, expr3);
        return transformed;
    }

    @Override
    public Expr transform(ExprFunctionN func, ExprList args) {
        Expr transformed = func.copySubstitute(this.b, true);
        if (transformed.equals(func))
            return super.transform(func, args);
        return transformed;
    }

    @Override
    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op opArg) {
        // Calling copySubstitute() likely won't work for these cases

        // Manually transform each argument
        Op op = Transformer.transform(new TransformCopy(), this, funcOp.getGraphPattern());
        ExprList newArgs = new ExprList();
        for (int i = 0; i < funcOp.getArgs().size(); i++) {
            Expr curr = funcOp.getArg(i);
            Expr newArg = curr.copySubstitute(this.b, true);
            newArgs.add(newArg);
        }
        return funcOp.copy(newArgs, op);
    }

}

@@ -1362,24 +1362,213 @@
 pr expr1) %7B%0A
+        // System.out.println(%22transform ExprFunction1: %22 + func + %22 - %22 +%0A        // expr1);%0A        if (!func.getArg().equals(expr1))%0A            func = (ExprFunction1) func.copy(expr1);%0A
         Expr
@@ -1821,24 +1821,270 @@
 pr expr2) %7B%0A
+        // System.out.println(%22transform ExprFunction2: %22 + func + %22 - %22 + expr1%0A        // + %22 - %22 + expr2);%0A        if (!func.getArg1().equals(expr1) %7C%7C !func.getArg2().equals(expr2))%0A            func = (ExprFunction2) func.copy(expr1, expr2);%0A
         Expr
@@ -2247,32 +2247,33 @@
 rn transformed;%0A
+%0A
     %7D%0A%0A    @Over
@@ -2357,24 +2357,327 @@
 pr expr3) %7B%0A
+        // System.out.println(%22transform ExprFunction3: %22 + func + %22 - %22 + expr1%0A        // + %22 - %22 + expr2 + %22 - %22 + expr3);%0A%0A        if (!func.getArg1().equals(expr1) %7C%7C !func.getArg2().equals(expr2) %7C%7C !func.getArg3().equals(expr3))%0A            func = (ExprFunction3) func.copy(expr1, expr2, expr3);%0A
         Expr
@@ -2935,24 +2935,128 @@
 ist args) %7B%0A
+        if (!func.getArgs().equals(args.getList()))%0A            func = (ExprFunctionN) func.copy(args);%0A
         Expr
@@ -3598,24 +3598,12 @@
 i %3C 
-funcOp.getA
+a
 rgs
-()
 .siz
@@ -3642,21 +3642,16 @@
 r = 
-funcOp
+args
 .get
-Arg
 (i);

Rework ExprTransformConstantFold to propogate folded expressions up the tree (JENA-630)