package org.jboss.cache.aop.collection;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.aop.test.Address;
import org.jboss.cache.PropertyConfigurator;

import java.util.*;
import java.io.StringWriter;
import java.io.PrintWriter;

//import org.jboss.test.JBossTestCase;


/**
 * Set interface testing.
 */

public class CachedSetAopTest extends TestCase
{
   Log log=LogFactory.getLog(CachedSetAopTest.class);
   PojoCache cache_;
   Set skills;

   public CachedSetAopTest(String name)
   {
      super(name);
   }

   protected void setUp() throws Exception
   {
      super.setUp();
      log.info("setUp() ....");
      String configFile = "META-INF/local-service.xml";
      cache_ = new PojoCache();
      PropertyConfigurator config = new PropertyConfigurator();
      config.configure(cache_, configFile); // read in generic replSync xml
      cache_.start();

      stage();
   }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      cache_.stop();
   }

   protected void stage() throws Exception
   {
      skills = new HashSet();
      skills.add("Java");
      skills.add("C++");
      skills.add("Perl");

      cache_.putObject("/person/test7", skills);
      skills = (Set)cache_.getObject("/person/test7");
      int size = skills.size();
      assertEquals("Size is ", 3, size);
   }

   public void testClear() throws Throwable
   {
      int size = skills.size();
      assertEquals("Size is ", 3, size);

      System.out.println(cache_.printDetails());
      skills.clear();
      size = skills.size();
      assertEquals("Size is ", 0, size);

      assertTrue("Should be empty", skills.isEmpty());
   }

   public void testAddAndRemoveIndex() throws Throwable
   {
      skills.add("Golf");
      int size = skills.size();
      assertEquals("Size is ", 4, size);

      skills.add("Golf");
      size = skills.size();
      assertEquals("Size is ", 4, size);

      assertTrue("Skill shuold contain Golf ", skills.contains("Golf"));
      skills.remove("C++");
      size = skills.size();
      assertEquals("Size is ", 3, size);
      assertFalse("Skill does not contain C++ anymore ", skills.contains("C++"));

      skills.add("Golf");
      size = skills.size();
      assertEquals("Size is ", 3, size);
      System.out.println(cache_.printDetails());
      skills.clear();
      size = skills.size();
      assertEquals("Size is ", 0, size);

      assertTrue("Should be empty", skills.isEmpty());
   }

   public void testAddAndRemoveAll() throws Throwable
   {
      List list = new ArrayList();
      list.add("Tennis");
      list.add("Polo");
      list.add("Baseball");

      skills.addAll((Collection)list);
      int size = skills.size();
      assertEquals("Size is ", 6, size);
      assertTrue("Skill contains Polo ", skills.contains("Polo"));

      skills.removeAll((Collection)list);
      size = skills.size();
      assertEquals("Size is ", 3, size);
      assertFalse("Skill does not contain Polo ", skills.contains("Polo"));
      assertTrue("Skill contains C++ ", skills.contains("C++"));

   }
   
   public void testRemoveAndAdd()
   {
      assertTrue(skills.remove("C++"));
      assertTrue(skills.add("C++"));
      assertEquals("removeAndAdd: size is 3", 3, skills.size());
   }

   public void testIterator() {
      Iterator it = skills.iterator();
      int counter = 0;
      while(it.hasNext()) {
         counter++;
         it.next();
         it.remove();
      }

      assertEquals("iterator: Size should be ", 3, counter);
      assertEquals("iterator: Skills should be empty ", 0, skills.size());

      List list = new ArrayList();
      list.add("Tennis");
      list.add("Polo");
      list.add("Baseball");
      list.add("Soccer");
      list.add("Hockey");
      list.add("Lacrosse");
      skills.addAll(list);
      it = skills.iterator();
      while(it.hasNext()) {
         counter++;
         if("Polo".equals(it.next())) {
            it.remove();
         }
      }
      assertFalse("iterator: item removed via iterator", skills.contains("Polo"));
      assertTrue("iterator: item not removed via iterator", skills.contains("Lacrosse"));
      
      // Check for proper relationship between hasNext and next
      list = new ArrayList();
      list.add("Tennis");
      list.add("Polo");
      list.add("Baseball");
      skills.addAll(list);
      it = skills.iterator();
      while(it.hasNext()) {
         it.next();
      }
      try
      {
         it.next();
         fail("iterator: Didn't fail on next() when hasNext() == false");
      }
      catch (NoSuchElementException good) {}
      
      // Check for proper relationship between next and remove
      it = skills.iterator();
      try
      {
         it.remove();
      }
      catch (IllegalStateException good) 
      {
         // behaves correctly per Iterator contract
      }
      catch (Exception e)
      {
         StringWriter stackTrace = new StringWriter();
         e.printStackTrace(new PrintWriter(stackTrace));
         fail("iterator: failed with incorrect exception type when removing " +
               "without first calling next() -- " + e.getClass().getName() + ".  stackTrace=" + stackTrace);
      }
      

   }

   public void testEquals() throws Throwable {
      Set set = (Set)cache_.getObject("/person/test7");
      assertTrue("iterator: List should be the same ", set.equals(skills));
      set = new HashSet();
      set.add("German");
      set.add("test");
      set.add("English");
      assertFalse("List should not be the same ", set.equals(skills));
      assertFalse("List should not be the same ", skills.equals(set));
   }


   public void testAttachAndDetach() throws Exception
   {
      Set set = new HashSet();
      set.add("English");
      set.add("French");
      set.add("Taiwanese");

      cache_.putObject("/test", set); // attach
      set = (Set)cache_.getObject("/test");
      assertEquals("Size ", 3, set.size());

      set = (Set)cache_.removeObject("/test");
      assertEquals("Size ", 3, set.size());

      System.out.println(cache_.printDetails());
      System.out.println("**** End of cache content **** ");
      set.remove("French");
      set.add("Hoklo");
      assertEquals("Size ", 3, set.size());
      assertTrue("Content ", set.contains("Hoklo"));

      // Try to re-attach
      cache_.putObject("/test", set);
      set.remove("Taiwanese");
      assertEquals("Size ", 2, set.size());
      System.out.println(cache_.printDetails());
   }

   public void testPojoAttachAndDetach() throws Exception
   {
      Address add1 = new Address();
      add1.setCity("San Jose");
      add1.setZip(95123);

      Address add2 = new Address();
      add2.setCity("Sunnyvale");
      add2.setZip(94086);

      Address add3 = new Address();
      add3.setCity("Santa Clara");
      add3.setZip(951131);

      Set set = new HashSet();
      set.add(add1);
      set.add(add2);
      set.add(add3);

      cache_.putObject("/test", set); // attach
      set = (Set)cache_.getObject("/test");
      assertEquals("Size ", 3, set.size());

      set = (Set)cache_.removeObject("/test");
      assertEquals("Size ", 3, set.size());

      System.out.println(cache_.printDetails());
      System.out.println("**** End of cache content **** ");
      set.remove(add2);
      set.add(add2);
      assertEquals("Size ", 3, set.size());
      assertTrue("Content ", set.contains(add2));

      // Try to re-attach
      cache_.putObject("/test", set);
      set.remove(add2);
      assertEquals("Size ", 2, set.size());
      System.out.println(cache_.printDetails());
   }

   public void  testToArray() throws Exception
   {
      Object[] arr = skills.toArray();
      assertEquals("toArray: array length is correct", 3, arr.length);
      testLanguagesFound(arr);
      
      Object[] arr1 = skills.toArray(arr);
      assertTrue("toArray: arrays match", Arrays.equals(arr, arr1));

      arr = new Object[5];
      arr = skills.toArray(arr);
      assertEquals("toArray: array length is correct", 5, arr.length);
      testLanguagesFound(arr);
      assertEquals(null, arr[3]);
      assertEquals(null, arr[4]);

      arr = new Object[2];
      arr = skills.toArray(arr);
      assertEquals("toArray: array length is correct", 3, arr.length);
      testLanguagesFound(arr);

   }
   
   private void testLanguagesFound(Object[] arr)
   {
      boolean[] found = new boolean[3];
      for (int i = 0; i < arr.length; i++)
      {
         if ("Java".equals(arr[i]))
            found[0] = true;
         else if ("C++".equals(arr[i]))
            found[1] = true;
         else if ("Perl".equals(arr[i]))
            found[2] = true;
      }
      assertTrue("toArray: all elements found", found[0] && found[1] && found[2]);
      
   }

   public void testRetainAll() throws Exception
   {
      LinkedList list2 = new LinkedList();
      list2.add("Java");

      assertTrue("testRetainAll", skills.retainAll(list2) );
      // should only have Java left
      assertTrue("testRetainAll, skills size should be 1 but is " + skills.size(), skills.size() == 1);
      assertTrue("testRetainAll", skills.contains("Java"));

   }

   public void testContainsAll() throws Exception
   {
      LinkedList list2 = new LinkedList();
      list2.add("Java");
      list2.add("C++");
      list2.add("Perl");

      skills.clear();

      assertTrue(skills.addAll(list2));
      list2.remove("Java");
      assertTrue("testContainsAll", skills.containsAll(list2) );
      skills.remove("C++");
      assertFalse("testContainsAll", skills.containsAll(list2) );
   }

   public static Test suite() throws Exception
   {
      return new TestSuite(CachedSetAopTest.class);
   }

   public static void main(String[] args) throws Exception
   {
      junit.textui.TestRunner.run(suite());
   }


}

