/*
 * 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.testing.tests.queries;

import java.util.*;

import org.eclipse.persistence.testing.framework.*;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.sessions.AbstractSession;

/**
 * Test the cursored stream feature by performing a cursor read on the database
 * and comparing the contents to a normal query read.
 */
public class

CursoredStreamTest extends AutoVerifyTestCase {
    protected int size;
    protected Vector normalQueryObjects;
    protected Vector cursoredQueryObjects;
    protected Class<?> referenceClass;
    protected Expression joinExpression;

    public CursoredStreamTest(Class<?> referenceClass, Expression expression) {
        setReferenceClass(referenceClass);
        setName(getName() + "(" + referenceClass + ")");
        setDescription("This test verifies that the number of objects read in using a cursored stream" +
                       " matches the number of object read in using a normal query");
        joinExpression = expression;
    }

    public Vector getCursoredQueryObjects() {
        return cursoredQueryObjects;
    }

    public Vector getNormalQueryObjects() {
        return normalQueryObjects;
    }

    public Class<?> getReferenceClass() {
        return referenceClass;
    }

    public int getSize() {
        return size;
    }

    public void setCursoredQueryObjects(Vector objects) {
        cursoredQueryObjects = objects;
    }

    public void setNormalQueryObjects(Vector objects) {
        normalQueryObjects = objects;
    }

    public void setReferenceClass(Class<?> aClass) {
        referenceClass = aClass;
    }

    public void setSize(int aSize) {
        size = aSize;
    }

    @Override
    protected void setup() {
        setNormalQueryObjects(getSession().readAllObjects(getReferenceClass(), joinExpression));
        getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
    }

    @Override
    public void test() {

        ReadAllQuery query = new ReadAllQuery();
        CursoredStream stream = null;

        try {
            Object databaseObject;

            cursoredQueryObjects = new Vector();

            query.setReferenceClass(getReferenceClass());
            query.setSelectionCriteria(joinExpression);
            query.useCursoredStream();
            stream = (CursoredStream)getSession().executeQuery(query);

            // Test dual cursors and read(int)
            CursoredStream stream2 = (CursoredStream)getSession().executeQuery(query);
            try {
                stream2.read(5);
            } catch (org.eclipse.persistence.exceptions.QueryException ex) {
            } // ignore at end
            setSize(stream2.size());
            stream2.close();
            while (!stream.atEnd()) {
                databaseObject = stream.read();
                getCursoredQueryObjects().addElement(databaseObject);
                stream.releasePrevious();
            }
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }

    /**
     * Verify if number of query objects matches number of cursor objects
     */
    @Override
    protected void verify() {
        if (getNormalQueryObjects().size() != getCursoredQueryObjects().size()) {
            throw new TestErrorException("The number of streamed objects does not match the number of objects stored on the database.  Expected: " +
                                         getNormalQueryObjects().size() + ". Got: " +
                                         getCursoredQueryObjects().size());
        }

        if (getNormalQueryObjects().size() == 0) {
            throw new TestWarningException("no object with the specified selection criteria was found ");
        }

        if (getSize() != getNormalQueryObjects().size()) {
            throw new TestErrorException("The cursored stream size function is not working properly");
        }

        int first = 0;
        int last = getNormalQueryObjects().size() - 1;
        if (!((AbstractSession)getSession()).compareObjects(getCursoredQueryObjects().elementAt(first),
                                                            getNormalQueryObjects().elementAt(first))) {
            throw new TestErrorException("The First Objects do not match");
        }
        if (!((AbstractSession)getSession()).compareObjects(getCursoredQueryObjects().elementAt(last),
                                                            getNormalQueryObjects().elementAt(last))) {
            throw new TestErrorException("The Last Objects do not match");
        }


    }
}
