/*
 * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.jpa.parsing;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReportQuery;

/**
 * INTERNAL:
 * <p><b>Purpose</b>: Represent a SELECT
 * <p><b>Responsibilities</b>:<ul>
 * <li> Hold the distinct status
 * <li> Modify a query based on the contents
 * </ul>
 *
 * <p>The SELECT statement determines the return type of an EJBQL query.
 * The SELECT may also determine the distinct state of a query
 *
 * A SELECT can be one of the following:
 * <pre>
 *  1. SELECT OBJECT(someObject)... This query will return a collection of objects
 *  2. SELECT anObject.anAttribute ... This will return a collection of anAttribute
 *  3. SELECT &lt;aggregateFunction&gt; ... This will return a single value
 *      The allowable aggregateFunctions are: AVG, COUNT, MAX, MIN, SUM
 *          SELECT AVG(emp.salary)... Returns the average of all the employees salaries
 *          SELECT COUNT(emp)... Returns a count of the employees
 *          SELECT COUNT(emp.firstName)... Returns a count of the employee's firstNames
 *          SELECT MAX(emp.salary)... Returns the maximum employee salary
 *          SELECT MIN(emp.salary)... Returns the minimum employee salary
 *          SELECT SUM(emp.salary)... Returns the sum of all the employees salaries
 * </pre>
 * @author Jon Driscoll
 * @since TopLink 5.0
 */
public class SelectNode extends QueryNode {

    private List<Node> selectExpressions = new ArrayList<>();
    private List<String> identifiers = new ArrayList<>();

    private boolean distinct = false;

    public SelectNode() {
    }

    public List<Node> getSelectExpressions() {
        return selectExpressions;
    }

    public void setSelectExpressions(List<Node> exprs) {
        selectExpressions = exprs;
    }

    public List<String> getIdentifiers() {
        return identifiers;
    }

    public void setIdentifiers(List<String> identifiers) {
        this.identifiers = identifiers;
    }

    public boolean usesDistinct() {
        return distinct;
    }
    public void setDistinct(boolean distinct) {
        this.distinct = distinct;
    }

    /**
     * Returns a DatabaseQuery instance representing the owning
     * ParseTree. This implementation returns a ReadAllQuery for simple SELECT
     * queries and a ReportQuery otherwise.
     */
    @Override
    public DatabaseQuery createDatabaseQuery(ParseTreeContext context) {

        // TODO: This optimization needs to be revisited because it causes GlassFish issues: 2084 and 2171
        // These issues have been solve in GlassFish by always generating a ReportQuery
        // The same fix has not been made in Oracle TopLink because it disables some advanced JPA Query Hints
        ObjectLevelReadQuery query;
        if (isReadAllQuery(context)) {
            query = new ReadAllQuery();
        } else {
            query = new ReportQuery();
        }
        query.dontUseDistinct(); //gf bug 1395- prevents using distinct unless user specified
        return query;
    }

    /**
     * Returns true if the SELECT clause consists of a single expression
     * returning the base identification variable of the query and if the base
     * variable is defined as a range variable w/o FETCH JOINs.
     */
    private boolean isReadAllQuery(ParseTreeContext context) {
        if (!isSingleSelectExpression()) {
            // multiple expressions in the select clause => ReportQuery
            return false;
        }

        Node node = getFirstSelectExpressionNode();
        if (!node.isVariableNode()) {
            // Does not select an identification variable (e.g. projection or
            // aggregate function) =>  ReportQuery
            return false;
        }
        String variable = ((VariableNode)node).getCanonicalVariableName();

        // Note, the base variable in ParseTreeContext is not yet set =>
        // calculate it
        String baseVariable = getParseTree().getFromNode().getFirstVariable();
        if (!context.isRangeVariable(baseVariable)) {
            // Query's base variable is not a range variable.
            return false;
        }

        // Bug 393470
        // Use ReportQuery for GROUP BY / HAVING clauses in ANTLR
        if (getParseTree().hasGroupBy() || getParseTree().hasHaving()) {
            return false;
        }

        // Use ReadAllQuery if the variable of the SELECT clause expression is
        // the base variable
        return baseVariable.equals(variable);
    }

