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.aop.test.Person;
import org.jboss.cache.PropertyConfigurator;

import java.util.*;

/**
 * Test object graph handling in aop, e.g., circular reference, multiple reference, link, etc.
 * @author Ben Wang  
 */

public class ReplicatedSyncSetTest extends TestCase
{
   Log log=LogFactory.getLog(ReplicatedSyncSetTest.class);
   PojoCache cache1;
   PojoCache cache2;

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

   protected void setUp() throws Exception
   {
      super.setUp();
      log.info("setUp() ....");
      cache1 = createCache("CacheGroup");
      cache2 = createCache("CacheGroup");
   }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      cache1.remove("/");
      cache1.stop();
      cache2.stop();
   }

   private PojoCache createCache(String name) throws Exception {
      PojoCache tree=new PojoCache();
      PropertyConfigurator config=new PropertyConfigurator();
      config.configure(tree, "META-INF/replSync-service.xml"); // read in generic replAsync xml
      tree.setClusterName(name);
      tree.createService();
      tree.startService();
      return tree;
   }

//   public void testDummy() {}


   protected Person createPerson(String name, int age)
   {
      Person p = new Person();
      p.setName(name);
      p.setAge(age);
      return p;
   }

   /**
    * Test attachment and then detachment and attachment.
    * @throws Exception
    */
   public void testAttachDetach() throws Exception
   {
      log.info("testAttachDetach() ....");
      Set set1 = new HashSet();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      set1.add(addr);

      Address addr2 = new Address();
      addr2.setCity("Santa Clara");
      addr2.setZip(95131);

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

      // Pure list
      cache1.putObject("/set", set1);
      set1 = (Set)cache1.getObject("/set");
      set1.add(addr2);
      cache1.removeObject("/set");
      assertEquals("Detached set should still be", 2, set1.size());
      set1.add(addr3);
      cache1.putObject("/set", set1);

      Set set2 = (Set)cache2.getObject("/set");
      assertEquals("Set size should be ", 3, set2.size());
   }

   public void testRelationshipWithSharedSet1() throws Exception
   {
      log.info("testRelationshipWithSet() ....");
      Set set1 = new HashSet();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      set1.add(addr);

      // Pure set
      cache1.putObject("/set", set1);
      // We specifically need to use Proxy otherwise it won't work with multiple references
      set1 = (Set)cache1.getObject("/set");
      cache1.putObject("/alias", set1);

      Set set2 = (Set)cache1.getObject("/alias");
      Address add1 = (Address)set2.iterator().next();
      assertNotNull("Address should not be null", add1);
      assertEquals("Zip ", 95123, add1.getZip());

      set1 = (Set)cache2.getObject("/set");
      set2 = (Set)cache2.getObject("/alias");
      assertTrue("Set size should not be 0 ", (set2.size() != 0));
      assertEquals("Both sets should be equal ", set1, set2);
      add1 = (Address)set2.iterator().next();
      assertNotNull("Address should not be null", add1);
      assertEquals("Zip ", 95123, add1.getZip());
   }

   public void testRelationshipWithSharedSet2() throws Exception
   {
      log.info("testRelationshipWithSet2() ....");
      Set set1 = new HashSet();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      set1.add(addr);

      Set set2 = new HashSet();
      set2.add(addr);

      cache1.putObject("/set1", set1);
      cache1.putObject("/set2", set2);
      Address add2 = (Address)((Set)cache2.getObject("/set2")).iterator().next();
      Address add1 = (Address)((Set)cache2.getObject("/set1")).iterator().next();
      assertEquals("Address should be the same", add1, add2);
      assertEquals("Both shared object should be equal ", add2.getZip(), add1.getZip());
   }

   public void testNullWithSharedSet1() throws Exception
   {
      log.info("testNullWithSharedSet1() ....");
      Set set1 = new HashSet();
      set1.add("element 0");
      set1.add(null);  // element 1
      set1.add("element 2");
      assertTrue("contains test for null value", set1.contains(null));
      Object a1[] = set1.toArray();
      for(int looper =0; looper < a1.length; looper++){
         System.out.println("contained values:" + a1[looper]);
      }

      // Pure set
      cache1.putObject("/set", set1);
      // We specifically need to use Proxy otherwise it won't work with multiple references
      set1 = (Set)cache1.getObject("/set");
      cache1.putObject("/alias", set1);

      Set set2 = (Set)cache1.getObject("/alias");

      set1 = (Set)cache2.getObject("/set");
      set2 =  (Set)cache2.getObject("/alias");
      assertTrue("Set size should not be 0 ", (set2.size() != 0));
      assertEquals("Both sets should be equal ", set1, set2);

      a1 = set1.toArray();
      for(int looper =0; looper < a1.length; looper++){
         System.out.println("contained values:" + a1[looper]);
      }
      assertTrue("contains test for null value", set1.contains(null));
      assertTrue("contains test for null value", set2.contains(null));

      Iterator iter = set1.iterator();
      while(iter.hasNext()) {
         Object val = iter.next();
         if("element 2".equals(val)) {
            iter.remove();  // remove element 2
         }
      }
      assertFalse("element 2 is removed", set2.contains("element 2"));
   }

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

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

}

