/*
 * Created on 17-Feb-2005
 *
 *
 *
 */
package org.jboss.cache.optimistic;

import org.jboss.cache.*;
import org.jboss.cache.interceptors.Interceptor;
import org.jboss.cache.interceptors.OptimisticCreateIfNotExistsInterceptor;
import org.jboss.cache.interceptors.OptimisticNodeInterceptor;
import org.jboss.cache.loader.SamplePojo;
import org.jboss.cache.transaction.DummyTransactionManager;

import javax.transaction.Transaction;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author xenephon
 */
public class NodeInterceptorRemoveNodeTest extends AbstractOptimisticTestCase
{


    /**
     * @param name
     */
    public NodeInterceptorRemoveNodeTest(String name)
    {
        super(name);

    }

    public void testTransactionRemoveNotExistsNodeMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));


        cache.remove("/one/two");
        mgr.commit();
        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        //assert what should be the results of our call
        assertEquals(0, workspace.getNodes().size());

        assertTrue(entry.getLocks().isEmpty());
        assertEquals(0, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());

        assertEquals(0, listener.getNodesAdded());
        cache.stopService();
    }

    public void testTransactionRemoveNodeMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        cache.remove("/one/two");
        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(false, workspace.getNode(Fqn.fromString("/one")).isDeleted());
        assertEquals(0, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(0)).size());
        assertEquals(1, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(1)).size());
        assertEquals(null, workspace.getNode(Fqn.fromString("/one")).getChild(Fqn.fromString("/one/two")));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(2, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        cache.stopService();

    }

    public void testTransactionRemoveIntermediateNodeMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        cache.remove("/one");
        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one")).isDeleted());
        assertEquals(1, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(0)).size());
        assertEquals(0, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(1)).size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/")).getChild(Fqn.fromString("/one")));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(2, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        cache.stopService();
    }

    public void testTransactionRemoveTwiceMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        // get the transaction stuff
        TransactionTable table = cache.getTransactionTable();
        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        workspace.getNode(Fqn.fromString("/one"));
        workspace.getNode(Fqn.fromString("/one/two"));


        cache.remove("/one");

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one")).isDeleted());

        //will still have alink from one to two
        assertNotNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/")).getChild("one"));

        //now put /one/two back in
        cache.remove("/one");


        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one")).isDeleted());

        //will still have alink from one to two
        assertNotNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/")).getChild("one"));

        assertEquals(null, dummy.getCalled());


        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());


        assertEquals(3, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        cache.stopService();
    }


    public void testTransactionRemovePutNodeMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        // get the transaction stuff
        TransactionTable table = cache.getTransactionTable();
        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        TreeNode one = workspace.getNode(Fqn.fromString("/one"));
        TreeNode two = workspace.getNode(Fqn.fromString("/one/two"));


        cache.remove("/one");

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one")).isDeleted());

        //will still have alink from one to two
        assertNotNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/")).getChild("one"));

        //now put /one/two back in
        cache.put("/one/two", temp);

        WorkspaceNode oneAfter = workspace.getNode(Fqn.fromString("/one"));
        WorkspaceNode twoAfter = workspace.getNode(Fqn.fromString("/one/two"));

        assertNotSame(one, oneAfter);
        assertEquals(false, oneAfter.isDeleted());
        assertNotSame(two, twoAfter);
        assertEquals(false, twoAfter.isDeleted());

        assertEquals(twoAfter.getNode(), workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(oneAfter.getNode(), workspace.getNode(Fqn.fromString("/")).getChild("one"));

        assertEquals(null, dummy.getCalled());


        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());


        assertEquals(3, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        assertEquals(4, listener.getNodesAdded());
        cache.stopService();
    }


    public void testTransactionRemovePutkeyValMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        // get the transaction stuff
        TransactionTable table = cache.getTransactionTable();
        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        TreeNode one = workspace.getNode(Fqn.fromString("/one"));
        TreeNode two = workspace.getNode(Fqn.fromString("/one/two"));


        cache.remove("/one");

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one")).isDeleted());

        //will still have alink from one to two
        assertNotNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/")).getChild("one"));

        //now put /one back in
        SamplePojo pojo2 = new SamplePojo(21, "test");
        cache.put("/one", "key1", pojo2);

        WorkspaceNode oneAfter = workspace.getNode(Fqn.fromString("/one"));
        WorkspaceNode twoAfter = workspace.getNode(Fqn.fromString("/one/two"));

        assertNotSame(one, oneAfter);
        assertEquals(false, oneAfter.isDeleted());
        assertEquals(two, twoAfter);
        assertEquals(true, twoAfter.isDeleted());

        assertNull(workspace.getNode(Fqn.fromString("/one")).getChild("two"));
        assertEquals(oneAfter.getNode(), workspace.getNode(Fqn.fromString("/")).getChild("one"));

        assertEquals(null, dummy.getCalled());


        mgr.commit();

        assertEquals(pojo2, workspace.getNode(Fqn.fromString("/one")).get("key1"));
        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());


        assertEquals(3, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        assertEquals(3, listener.getNodesAdded());
        cache.stopService();
    }

    public void testTransactionRemoveSubNodeMethod() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor nodeInterceptor = new OptimisticNodeInterceptor();
        nodeInterceptor.setCache(cache);
        MockInterceptor dummy = new MockInterceptor();
        dummy.setCache(cache);

        interceptor.setNext(nodeInterceptor);
        nodeInterceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

//		 first set up a node with a pojo
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        Transaction tx = mgr.getTransaction();

        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx));

        SamplePojo pojo = new SamplePojo(21, "test");
        Map temp = new HashMap();
        temp.put("key1", pojo);
        cache.put("/one/two", temp);

        // get the transaction stuff
        TransactionTable table = cache.getTransactionTable();
        GlobalTransaction gtx = table.get(tx);

        OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        WorkspaceNode one = workspace.getNode(Fqn.fromString("/one"));

        assertEquals(1, ((Set) one.getMergedChildren().get(0)).size());
        assertEquals(0, ((Set) one.getMergedChildren().get(1)).size());

        cache.remove("/one/two");

        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(true, workspace.getNode(Fqn.fromString("/one/two")).isDeleted());
        assertNotNull(workspace.getNode(Fqn.fromString("/one")));
        assertEquals(false, workspace.getNode(Fqn.fromString("/one")).isDeleted());

        //will still have alink from one to two
        assertEquals(null, workspace.getNode(Fqn.fromString("/one")).getChild("two"));


        assertEquals(null, dummy.getCalled());


        mgr.commit();

        assertEquals(0, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(0)).size());
        assertEquals(1, ((Set) workspace.getNode(Fqn.fromString("/one")).getMergedChildren().get(1)).size());
        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());


        assertEquals(2, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        assertEquals(2, listener.getNodesAdded());
        cache.stopService();
    }
}
