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;

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


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

    public void testTransactionGetKeyMethod() 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");

        cache.put("/one/two", "key1", pojo);

        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

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

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        //assert we can see this with a key value get in the transaction
        assertEquals(pojo, cache.get("/one/two", "key1"));
        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(1, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());

        //assert that we cannot see the change if we have not put it into the cache
        // we need to do this as we do not have the tx interceptor in this stack
        mgr.begin();

        Transaction tx2 = mgr.getTransaction();

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

        assertNull(cache.get("/one/two", "key1"));
        mgr.commit();
        cache.stopService();
    }

    public void testTransactionGetKeyValOverwriteMethod() 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");

        cache.put("/one/two", "key1", pojo);

        //overwrite the map we just put in
        SamplePojo pojo2 = new SamplePojo(22, "test2");

        cache.put("/one/two", "key1", pojo2);

        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

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

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();
        assertEquals(pojo2, cache.get("/one/two", "key1"));
        mgr.commit();

        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(pojo2, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(2, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());

        cache.stopService();
    }

    public void testTransactionGetKeyValOverwriteNullMethod() 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");

        cache.put("/one/two", "key1", pojo);


        cache.put("/one/two", "key1", null);

        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();

        GlobalTransaction gtx = table.get(tx);

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

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        assertEquals(null, cache.get("/one/two", "key1"));

        mgr.commit();
        //assert what should be the results of our call
        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(null, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(2, entry.getModifications().size());
        assertTrue(!cache.exists("/one/two"));
        assertEquals(null, dummy.getCalled());
        cache.stopService();
    }


    public void testTwoTransactionGetIsolationKeyValMethod() 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");

        cache.put("/one/two", "key1", pojo);

        assertEquals(pojo, cache.get("/one/two", "key1"));
        //suspend current transaction
        mgr.suspend();

        //start a new transaction
        mgr.begin();
        Transaction tx2 = mgr.getTransaction();
        // inject InvocationContext
        cache.getInvocationContext().setTransaction(tx2);
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx2));

        SamplePojo pojo2 = new SamplePojo(22, "test2");

        cache.put("/one/two", "key2", pojo2);
        assertEquals(null, cache.get("/one/two", "key1"));
        assertEquals(pojo2, cache.get("/one/two", "key2"));


        assertEquals(null, dummy.getCalled());
        TransactionTable table = cache.getTransactionTable();


        GlobalTransaction gtx = table.get(tx);

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

        TransactionWorkspace workspace = entry.getTransactionWorkSpace();

        //resume the suspended transaction
        GlobalTransaction gtx2 = table.get(tx2);

        OptimisticTransactionEntry entry2 = (OptimisticTransactionEntry) table.get(gtx2);

        TransactionWorkspace workspace2 = entry2.getTransactionWorkSpace();

        //commit both tx
        mgr.commit();
        mgr.resume(tx);
        mgr.commit();

        //assert that our keys are in one space
        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertEquals(null, workspace.getNode(Fqn.fromString("/one/two")).get("key2"));
        assertTrue(entry.getLocks().isEmpty());
        assertEquals(1, entry.getModifications().size());

        //assert that our keys are in one space
        assertEquals(3, workspace2.getNodes().size());
        assertNotNull(workspace2.getNode(Fqn.fromString("/one/two")));
        assertEquals(null, workspace2.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertEquals(pojo2, workspace2.getNode(Fqn.fromString("/one/two")).get("key2"));
        assertTrue(entry2.getLocks().isEmpty());
        assertEquals(1, entry2.getModifications().size());

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


}
