/*
 * 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.persistence.proxy;

import java.util.LinkedHashSet;

import javax.persistence.EntityManager;

import org.apache.openjpa.persistence.test.SingleEMFTestCase;
import org.apache.openjpa.util.ChangeTracker;
import org.apache.openjpa.util.ProxyCollection;

/**
 * Tests proxying and change tracking of collection fields for modification in
 * detached state.
 *
 * Originally reported in
 * <A HREF="https://issues.apache.org/jira/browse/OPENJPA-628">OPENJPA-628</A>
 *
 * @author Pinaki Poddar
 *
 */
public class TestProxyCollection extends SingleEMFTestCase {
	@Override
    public void setUp() {
		super.setUp(CLEAR_TABLES, TreeNode.class, ConcreteEntity.class, AbstractEntity.class);
	}
	/**
	 * Tests that a uniform tree is created with expected fan outs at each
	 * level. This is not a persistent operation, just in-memory.
	 */
	public void testCreateTree() {
		TreeNode root = new TreeNode();
		root.setName("0");
		int[] fanOuts = {1,2,3};
		root.createTree(fanOuts);
		assertArrayEquals(fanOuts, root.getFanOuts());
	}

	/**
     * Tests that a uniform tree can be modified with different fan outs at each
	 * level. This is not a persistent operation, just in-memory.
	 */
	public void testModifyTree() {
		int[] fanOuts = {1,2,2,4};
		int[] newFanOuts = {1,3,1,2};
		TreeNode root = new TreeNode();
		root.createTree(fanOuts);
		assertArrayEquals(fanOuts, root.getFanOuts());

		root.modify(newFanOuts);
		assertArrayEquals(newFanOuts, root.getFanOuts());
	}

	/**
     * Tests that a uniform tree is persisted and later fetched back with same
	 * number of children at every level.
	 */
	public void testPersistTree() {
		int[] fanOuts = {2,3,4};
		verify(create(fanOuts), fanOuts);
	}

	public void testAddNodeAtLeaf() {
		int[] original = {1,2,3};
		int[] modifier = {1,2,4}; // add new child at Level 2
		createModifyAndMerge(original, modifier);
	}

	public void testAddNewLevel() {
		int[] original = {1,2,3};
		int[] modifier = {1,2,3,2}; // add 2 new children at new Level
		createModifyAndMerge(original, modifier);
	}

	public void testAddAndRemove() {
		int[] original = {2,3,4};
        int[] modifier = {4,3,2}; // add 1 at Level 1 + remove 1 at Level 3
		createModifyAndMerge(original, modifier);
	}

	public void testAddAtAllLevel() {
		int[] original = {2,3,4};
		int[] modifier = {3,4,5}; // add 1 at each Level
		createModifyAndMerge(original, modifier);
	}

	public void testRemoveAtAllLevel() {
		int[] original = {2,3,4};
		int[] modifier = {1,2,3}; // remove 1 from each Level
		createModifyAndMerge(original, modifier);
	}

    public void testCreateCorrectType() {
        ConcreteEntity ce = new ConcreteEntity();
        ce.addItem(ce);

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        em.persist(ce);
        em.getTransaction().commit();
        em.clear();

        ce = em.find(ConcreteEntity.class, ce.getId());
        assertNotNull(ce);
        Class<?> proxyCls = ce.getItems().getClass();
        assertTrue(proxyCls + " is not assignableFrom " + LinkedHashSet.class,
            LinkedHashSet.class.isAssignableFrom(proxyCls));
    }
	/**
	 * Create a uniform tree with original fanout.
	 * Persist.
	 * Verify in a separate persistence context that the tree is stored.
	 * Modify the tree by adding or deleting nodes according to the given
	 * modified fanouts outside a transaction.
	 * Merge the changes.
	 * Verify that the changes are merged by fetching the modified version.
	 *
	 * @param original
	 * @param modified
	 */
	void createModifyAndMerge(int[] original, int[] modifier) {
		TreeNode root = create(original);

		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		TreeNode modified = em.find(TreeNode.class, root.getId());
		modified.modify(modifier);
		em.merge(modified);
		em.getTransaction().commit();

		em.clear();

		assertProxyCollection(root.getNodes(), false);

		verify(root, modifier);
	}

	/**
	 * Create a uniform tree with given fan out.
	 * Persist.
     * Verify that the tree is stored by fetching it in a separate persistence
	 * context.
	 */
	TreeNode create(int[] original) {
		TreeNode root = new TreeNode();
		root.createTree(original);

		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		em.persist(root);
		em.getTransaction().commit();
		em.clear();

		return root;
	}

	void verify(TreeNode node, int[] fanOuts) {
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		TreeNode test = em.find(TreeNode.class, node.getId());
		assertNotNull(test);
		assertArrayEquals(fanOuts, test.getFanOuts());
	}

    /**
     * Asserts the given arrays have exactly same elements at the same index.
     */
	void assertArrayEquals(int[] a, int[] b) {
		assertEquals(a.length, b.length);
		for (int i = 0; i<a.length; i++)
			assertEquals(a[i], b[i]);
	}

	/**
     * Asserts that the given object is a proxy collection and whether it is
	 * tracking changes.
	 */
	void assertProxyCollection(Object o, boolean tracking) {
		assertTrue(o instanceof ProxyCollection);
		ChangeTracker tracker = ((ProxyCollection)o).getChangeTracker();
		if (tracking) {
			assertNotNull(tracker);
			assertTrue(tracker.isTracking());
		} else {
			assertFalse(tracker.isTracking());
		}
	}

	/**
	 * Asserts that the given object is NOT a proxy collection.
	 */
	void assertNotProxyCollection(Object o) {
		assertFalse(o instanceof ProxyCollection);
	}
}

