/*
 * 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.vxquery.compiler.rewriter.rules;

import java.util.List;

import org.apache.commons.lang3.mutable.Mutable;
import org.apache.vxquery.compiler.rewriter.rules.util.ExpressionToolbox;
import org.apache.vxquery.compiler.rewriter.rules.util.OperatorToolbox;
import org.apache.vxquery.context.RootStaticContextImpl;
import org.apache.vxquery.context.StaticContextImpl;
import org.apache.vxquery.datamodel.accessors.TaggedValuePointable;
import org.apache.vxquery.functions.BuiltinFunctions;
import org.apache.vxquery.functions.BuiltinOperators;
import org.apache.vxquery.functions.Function;
import org.apache.vxquery.types.SequenceType;

import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.IOptimizationContext;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import edu.uci.ics.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
import edu.uci.ics.hyracks.data.std.primitive.IntegerPointable;

/**
 * The rule searches for where the xquery treat function is used. When the
 * expression's return type matches the treat expression type, the treat is
 * removed.
 * 
 * <pre>
 * Before
 * 
 *   plan__parent
 *   %OPERATOR( $v1 : treat( \@input_expression, \@type_expression ) )
 *   plan__child
 *   
 *   Where treat \@type_expression is the same as the return type of \@input_expression.
 *   
 * After 
 * 
 *   plan__parent
 *   %OPERATOR( $v1 : \@input_expression )
 *   plan__child
 * </pre>
 * 
 * @author prestonc
 */

public class RemoveRedudantTreatExpressionsRule implements IAlgebraicRewriteRule {
    final StaticContextImpl dCtx = new StaticContextImpl(RootStaticContextImpl.INSTANCE);
    final int ARG_DATA = 0;
    final int ARG_TYPE = 1;

    @Override
    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
        return false;
    }

    @Override
    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
            throws AlgebricksException {
        boolean modified = false;
        List<Mutable<ILogicalExpression>> expressions = OperatorToolbox.getExpression(opRef);
        for (Mutable<ILogicalExpression> expression : expressions) {
            if (processTreatExpression(expression)) {
                modified = true;
            }
        }
        return modified;
    }

    private boolean processTreatExpression(Mutable<ILogicalExpression> search) {
        boolean modified = false;
        Mutable<ILogicalExpression> treatM = ExpressionToolbox.findFunctionExpression(search,
                BuiltinOperators.TREAT.getFunctionIdentifier());
        if (treatM != null) {
            // Get input function
            AbstractFunctionCallExpression treatFunction = (AbstractFunctionCallExpression) treatM.getValue();
            Mutable<ILogicalExpression> argDataM = treatFunction.getArguments().get(ARG_DATA);
            
            // Find the input return type.
            SequenceType inputSequenceType = null;
            Function function = ExpressionToolbox.getBuiltIn(argDataM);
            if (function == null) {
                return false;
            } else {
                inputSequenceType = function.getSignature().getReturnType();
            }

            // Find the treat type.
            ILogicalExpression argType = treatFunction.getArguments().get(ARG_TYPE).getValue();
            if (argType.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
                return false;
            }
            TaggedValuePointable tvp = new TaggedValuePointable();
            ExpressionToolbox.getConstantAsPointable((ConstantExpression) argType, tvp);

            IntegerPointable pTypeCode = (IntegerPointable) IntegerPointable.FACTORY.createPointable();
            tvp.getValue(pTypeCode);
            SequenceType sType = dCtx.lookupSequenceType(pTypeCode.getInteger());

            // remove
            if (inputSequenceType != null && inputSequenceType.equals(sType)) {
                treatM.setValue(argDataM.getValue());
                modified = true;
                processTreatExpression(argDataM);
            }
        }
        return modified;
    }

}

@@ -1249,62 +1249,8 @@
 le;%0A
-import org.apache.vxquery.functions.BuiltinFunctions;%0A
 impo
@@ -1957,89 +1957,8 @@
 on;%0A
-import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;%0A
 impo

Clean up.