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

package org.jboss.cache.pojo.rollback;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;

import java.util.HashMap;
import java.util.Map;

import javax.transaction.TransactionManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.proxy.ClassProxy;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
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 MapTxUndoTest
{
   Log log_ = LogFactory.getLog(MapTxUndoTest.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 testSimple() throws Exception
   {
      HashMap<String, String> map = new HashMap<String, String>();
      map.put("1", "test1");

      tx_mgr.begin();
      cache_.attach("/a", map);
      tx_mgr.rollback();
      assertFalse("Should not have cache interceptor ", isProxy(map));

      cache_.attach("/a", map);
   }

   public void testSimpleTxWithRollback1() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      HashMap<String, String> map = new HashMap<String, String>();
      map.put("1", "English");
      test.setHobbies(map);

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

      cache_.attach("/a", test);
   }

   private boolean isProxy(Object pojo)
   {
      if (pojo instanceof ClassProxy) return true;
      return false;
   }

   public void testSimpleTxWithRollback2() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      HashMap<String, String> map = new HashMap<String, String>();
      map.put("1", "English");
      test.setHobbies(map);

      cache_.attach("/a", test);

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

      assertTrue("Should still have cache interceptor ", isProxy(test.getHobbies()));
      cache_.detach("/a");
   }

   public void testSimpleTxWithRollback3() throws Exception
   {
      log_.info("testSimpleTxWithRollback1() ....");
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      HashMap<String, String> map = new HashMap<String, String>();
      map.put("1", "English");
      test.setHobbies(map);
      tx_mgr.begin();
      cache_.attach("/a", test);
      cache_.detach("/a");
      tx_mgr.rollback();

      assertFalse("Should not have cache interceptor ", isProxy(test.getHobbies()));
   }

   /**
    * Contributed by Niztan Niv
    *
    * @throws Exception
    */
   @SuppressWarnings("unchecked")
   public void testNestedMapWithRollback() throws Exception
   {
      // create cached data objects
      Map<String, String> obj1 = new HashMap<String, String>();
      obj1.put("id", "1");
      cache_.attach("objs/1", obj1);
      obj1 = (Map<String, String>) cache_.find("objs/1");

      Map<String, String> obj2 = new HashMap<String, String>();
      obj2.put("id", "2");
      cache_.attach("objs/2", obj2);
      obj2 = (Map<String, String>) cache_.find("objs/2");

      // create cached collection of data objects
      Map<String, Map<String, String>> indexMap = new HashMap<String, Map<String, String>>();
      cache_.attach("objsIndex", indexMap);
      indexMap = (Map<String, Map<String, String>>) cache_.find("objsIndex");

      // initialize collection by adding a data object
      final String KEY = "KEY";
      indexMap.put(KEY, obj1);

      Object beforeModify = indexMap.get(KEY);
      System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map) beforeModify).get("id"));

      // modify the collection by replacing the first data object with the second
      // and then roll-back the transaction
      tx_mgr.begin();
      indexMap.put(KEY, obj2);
      tx_mgr.rollback();

      Object afterRollback = indexMap.get(KEY);
      System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map) afterRollback).get("id"));

      // check if state of collection was restored
      assertEquals(beforeModify, afterRollback);
   }

   @SuppressWarnings("unchecked")
   public void testPlainMapRollback() throws Exception
   {
      // create cached data objects
      Map<String, String> obj1 = new HashMap<String, String>();
      obj1.put("id", "1");
      cache_.attach("objs/1", obj1);
      obj1 = (Map<String, String>) cache_.find("objs/1");

      tx_mgr.begin();
      obj1.put("id", "newId");
      tx_mgr.rollback();

      assertEquals("1", obj1.get("id"));
   }




}
