/*
 * Copyright (c) 2006, 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
//
package org.eclipse.persistence.jpa.tests.jpql;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import org.eclipse.persistence.jpa.jpql.AbstractValidator;
import org.eclipse.persistence.jpa.jpql.JPQLQueryProblem;
import org.eclipse.persistence.jpa.jpql.JPQLQueryProblemResourceBundle;
import org.eclipse.persistence.jpa.jpql.parser.JPQLExpression;
import org.eclipse.persistence.jpa.jpql.parser.JPQLGrammar;
import org.eclipse.persistence.jpa.jpql.parser.JPQLQueryBNF;
import org.eclipse.persistence.jpa.tests.jpql.parser.JPQLGrammarTestHelper;
import org.eclipse.persistence.jpa.tests.jpql.parser.JPQLQueryBuilder;
import org.eclipse.persistence.jpa.tests.jpql.parser.JPQLQueryStringFormatter;
import static org.junit.Assert.*;

/**
 * The abstract definition of a unit-test testing an {@link AbstractValidator}.
 *
 * @version 2.4
 * @since 2.3
 * @author Pascal Filion
 */
@SuppressWarnings("nls")
public abstract class AbstractValidatorTest extends JPQLCoreTest {

    /**
     * The {@link JPQLGrammar} that is injected by the test suite, which is used to parse the JPQL query.
     */
    @JPQLGrammarTestHelper
    protected JPQLGrammar jpqlGrammar;

    /**
     * The {@link ResourceBundle} that contains the key-value pairs coming from the .properties file.
     */
    private ResourceBundle propertiesFile;

    /**
     * The {@link ResourceBundle} that contains the key-value pairs coming from {@link JPQLQueryProblemResourceBundle}.
     */
    private ResourceBundle resourceBundle;

    /**
     * The validator being tested.
     */
    private AbstractValidator validator;

    private CharSequence buildProblemMessages(List<JPQLQueryProblem> problems) {

        StringBuilder sb = new StringBuilder();

        for (int index = 0, count = problems.size(); index < count; index++) {

            JPQLQueryProblem problem = problems.get(index);
            sb.append(problem.getMessageKey());

            if (index + 1 < count) {
                sb.append(", ");
            }
        }

        return sb;
    }

    protected abstract AbstractValidator buildValidator();

    /**
     * Retrieves the BNF object that was registered for the given unique identifier.
     *
     * @param queryBNFId The unique identifier of the {@link JPQLQueryBNF} to retrieve
     * @return The {@link JPQLQueryBNF} representing a section of the grammar
     */
    protected JPQLQueryBNF getQueryBNF(String queryBNFId) {
        return jpqlGrammar.getExpressionRegistry().getQueryBNF(queryBNFId);
    }

    protected AbstractValidator getValidator() {
        return validator;
    }

    private ResourceBundle loadPropertiesFile() {

        // Running from plug-in project in Eclipse
        ClassLoader classLoader = AbstractValidator.class.getClassLoader();
        URL url = classLoader.getResource("/resource/org/eclipse/persistence/jpa/jpql/jpa_jpql_validation.properties");

        if (url != null) {
            return ResourceBundle.getBundle(
                "resource.org.eclipse.persistence.jpa.jpql.jpa_jpql_validation",
                Locale.getDefault(),
                classLoader
            );
        }
        // Running within the plug-in jar or from Hermes JUnit test
        else {
            return ResourceBundle.getBundle(
                JPQLQueryProblemResourceBundle.PROPERTIES_FILE_NAME,
                Locale.getDefault(),
                classLoader
            );
        }
    }

    private ResourceBundle loadResourceBundle() {
        return ResourceBundle.getBundle(JPQLQueryProblemResourceBundle.class.getName());
    }

    @Override
    protected void setUpClass() throws Exception {
        super.setUpClass();

        // Load the resource bundles
        resourceBundle = loadResourceBundle();
        propertiesFile = loadPropertiesFile();

        // Create the validator that is used by this unit-test
        validator = buildValidator();
    }

    @Override
    protected void tearDown() throws Exception {
        if (validator != null) {
            validator.dispose();
        }
        super.tearDown();
    }

    @Override
    protected void tearDownClass() throws Exception {
        jpqlGrammar    = null;
        validator      = null;
        resourceBundle = null;
        propertiesFile = null;
        super.tearDownClass();
    }

    protected final void testDoesNotHaveProblem(List<JPQLQueryProblem> problems, String messageKey) {

        for (JPQLQueryProblem problem : problems) {
            assertFalse(
                messageKey + " should not be part of the list",
                problem.getMessageKey() == messageKey
            );
        }
    }

    protected final void testHasNoProblems(List<JPQLQueryProblem> problems) {
        assertTrue(
            "The list of problems should be empty: " + buildProblemMessages(problems),
            problems.isEmpty()
        );
    }

    protected final void testHasOnlyOneProblem(List<JPQLQueryProblem> problems,
                                               String messageKey,
                                               int startPosition,
                                               int endPosition) {

        assertFalse(
            "There are no problems in the list: " + messageKey,
            problems.isEmpty()
        );

        assertEquals(
            "More than one problem was found: " + buildProblemMessages(problems),
            1,
            problems.size()
        );

        JPQLQueryProblem problem = problems.get(0);

        assertSame(
            "The problem was not added to the list: " + messageKey,
            messageKey,
            problem.getMessageKey()
        );

        testProblem(problem, startPosition, endPosition);
    }

