package org.jboss.cache.pojo.collection;

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

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * Generic Collection class support testing.
 *
 * @author Ben Wang
 */

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


   @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();
   }

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

   /**
    * Testing using LinkedList proxy.
    *
    * @throws Exception
    */
   @SuppressWarnings("unchecked")
   public void testLinkedList() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list1;
      list.add("English");
      try
      {
         cache_.attach("/aop/list", list);
         list = (LinkedList<String>) cache_.find("/aop/list");
         list.add("French");
         list1 = (LinkedList<String>) cache_.find("/aop/list");
         assertEquals("Size of list ", 2, list1.size());
      }
      catch (Exception e)
      {
         fail("pubtObject fails");
         throw e;
      }
   }

   /**
    * Testing using LinkedMap proxy.
    *
    * @throws Exception
    */
   @SuppressWarnings("unchecked")
   public void testLinkedMap() throws Exception
   {
      LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
      LinkedHashMap<String, String> map1;
      map.put("1", "English");
      try
      {
         cache_.attach("/aop/map", map);
         map = (LinkedHashMap<String, String>) cache_.find("/aop/map");
         map.put("2", "French");
         map1 = (LinkedHashMap<String, String>) cache_.find("/aop/map");
         assertEquals("Size of map ", 2, map1.size());
      }
      catch (Exception e)
      {
         fail("pubtObject fails");
         throw e;
      }
   }

   /**
    * Testing using LinkedSet proxy.
    *
    * @throws Exception
    */
   @SuppressWarnings("unchecked")
   public void testLinkedSet() throws Exception
   {
      LinkedHashSet<String> set = new LinkedHashSet<String>();
      LinkedHashSet set1;
      set.add("English");
      try
      {
         cache_.attach("/aop/set", set);
         set = (LinkedHashSet<String>) cache_.find("/aop/set");
         set.add("French");
         set1 = (LinkedHashSet) cache_.find("/aop/set");
         assertEquals("Size of set ", 2, set1.size());
      }
      catch (Exception e)
      {
         fail("pubtObject fails");
         throw e;
      }
   }

   // tests for each of the methods in Collection interface
   @SuppressWarnings({ "unchecked", "unchecked" })
   public void testSize() throws Exception
   {

      LinkedList<String> list = new LinkedList<String>();
      list.add("java");
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertEquals("size of collection", 1, list.size());
         list.add("c");
         list.add("lisp");
         assertEquals("size of collection", 3, list.size());
         list.remove("lisp");
         assertEquals("size of collection", 2, list.size());
         list.remove("c");
         assertEquals("size of collection", 1, list.size());
         list.clear();
         assertEquals("size of collection", 0, list.size());
      }
      catch (Exception e)
      {
         fail("testSize " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testIsEmpty() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue("collection is empty", list.isEmpty());
         list.add("c");
         list.add("lisp");
         assertFalse("collection is not empty", list.isEmpty());
         list.remove("lisp");
         assertFalse("collection is not empty", list.isEmpty());
         list.remove("c");
         assertTrue("collection is empty", list.isEmpty());
      }
      catch (Exception e)
      {
         fail("testIsEmpty " + e.getMessage());
         throw e;
      }
   }

   @SuppressWarnings("unchecked")
   public void testContains() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      list.add("java");
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertFalse("collection doesn't contains", list.contains("lisp"));
         list.add("c");
         list.add("lisp");
         assertTrue("collection contains", list.contains("lisp"));
         list.remove("lisp");
         assertFalse("collection doesn't contain", list.contains("lisp"));
         list.remove("c");
         list.clear();
         assertFalse("collection doesn't contains", list.contains("c"));
      }
      catch (Exception e)
      {
         fail("testContains " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testIterator() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         list.addAll(list2);
         for (Object o : list) assertTrue("Iteration test", list2.contains(o));
      }
      catch (Exception e)
      {
         fail("testIterator " + e.getMessage());
         throw e;
      }
   }

   @SuppressWarnings("unchecked")
   public void testToArray() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");
      list.addAll(list2);
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         Object[] values = list.toArray();

         for (int looper = 0; looper < values.length; looper++)
         {
            assertTrue("toArray test", list2.contains(values[looper]));
         }

         values = new Object[1];
         values = list.toArray(values);  // test with too small of an array
         for (int looper = 0; looper < values.length; looper++)
         {
            assertTrue("toArray test", list2.contains(values[looper]));
         }

         values = new Object[10];
         values = list.toArray(values);  // test with too large of an array, result should be null padded
         for (int looper = 0; looper < values.length; looper++)
         {
            assertTrue("toArray test", (values[looper] == null || list2.contains(values[looper])));
         }

      }
      catch (Exception e)
      {
         fail("testToArray " + e.getMessage());
         throw e;
      }
   }

   @SuppressWarnings("unchecked")
   public void testAdd() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         list.add("java");
         assertTrue("add test", list.contains("java"));
         assertFalse("add test", list.contains("c#"));
      }
      catch (Exception e)
      {
         fail("testAdd " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testRemove() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         list.add("java");
         assertTrue(list.remove("java"));
         assertFalse("remove test", list.contains("java"));
      }
      catch (Exception e)
      {
         fail("testRemove " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testAddAll() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue(list.addAll(list2));
         Object[] values = list.toArray();

         for (int looper = 0; looper < values.length; looper++)
         {
            assertTrue("testAddAll", list2.contains(values[looper]));
         }
      }
      catch (Exception e)
      {
         fail("testAddAll " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testClear() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue(list.addAll(list2));
         assertTrue("testClear", list.size() > 0);
         list.clear();
         assertTrue("testClear", list.size() == 0);
      }
      catch (Exception e)
      {
         fail("testClear " + e.getMessage());
         throw e;
      }

   }

   @SuppressWarnings("unchecked")
   public void testRetainAll() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue(list.addAll(list2));
         list2.remove("c");
         list2.remove("lisp");
         list2.remove("c++");
         list2.remove("forth");
         assertTrue("testRetainAll", list.retainAll(list2));
         // should only have java left
         assertTrue("testRetainAll, list size should be 1 but is " + list.size(), list.size() == 1);
         assertTrue("testRetainAll", list.contains("java"));
      }
      catch (Exception e)
      {
         fail("testRetainAll " + e.getMessage());
         throw e;
      }


   }

   @SuppressWarnings({ "unchecked", "unchecked" })
   public void testRemoveAll() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue(list.addAll(list2));
         list2.remove("java");
         assertTrue("testRemoveAll", list.removeAll(list2));
         // should only have java left
         assertTrue("testRemoveAll", list.size() == 1);
         assertTrue("testRemoveAll", list.contains("java"));
      }

      catch (Exception e)
      {
         fail("testRemoveAll " + e.getMessage());
         throw e;
      }


   }

   @SuppressWarnings("unchecked")
   public void testContainsAll() throws Exception
   {
      LinkedList<String> list = new LinkedList<String>();
      LinkedList<String> list2 = new LinkedList<String>();
      list2.add("java");
      list2.add("c");
      list2.add("lisp");
      list2.add("c++");
      list2.add("forth");

      try
      {
         cache_.attach("/language/list", list);
         list = (LinkedList<String>) cache_.find("/language/list");
         assertTrue(list.addAll(list2));
         list2.remove("java");
         assertTrue("testContainsAll", list.containsAll(list2));
         list.remove("c");
         assertFalse("testContainsAll", list.containsAll(list2));
      }
      catch (Exception e)
      {
         fail("testContainsAll " + e.getMessage());
         throw e;
      }
   }

}