    /**
     * INTERNAL
     * Apply this node to the passed query
     */
    @Override
    public void applyToQuery(DatabaseQuery theQuery, GenerationContext context) {
        ObjectLevelReadQuery readQuery = (ObjectLevelReadQuery)theQuery;
        if (selectExpressions.isEmpty()) {
            return;
        }

        //set the distinct state
        //BUG 3168673: Don't set distinct state if we're using Count
        if (!(isSingleSelectExpression() && getFirstSelectExpressionNode().isCountNode())) {
            // Set the distinct state for the query
            if (usesDistinct()) {
                getParseTree().setDistinctState(ObjectLevelReadQuery.USE_DISTINCT);
                readQuery.setDistinctState(ObjectLevelReadQuery.USE_DISTINCT);
            }
        }

        if (readQuery instanceof ReportQuery) {
            ReportQuery reportQuery = (ReportQuery)readQuery;
            reportQuery.returnWithoutReportQueryResult();
            if (isSingleSelectExpression()) {
                reportQuery.returnSingleAttribute();
            }
        }
        SelectGenerationContext selectContext = (SelectGenerationContext)context;
        for (int i=0;i<selectExpressions.size();i++){
            Node node = selectExpressions.get(i);
            if (selectingRelationshipField(node, context)) {
                selectContext.useOuterJoins();
            }
            if (node.isAliasableNode() && identifiers != null){
                String alias = identifiers.get(i);
                if (alias != null){
                    ((AliasableNode)node).setAlias(alias);
                }
            }
            node.applyToQuery(readQuery, context);
            selectContext.dontUseOuterJoins();
        }

        //indicate on the query if "return null if primary key null"
        //This means we want nulls returned if we expect an outer join
        readQuery.setShouldBuildNullForNullPk(this.hasOneToOneSelected(context));

    }

