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 org.jboss.test.JBossTestCase;


/**
 * List interface testing.
 */

public class CachedListAopTest extends TestCase
{
   Log log=LogFactory.getLog(CachedListAopTest.class);
   PojoCache cache_;
   List languages;
   List languages2;     // treat the java.util.List implementation like a reference implementation
                        // for comparison.

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

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

   public void testAddAndRemoveIndex() throws Throwable
   {
      stage();

      languages.add(1, "Taiwanese");
      assertEquals("Languages size ", 4, languages.size());
      assertEquals("Language ", (Object)"Taiwanese", (Object)languages.get(1));
      languages.remove(2);
      assertEquals("Languages size ", 3, languages.size());
      assertEquals("Language ", (Object)"English", (Object)languages.get(2));

      languages.add("Mandarin");
      assertEquals("Languages size ", 4, languages.size());
      languages.remove("Mandarin");
      assertEquals("Languages size ", 3, languages.size());
   }

   protected void stage() throws Throwable
   {
      languages = new ArrayList();
      languages.add("English");
      languages.add("French");
      languages.add("English");
      cache_.putObject("/person/test6", languages);
      languages = (List)cache_.getObject("/person/test6");
      int size = languages.size();
      assertEquals("Size of list ", 3, size);

      languages2 = new ArrayList();
      languages2.addAll(languages);
      assertEquals("New ArrayList().addAll(CachedList)",languages,languages2);
   }

   public void testAddAllAndClear() throws Throwable
   {
      stage();
      List list = new ArrayList();
      list.add("Taiwanese");
      list.add("Madarin");

      assertTrue("Language is Taiwanese ", list.contains("Taiwanese"));

      languages.addAll(list);
      assertEquals("Languages size ", 5, languages.size());

      languages.removeAll(list);
      assertEquals("Languages size ", 3, languages.size());

      assertEquals("Index of French ", 1, languages.indexOf("French"));

      languages.clear();
      assertEquals("Languages size ", 0, languages.size());

      assertTrue("Languages empty ", languages.isEmpty());
   }

   public void testEquals() throws Throwable {
      stage();

      List list = (List)cache_.getObject("/person/test6");
      assertTrue("List should be the same ", list.equals(languages));
      list = new ArrayList();
      list.add("German");
      list.add("test");
      list.add("English");
      assertFalse("List should not be the same ", languages.equals(list));
      assertFalse("List should not be the same ", list.equals(languages));
   }

   public void testIterator() throws Throwable
   {
      stage();

      Iterator it = languages.iterator();
      Iterator it2 = languages2.iterator();
      int counter = 0;
      while(it.hasNext()) {
         counter++;
         assertEquals(it.next(), it2.next());
         it.remove();
         it2.remove();
      }

      assertEquals("Size should be ", 3, counter);
      assertEquals("Skills should be empty ", 0, languages.size());
   }

   public void testListIterator() throws Throwable
   {
      stage();

      ListIterator li = languages.listIterator();
      ListIterator li2 = languages2.listIterator();
      assertFalse("LI has no previous element ", li.hasPrevious());
      assertFalse("LI2 has no previous element ", li2.hasPrevious());
      assertTrue("LI has next element ", li.hasNext());
      assertTrue("LI2 has next element ", li2.hasNext());
      assertEquals(li.next(), li2.next());
      assertEquals("Index is ", 1, li.nextIndex());
      assertEquals("Index is ", 1, li2.nextIndex());
      assertEquals("Index is ", 0, li.previousIndex());
      assertEquals("Index is ", 0, li2.previousIndex());
      assertEquals(li.next(), li2.next());
      assertEquals(li.next(), li2.next()); // the end
      try {
         li.next();
         fail("Should throw an exception here ");
      }
      catch (NoSuchElementException ex) {
         ;
      }
      try {
         li2.next();
         fail("Should throw an exception here ");
      }
      catch (NoSuchElementException ex) {
         ;
      }

      assertEquals("Index is ", 3, li.nextIndex());
      assertEquals("Index is ", 3, li2.nextIndex());
      assertEquals("Index is ", 2, li.previousIndex());
      assertEquals("Index is ", 2, li2.previousIndex());
      li.previous();
      li2.previous();
      assertEquals("Index is ", 2, li.nextIndex());
      assertEquals("Index is ", 2, li2.nextIndex());
      assertEquals("Index is ", 1, li.previousIndex());
      assertEquals("Index is ", 1, li2.previousIndex());
      li.previous();
      li2.previous();
      li.previous();
      li2.previous();

      try {
         li.previous();
         fail("Should throw an exception here ");
      }
      catch (NoSuchElementException ex) {
         ;
      }

      try {
         li2.previous();
         fail("Should throw an exception here ");
      }
      catch (NoSuchElementException ex) {
         ;
      }

      try {
         assertEquals(li.next(), li2.next());
         li.remove();
         li2.remove();
      }
      catch(Exception e) {
         fail("ListIterator.remove failed" + e);
      }


      try {
         assertEquals(li.next(), li2.next());
         li.remove();
         li2.remove();
      }
      catch(Exception e) {
         fail("ListIterator.remove failed" + e );
      }

      try {
         assertEquals(li.next(), li2.next());
         assertEquals("ListIterator.remove test problem with nextIndex, cache next index="+ li.nextIndex()+
            ", jdk next index=" + li2.nextIndex() + "cache list size = " + languages.size() + ", jdk list size = " + languages.size(),
            li.nextIndex(), li2.nextIndex());
         li2.set("German");
         li.set("German");
         String s1 = (String)li.previous();
         String s2 = (String)li2.previous();
         assertEquals(s1, s2);
         assertEquals(s2, "German");
      }
      catch(Exception e) {
         fail("ListIterator.remove failed" + e +", cache list size = " + languages.size() + ", jdk list size = " + languages.size());
      }

      try {
         assertEquals(li.next(),li2.next());
         li2.add("Vulcan");
         li.add("Vulcan");
         String s1 = (String)li.previous();
         String s2 = (String)li2.previous();
         assertEquals(s1, s2);
         assertEquals(s2, "Vulcan");
      }
      catch(Exception e) {
         fail("ListIterator.add failed" + e +", cache list size = " + languages.size() + ", jdk list size = " + languages.size());
      }

   }


   public void testAttachAndDetach() throws Exception
   {
      List list = new ArrayList();
      list.add("English");
      list.add("French");
      list.add("Taiwanese");

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

      list = (List)cache_.removeObject("/test");
      assertEquals("Size ", 3, list.size());

      System.out.println(cache_.printDetails());
      System.out.println("**** End of cache content **** ");
      list.remove(2);
      list.add("Hoklo");
      assertEquals("Size ", 3, list.size());
      assertEquals("Content ", "Hoklo", list.get(2));

      // Try to re-attach
      cache_.putObject("/test", list);
      list.remove(2);
      assertEquals("Size ", 2, list.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);

      List list = new ArrayList();
      list.add(add1);
      list.add(add2);
      list.add(add3);

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

      list = (List)cache_.removeObject("/test");
      assertEquals("Size ", 3, list.size());

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

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

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

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

}

