/*
 * 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.openjpa.jdbc.kernel;

import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.StateManagerImpl;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.persistence.EntityManagerImpl;
import org.apache.openjpa.persistence.FetchPlan;
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
import org.apache.openjpa.persistence.jdbc.JDBCFetchPlan;
import org.apache.openjpa.persistence.test.SQLListenerTestCase;

public class TestJDBCStoreOptSelect extends SQLListenerTestCase {
    Object[] props = new Object[] { CLEAR_TABLES, OptSelectEntity.class
        };
    OptSelectEntity e1, e2;

    @Override
    public void setUp() throws Exception {
        super.setUp(props);
        createData();
    }

    public void test() {
        OpenJPAEntityManagerSPI em = emf.createEntityManager();
        StoreManager store = ((EntityManagerImpl) em).getBroker().getStoreManager().getDelegate();

        FetchPlan fp = getFetchPlan(em);
        try {
            sql.clear();

            if (!(store instanceof JDBCStoreManager)) {
                fail("StoreManager is not an instanceof JDBCStoreManager");
            }
            // Set this JDBCFetchPlan property so that we will select FKs for fields that are in the DFG, but not
            // included in the current load. If this property isn't set, the FK for eagerOneToOneOwner will not be
            // selected.
             ((JDBCFetchPlan)fp).setIgnoreDfgForFkSelect(true);

            // Remove all relationships
            fp.removeField(OptSelectEntity.class, "eagerOneToOne");
            fp.removeField(OptSelectEntity.class, "eagerOneToOneOwner");
            fp.removeField(OptSelectEntity.class, "lazyOneToOne");
            fp.removeField(OptSelectEntity.class, "lazyOneToOneOwner");

            OptSelectEntity ee1 = em.find(OptSelectEntity.class, e1.getId());

            // Make sure our sql has no joins
            assertEquals(1, sql.size());
            String s = sql.get(0);
            assertFalse(s.contains("JOIN") && s.contains("join"));

            // Check to see how many fks(intermediate fields) we selected.
            StateManagerImpl smi = ((StateManagerImpl) ((PersistenceCapable) ee1).pcGetStateManager());
            ClassMetaData cmd =
                em.getConfiguration().getMetaDataRepositoryInstance().getMetaData(OptSelectEntity.class, null, true);
            int fks = 0;
            for (FieldMetaData fmd : cmd.getFields()) {
                if (smi.getIntermediate(fmd.getIndex()) != null) {
                    fks++;
                }
            }
            // We expected to find 2 FKs. One for each of the owners (lazyOneToOneOwner and eagerOneToOneOwner)
            assertEquals(2, fks);
        } finally {
            if (em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
            if (em.isOpen()) {
                em.close();
            }
        }
    }

    private FetchPlan getFetchPlan(OpenJPAEntityManagerSPI em) {
        MetaDataRepository mdr = em.getConfiguration().getMetaDataRepositoryInstance();
        FetchPlan fp = em.pushFetchPlan();
        fp.removeFetchGroups(fp.getFetchGroups());
        for (Class<?> cls : new Class<?>[] { OptSelectEntity.class }) {
            ClassMetaData cmd = mdr.getMetaData(cls, null, true);
            for (FieldMetaData fmd : cmd.getFields()) {
                fp.addField(cls, fmd.getName());
            }
        }
        return fp;
    }

    void createData() {
        OpenJPAEntityManagerSPI em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            e1 = new OptSelectEntity();
            e2 = new OptSelectEntity();

            e1.setEagerOneToOne(e2);
            e2.setEagerOneToOneOwner(e2);

            e1.setLazyOneToOne(e2);
            e2.setLazyOneToOneOwner(e1);

            em.persistAll(e1, e2);

            em.getTransaction().commit();
        } finally {
            if (em.getTransaction().isActive())
                em.getTransaction().rollback();
            if (em.isOpen())
                em.close();
        }
    }
}