    public boolean hasOneToOneSelected(GenerationContext context) {
        // Iterate the select expression and return true if one of it has a
        // oneToOne selected.
        for (Iterator<Node> i = selectExpressions.iterator(); i.hasNext();) {
            Node node = i.next();
            if (hasOneToOneSelected(node, context)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Answer true if there is a one-to-one relationship selected.
     * This includes a chain of relationships.
     * True: SELECT employee.address FROM ..... //Simple 1:1
     * True: SELECT a.b.c.d FROM ..... //where a-{@literal >}b, b-{@literal >}c and c-{@literal >}d are all 1:1.
     * False: SELECT OBJECT(employee) FROM ..... //simple SELECT
     * False: SELECT phoneNumber.areaCode FROM ..... //direct-to-field
     */
    private boolean hasOneToOneSelected(Node node, GenerationContext context) {
        //BUG 3240484: Not SELECTing 1:1 if it's in a COUNT
        if (node.isCountNode()) {
            return false;
        }

        if (node.isAggregateNode()) {
            // delegate to aggregate expression
            return hasOneToOneSelected(node.getLeft(), context);
        }

        if (node.isVariableNode()){
            return !nodeRefersToObject(node, context);
        }

        if (node.isConstructorNode()) {
            List<Node> args = ((ConstructorNode)node).getConstructorItems();
            for (Iterator<Node> i = args.iterator(); i.hasNext();) {
                Node arg = i.next();
                if (hasOneToOneSelected(arg, context)) {
                    return true;
                }
            }
            return false;
        }

        // check whether it is a direct-to-field mapping
        return !selectingDirectToField(node, context);
    }

    /**
     * Verify that the selected alias is a valid alias. If it's not valid,
     * an Exception will be thrown, likely JPQLException.aliasResolutionException.
     *
     * Valid: SELECT OBJECT(emp) FROM Employee emp WHERE ...
     * Invalid: SELECT OBJECT(badAlias) FROM Employee emp WHERE ...
     */
    public void verifySelectedAlias(GenerationContext context) {
        for (Iterator<Node> i = selectExpressions.iterator(); i.hasNext();) {
            Node node = i.next();
            //if the node is a DotNode, there is no selected alias
            if (node.isDotNode()) {
                return;
            }
            node.resolveClass(context);
        }
    }

    /**
     * Answer true if the variable name given as argument is SELECTed.
     *
     * True: "SELECT OBJECT(emp) ...." &amp; variableName = "emp"
     * False: "SELECT OBJECT(somethingElse) ..." &amp; variableName = "emp"
     */
    public boolean isSelected(String variableName) {
        for (Iterator<Node> i = selectExpressions.iterator(); i.hasNext();) {
            Node node = i.next();
            //Make sure we've SELECted a VariableNode
            if (node.isVariableNode() &&
                ((VariableNode)node).getCanonicalVariableName().equals(variableName)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isSelectNode() {
        return true;
    }

    /**
     * Check the select expression nodes for a path expression starting with a
     * unqualified field access and if so, replace it by a qualified field
     * access.
     */
    @Override
    public Node qualifyAttributeAccess(ParseTreeContext context) {
        for (int i = 0; i < selectExpressions.size(); i++) {
            Node item = selectExpressions.get(i);
            selectExpressions.set(i, item.qualifyAttributeAccess(context));
        }
        return this;
    }

    /**
     * Validate node.
     */
    @Override
    public void validate(ParseTreeContext context) {
        for (Iterator<Node> i = selectExpressions.iterator(); i.hasNext(); ) {
            Node item = i.next();
            item.validate(context);
        }
    }

    /**
     * Answer the class associated with my left node.
     */
    @Override
    public Class<?> resolveClass(GenerationContext context) {
        return getReferenceClass(context);
    }

    /**
     * Return a EclipseLink expression generated using the left node.
     */
    @Override
    public Expression generateExpression(GenerationContext context) {
        return null;
    }

    /**
     * Compute the Reference class for this query.
     * @return the class this query is querying for
     */
    @Override
    public Class<?> getReferenceClass(GenerationContext context) {
        return getClassOfFirstVariable(context);
    }

    private Class<?> getClassOfFirstVariable(GenerationContext context) {
        Class<?> clazz = null;
        String variable = getParseTree().getFromNode().getFirstVariable();
        ParseTreeContext parseTreeContext = context.getParseTreeContext();
        if (parseTreeContext.isRangeVariable(variable)) {
            String schema = parseTreeContext.schemaForVariable(variable);
            // variables is defines in a range variable declaration, so there
            // is a schema name for this variable
            clazz = parseTreeContext.classForSchemaName(schema, context);
        } else {
            // variable is defined in a JOIN clause, so there is a a defining
            // node for the variable
            Node path = parseTreeContext.pathForVariable(variable);
            clazz = path.resolveClass(context);
        }
        return clazz;
    }

    /**
     * Answer true if a variable in the IN clause is SELECTed
     */
    public boolean isVariableInINClauseSelected(GenerationContext context) {
        for (Iterator<Node> i = selectExpressions.iterator(); i.hasNext();) {
            Node node = i.next();

            if (node.isVariableNode()) {
                String variableNameForLeft = ((VariableNode)node).getCanonicalVariableName();
                if (!context.getParseTreeContext().isRangeVariable(variableNameForLeft)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Answer true if this node refers to an object described later in the EJBQL
     * True: SELECT p FROM Project p
     * False: SELECT p.id FROM Project p
     */
    public boolean nodeRefersToObject(Node node, GenerationContext context) {
        if (!node.isVariableNode()){
            return false;
        }
        String name = ((VariableNode)node).getCanonicalVariableName();
        String alias = context.getParseTreeContext().schemaForVariable(name);
        if (alias != null){
            ClassDescriptor descriptor = context.getSession().getDescriptorForAlias(alias);
            if (descriptor != null){
                return true;
            }
        }
        return false;
    }

    private boolean selectingRelationshipField(Node node, GenerationContext context) {
        if ((node == null) || !node.isDotNode()) {
            return false;
        }
        TypeHelper typeHelper = context.getParseTreeContext().getTypeHelper();
        Node path = node.getLeft();
        AttributeNode attribute = (AttributeNode)node.getRight();
        return typeHelper.isRelationship(path.getType(),
                                         attribute.getAttributeName());
    }

    /**
     * Answer true if the SELECT ends in a direct-to-field.
     * true: SELECT phone.areaCode
     * false: SELECT employee.address
     */
    private boolean selectingDirectToField(Node node, GenerationContext context) {

        if ((node == null) || !node.isDotNode()) {
            return false;
        }
        return ((DotNode)node).endsWithDirectToField(context);
    }

    /**
     * Returns the first select expression node.
     */
    private Node getFirstSelectExpressionNode() {
        return selectExpressions.size() > 0 ?
                selectExpressions.get(0) : null;
    }

    private boolean isSingleSelectExpression() {
        return selectExpressions.size() == 1;
    }

}