    protected final void testHasOnlyTheseProblems(List<JPQLQueryProblem> problems,
                                                  String[] messageKeys,
                                                  int[] startPositions,
                                                  int[] endPositions) {

        List<String> problemsNotFound = new ArrayList<String>();
        List<String> extraProblems = new ArrayList<String>();

        for (String messageKey : messageKeys) {
            problemsNotFound.add(messageKey);
        }

        for (JPQLQueryProblem problem : problems) {
            extraProblems.add(problem.getMessageKey());
        }

        // Iterate through the problems that should be part of the list
        for (int index = 0; index < messageKeys.length; index++) {

            String messageKey = messageKeys[index];

            // Iterator through the list that was generated from validation
            for (JPQLQueryProblem problem : problems) {

                if (problem.getMessageKey()    == messageKey &&
                    problem.getStartPosition() == startPositions[index] &&
                    problem.getEndPosition()   == endPositions  [index]) {

                    extraProblems.remove(messageKey);
                    problemsNotFound.remove(messageKey);
                    testResourceBundle(messageKey);
                    break;
                }
            }
        }

        assertTrue(
            "Some problems were not added to the list or has wrong positions: " + problemsNotFound,
            problemsNotFound.isEmpty()
        );

        assertTrue(
            "Some problems were incorrectly added to the list: " + extraProblems,
            extraProblems.isEmpty()
        );
    }

    protected final void testHasProblem(List<JPQLQueryProblem> problems,
                                        String messageKey,
                                        int startPosition,
                                        int endPosition) {

        JPQLQueryProblem problem = null;

        for (JPQLQueryProblem queryProblem : problems) {
            if (messageKey == queryProblem.getMessageKey()) {
                problem = queryProblem;
                break;
            }
        }

        assertNotNull(
            "The problem was not added to the list: " + messageKey,
            problem
        );

        testProblem(problem, startPosition, endPosition);
    }

    protected final void testHasProblems(List<JPQLQueryProblem> problems,
                                         String[] messageKeys,
                                         int[] startPositions,
                                         int[] endPositions) {

        List<String> problemsNotFound = new ArrayList<String>();

        for (String messageKey : messageKeys) {
            problemsNotFound.add(messageKey);
        }

        // Iterate through the problems that should be part of the list
        for (int index = 0; index < messageKeys.length; index++) {

            String messageKey = messageKeys[index];

            // Iterator through the list that was generated from validation
            for (JPQLQueryProblem problem : problems) {

                if (problem.getMessageKey()    == messageKey &&
                    problem.getStartPosition() == startPositions[index] &&
                    problem.getEndPosition()   == endPositions[index]) {

                    problemsNotFound.remove(messageKey);
                    testResourceBundle(messageKey);
                    break;
                }
            }
        }

        assertTrue(
            "Some problems were not added to the list: " + problemsNotFound,
            problemsNotFound.isEmpty()
        );
    }

    private void testProblem(JPQLQueryProblem problem, int startPosition, int endPosition) {

        assertEquals(
            "The start position was not calculating correctly",
            startPosition,
            problem.getStartPosition()
        );

        assertEquals(
            "The end position was not calculating correctly",
            endPosition,
            problem.getEndPosition()
        );

        testResourceBundle(problem.getMessageKey());
    }

    protected void testResourceBundle(String messageKey) {

        // JPQLQueryProblemResourceBundle
        assertNotNull(
            messageKey + " was not added to the resource bundle clas",
            resourceBundle.getString(messageKey)
        );

        // jpa_jpql_validation.properties
        assertNotNull(
            messageKey + " was not added to the .properties file",
            propertiesFile.getString(messageKey)
        );
    }

    /**
     * Validates the given named query and returns the list of {@link JPQLQueryProblem problems}.
     *
     * @param jpqlQuery The JPQL query to validate
     * @return Either an empty list if validation didn't find any problem or the list of
     * {@link JPQLQueryProblem problems}
     */
    protected List<JPQLQueryProblem> validate(String jpqlQuery) throws Exception {
        return validate(jpqlQuery, JPQLQueryStringFormatter.DEFAULT);
    }

    /**
     * Validates the JPQL query and returns the list of {@link JPQLQueryProblem problems}.
     *
     * @param jpqlQuery The JPQL query to validate
     * @param jpqlExpression The parsed tree representation of the JPQL query
     * @return Either an empty list if validation didn't find any problem or the list of {@link
     * JPQLQueryProblem problems}
     */
    protected List<JPQLQueryProblem> validate(String jpqlQuery, JPQLExpression jpqlExpression) throws Exception {
        List<JPQLQueryProblem> problems = new ArrayList<JPQLQueryProblem>();
        validator.setProblems(problems);
        jpqlExpression.accept(validator);
        return problems;
    }

    /**
     * Validates the given named query and returns the list of {@link JPQLQueryProblem problems}.
     *
     * @param jpqlQuery The JPQL query to validate
     * @param formatter The formatter used to update the format of the query when validating the parsed tree
     * @return Either an empty list if validation didn't find any problem or the list of {@link
     * JPQLQueryProblem problems}
     */
    protected List<JPQLQueryProblem> validate(String jpqlQuery, JPQLQueryStringFormatter formatter) throws Exception {
        JPQLExpression jpqlExpression = JPQLQueryBuilder.buildQuery(jpqlQuery, jpqlGrammar, formatter, true);
        return validate(jpqlQuery, jpqlExpression);
    }
}
