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 ObjectGraphAopTest extends TestCase
{
   Log log=LogFactory.getLog(ObjectGraphAopTest.class);
   PojoCache cache_;

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

   protected void setUp() throws Exception
   {
      super.setUp();
      log.info("setUp() ....");
//      String configFile = "META-INF/local-service.xml";
      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 testDummy() {}

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


   public void testListWithMultipleSharedObjccts() throws Exception
   {
      log.info("testListWithMultipleSharedObjects() ....");
      List list1 = new ArrayList();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      list1.add(addr);

      List list2 = new ArrayList();
      List list3 = new ArrayList();
      list2.add(addr);
      list3.add(addr);

      cache_.putObject("/list1", list1);
      cache_.putObject("/list2", list2);
      cache_.putObject("/list3", list3);

      list3 = (List)cache_.getObject("/list3");
      assertTrue("List size should not be 0 ", (list3.size() != 0));
      assertEquals("Address ", addr.getZip(), ((Address)list3.get(0)).getZip());
      addr.setCity("Sunnyvale");
      assertEquals("Address ", addr.getCity(), ((Address)list3.get(0)).getCity());

      cache_.removeObject("/list1");
      cache_.removeObject("/list2");
      cache_.removeObject("/list3");
   }

   public void testRelationshipWithSharedList1() throws Exception
   {
      log.info("testRelationshipWithList() ....");
      List list1 = new ArrayList();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      list1.add(addr);

      cache_.putObject("/list", list1);
      list1 = (List)cache_.getObject("/list");
      assertEquals("List size should be ", 1, list1.size());
      cache_.putObject("/alias", list1);

      list1 = (List)cache_.getObject("/list");
      assertEquals("List size should be ", 1, list1.size());
      List list2 = (List)cache_.getObject("/alias");
//      System.out.println(cache_.printDetails());
      assertEquals("List size should be ", 1, list2.size());
      assertEquals("Both lists should be equal ", list1, list2);
      assertEquals("Both list values should be equal ", list1.get(0), list2.get(0));
   }

   public void testRelationshipWithSharedList2() throws Exception
   {
      log.info("testRelationshipWithList2() ....");
      List list1 = new ArrayList();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      list1.add(addr);

      List list2 = new ArrayList();
      list2.add(addr);

      cache_.putObject("/list1", list1);
      cache_.putObject("/list2", list2);
      Address add2 = (Address)((List)cache_.getObject("/list2")).get(0);
      Address add1 = (Address)((List)cache_.getObject("/list1")).get(0);
      assertEquals("Address should be the same", add1, add2);
      assertEquals("Both shared object should be equal ", add2.getZip(), add1.getZip());
   }

   public void testListWithAttachAndDetach() throws Exception
   {
      log.info("testListWithAttachAndDetach() ....");
      List list1 = new ArrayList();
      Address addr1 = new Address();
      addr1.setCity("San Jose");
      addr1.setZip(95123);

      Address addr2 = new Address();
      addr2.setCity("Sunnyvale");
      addr2.setZip(94086);
      list1.add(addr2);

      cache_.putObject("/list", list1);
      list1 = (List)cache_.getObject("/list");
      assertEquals("List size should be ", 1, list1.size());
      cache_.putObject("/alias", list1);

      list1 = (List)cache_.getObject("/list");
      assertEquals("List size should be ", 1, list1.size());
      List list2 = (List)cache_.getObject("/alias");
//      System.out.println(cache_.printDetails());
      assertEquals("List size should be ", 1, list2.size());
      assertEquals("Both lists should be equal ", list1, list2);
      assertEquals("Both list values should be equal ", list1.get(0), list2.get(0));
   }

   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
      cache_.putObject("/set", set1);
      // We specifically need to use Proxy otherwise it won't work with multiple references
      set1 = (Set)cache_.getObject("/set");
      cache_.putObject("/alias", set1);

      set1 = (Set)cache_.getObject("/set");
      Set set2 = (Set)cache_.getObject("/alias");
      assertTrue("Set size should not be 0 ", (set2.size() != 0));
      assertEquals("Both sets should be equal ", set1, set2);
      Address 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);

      cache_.putObject("/set1", set1);
      cache_.putObject("/set2", set2);

      Address add2 = (Address)((Set)cache_.getObject("/set2")).iterator().next();
      Address add1 = (Address)((Set)cache_.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 testRelationshipWithSharedMap1() throws Exception
   {
      log.info("testRelationshipWithMap() ....");
      Map map1 = new HashMap();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      map1.put("key1", addr);

      cache_.putObject("/map", map1);
      cache_.putObject("/alias", map1);

      map1 = (Map)cache_.getObject("/map");
      Map map2 = (Map)cache_.getObject("/alias");
      assertTrue("Map size should not be 0 ", (map2.size() != 0));
      assertEquals("Both maps should be equal ", map1, map2);
      Address add1 = (Address)((Map.Entry)map2.entrySet().iterator().next()).getValue();
      assertNotNull("Address should not be null", add1);
      assertEquals("Zip ", 95123, add1.getZip());
   }

   public void testRelationshipWithSharedMap2() throws Exception
   {
      log.info("testRelationshipWithMap2() ....");
      Map map1 = new HashMap();
      Address addr = new Address();
      addr.setCity("San Jose");
      addr.setZip(95123);
      map1.put("key1", addr);

      Map map2 = new HashMap();
      map2.put("key2", addr);

      // Pure map
      cache_.putObject("/map", map1);
      cache_.putObject("/alias", map2);

      map1 = (Map)cache_.getObject("/map");
      map2 = (Map)cache_.getObject("/alias");
      assertTrue("Map size should not be 0 ", (map2.size() != 0));
      Address add1 = (Address)((Map.Entry)map2.entrySet().iterator().next()).getValue();
      assertNotNull("Address should not be null", add1);
      assertEquals("Zip ", 95123, add1.getZip());
   }


   public void testObjectIdentity() throws Exception
   {
   }

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

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

}

