/*******************************************************************************
 * 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.sling.scripting.sightly.impl.compiler.optimization.reduce;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.sling.scripting.sightly.compiler.SightlyCompilerException;
import org.apache.sling.scripting.sightly.compiler.expression.Expression;
import org.apache.sling.scripting.sightly.compiler.expression.ExpressionNode;
import org.apache.sling.scripting.sightly.compiler.expression.NodeVisitor;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.ArrayLiteral;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.BinaryOperation;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.BooleanConstant;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.Identifier;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.MapLiteral;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.NullLiteral;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.NumericConstant;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.PropertyAccess;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.RuntimeCall;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.StringConstant;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.TernaryOperator;
import org.apache.sling.scripting.sightly.compiler.expression.nodes.UnaryOperation;
import org.apache.sling.scripting.sightly.compiler.util.VariableTracker;
import org.apache.sling.scripting.sightly.compiler.util.ObjectModel;

/**
 * Try to evaluate constant parts in expressions
 */
public class ExpressionReducer implements NodeVisitor<EvalResult> {

    private final VariableTracker<EvalResult> tracker;

    public static EvalResult reduce(ExpressionNode node, VariableTracker<EvalResult> tracker) {
        ExpressionReducer reducer = new ExpressionReducer(tracker);
        return reducer.eval(node);
    }

    private ExpressionReducer(VariableTracker<EvalResult> tracker) {
        this.tracker = tracker;
    }

    private EvalResult eval(ExpressionNode node) {
        try {
            return node.accept(this);
        } catch (SightlyCompilerException e) {
            if (node instanceof BinaryOperation) {
                BinaryOperation binaryOperation = (BinaryOperation) node;
                Expression parentExpression = binaryOperation.getParentExpression();
                if (parentExpression != null) {
                    throw new SightlyCompilerException(e.getMessage(), parentExpression.getRawText());
                }
            }
            throw e;
        } catch (Exception e) {
            //evaluating constant expressions may lead to errors (like division by zero)
            //in this case we leave the nodes as-is.
            return EvalResult.nonConstant(node);
        }
    }

    @Override
    public EvalResult evaluate(PropertyAccess propertyAccess) {
        EvalResult target = eval(propertyAccess.getTarget());
        EvalResult property = eval(propertyAccess.getProperty());
        if (!target.isConstant() || !property.isConstant()) {
            return EvalResult.nonConstant(new PropertyAccess(
                    target.getNode(),
                    property.getNode()));
        }

        return EvalResult.constant(ObjectModel.resolveProperty(
                target.getValue(), property.getValue()));
    }

    @Override
    public EvalResult evaluate(Identifier identifier) {
        EvalResult result = tracker.get(identifier.getName());
        if (result != null && result.isConstant()) {
            return EvalResult.constant(result.getValue());
        }
        return EvalResult.nonConstant(identifier);
    }

    @Override
    public EvalResult evaluate(StringConstant text) {
        return EvalResult.constant(text.getText());
    }

    @Override
    public EvalResult evaluate(BinaryOperation binaryOperation) {
        EvalResult left = eval(binaryOperation.getLeftOperand());
        EvalResult right = eval(binaryOperation.getRightOperand());
        if (!(left.isConstant() && right.isConstant())) {
            return EvalResult.nonConstant(new BinaryOperation(
                    binaryOperation.getOperator(),
                    left.getNode(),
                    right.getNode()));
        }
        return EvalResult.constant(binaryOperation.getOperator().eval(left.getValue(), right.getValue()));
    }

    @Override
    public EvalResult evaluate(BooleanConstant booleanConstant) {
        return EvalResult.constant(booleanConstant.getValue());
    }

    @Override
    public EvalResult evaluate(NumericConstant numericConstant) {
        return EvalResult.constant(numericConstant.getValue());
    }

    @Override
    public EvalResult evaluate(UnaryOperation unaryOperation) {
        EvalResult target = eval(unaryOperation.getTarget());
        if (!target.isConstant()) {
            return EvalResult.nonConstant(new UnaryOperation(
                    unaryOperation.getOperator(), target.getNode()));
        }
        return EvalResult.constant(unaryOperation.getOperator().eval(target.getValue()));
    }

    @Override
    public EvalResult evaluate(TernaryOperator ternaryOperator) {
        EvalResult condition = eval(ternaryOperator.getCondition());
        if (!condition.isConstant()) {
            return EvalResult.nonConstant(new TernaryOperator(
                    condition.getNode(),
                    ternaryOperator.getThenBranch(),
                    ternaryOperator.getElseBranch()));
        }
        return (ObjectModel.toBoolean(condition.getValue()))
                ? eval(ternaryOperator.getThenBranch())
                : eval(ternaryOperator.getElseBranch());
    }

    @Override
    public EvalResult evaluate(RuntimeCall runtimeCall) {
        List<ExpressionNode> nodes = new ArrayList<>();
        for (ExpressionNode node : runtimeCall.getArguments()) {
            EvalResult result = eval(node);
            nodes.add(result.getNode());
        }
        return EvalResult.nonConstant(new RuntimeCall(runtimeCall.getFunctionName(), nodes));
    }

    @Override
    public EvalResult evaluate(MapLiteral mapLiteral) {
        HashMap<String, EvalResult> results = new HashMap<>();
        boolean isConstant = true;
        for (Map.Entry<String, ExpressionNode> entry : mapLiteral.getMap().entrySet()) {
            EvalResult result = eval(entry.getValue());
            results.put(entry.getKey(), result);
            isConstant = isConstant && result.isConstant();
        }
        if (isConstant) {
            HashMap<String, Object> map = new HashMap<>();
            for (Map.Entry<String, EvalResult> entry : results.entrySet()) {
                map.put(entry.getKey(), entry.getValue().getValue());
            }
            return EvalResult.constant(map);
        } else {
            HashMap<String, ExpressionNode> literal = new HashMap<>();
            for (Map.Entry<String, EvalResult> entry : results.entrySet()) {
                literal.put(entry.getKey(), entry.getValue().getNode());
            }
            return EvalResult.nonConstant(new MapLiteral(literal));
        }
    }

    @Override
    public EvalResult evaluate(ArrayLiteral arrayLiteral) {
        ArrayList<EvalResult> results = new ArrayList<>();
        boolean isConstant = true;
        for (ExpressionNode node : arrayLiteral.getItems()) {
            EvalResult result = eval(node);
            results.add(result);
            isConstant = isConstant && result.isConstant();
        }
        if (isConstant) {
            ArrayList<Object> list = new ArrayList<>();
            for (EvalResult result : results) {
                list.add(result.getValue());
            }
            return EvalResult.constant(list);
        } else {
            ArrayList<ExpressionNode> literal = new ArrayList<>();
            for (EvalResult result : results) {
                literal.add(result.getNode());
            }
            return EvalResult.nonConstant(new ArrayLiteral(literal));
        }
    }

    @Override
    public EvalResult evaluate(NullLiteral nullLiteral) {
        return EvalResult.constant(null);
    }
}
