/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.pojo;

import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertNull;

import java.util.ArrayList;
import java.util.List;

import javax.transaction.TransactionManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.Advised;
import org.jboss.aop.advice.Interceptor;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.test.ArrayObject;
import org.jboss.cache.pojo.test.Person;
import org.jboss.cache.transaction.DummyTransactionManager;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * Additional basic tests
 *
 * @author Ben Wang
 */

@Test(groups = {"functional"})
public class TxUndoTest
{
   Log log_ = LogFactory.getLog(TxUndoTest.class);
   PojoCache cache_;
   TransactionManager tx_mgr;


   @BeforeMethod(alwaysRun = true)
   protected void setUp() throws Exception
   {
      log_.info("setUp() ....");
      String configFile = "META-INF/local-service.xml";
      boolean toStart = false;
      cache_ = PojoCacheFactory.createCache(configFile, toStart);
      cache_.start();
      tx_mgr = DummyTransactionManager.getInstance();

   }

   @AfterMethod(alwaysRun = true)
   protected void tearDown() throws Exception
   {
      cache_.stop();
   }

//   public void testDummy() {}

   public void testSimpleTxWithRollback1() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);

      tx_mgr.begin();
      cache_.attach("/a", test);
      tx_mgr.rollback();
      assertFalse("Should not have cache interceptor ", hasCacheInterceptor(test));
   }

   private boolean hasCacheInterceptor(Object pojo)
   {
      Interceptor[] interceptors = null;
      try
      {
         interceptors = ((Advised) pojo)._getInstanceAdvisor().getInterceptors();
      }
      catch (Exception ex)
      {
         return false;
      }

      for (int i = 0; i < interceptors.length; i++)
      {
         if (interceptors[i] instanceof CacheFieldInterceptor)
            return true;
      }
      return false;
   }

   public void testSimpleTxWithRollback2() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      cache_.attach("/a", test);

      tx_mgr.begin();
      cache_.detach("/a");
      tx_mgr.rollback();

      assertTrue("Should still have cache interceptor ", hasCacheInterceptor(test));
   }

   public void testSimpleTxWithRollback3() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      tx_mgr.begin();
      cache_.attach("/a", test);
      cache_.detach("/a");
      tx_mgr.rollback();

      assertFalse("Should not have cache interceptor ", hasCacheInterceptor(test));
   }

   public void testCollectionRollback() throws Exception
   {
      Person test = new Person();
      test.setName("Ben");
      List<String> languages = new ArrayList<String>();
      languages.add("English");
      languages.add("French");
      test.setLanguages(languages);
      cache_.attach("/a", test);

      tx_mgr.begin();
      cache_.detach("/a");
      tx_mgr.rollback();
      languages = test.getLanguages();
      tx_mgr.begin();
      languages.add("temp");
      tx_mgr.rollback();
      assertFalse("Languages is not attached", languages.contains("temp"));
      assertTrue(languages.contains("English"));
      assertTrue(languages.contains("French"));
    }

   public void testArrayRollback() throws Exception
   {
      ArrayObject test = new ArrayObject();
      ArrayObject.Person bob = new ArrayObject.Person("bob");
      ArrayObject.Person david = new ArrayObject.Person("david");
      test.setPerson(0, bob);
      test.setPerson(1, david);
      cache_.attach("/a", test);

      tx_mgr.begin();
      cache_.detach("/a");
      tx_mgr.rollback();

      tx_mgr.begin();
      test.setPerson(2, bob);
      assertSame(bob, test.getPerson(2));
      tx_mgr.rollback();
      assertNull("Array is not attached", test.getPerson(2));
      assertSame(bob, test.getPerson(0));
      assertSame(david, test.getPerson(1));
    }
}
