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.aop.proxy.ClassProxy;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.aop.test.Address;

import java.util.*;

//import org.jboss.test.JBossTestCase;


/**
 * Set interface testing.
 * @author Scott Marlow
 */

public class CachedMapAopNullTest extends TestCase
{
   Log log=LogFactory.getLog(CachedMapAopNullTest.class);
   PojoCache cache_;
   Map hobbies;

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

   static final int NUMBER_OF_STAGED_HOBBIES = 5;
   protected void stage() throws Exception
   {
      hobbies = new HashMap();
      hobbies.put( "1", "golf");
      hobbies.put("2", "tennis");
      hobbies.put("3", "polo");
      hobbies.put(null,"Non-null value but the key is null");
      hobbies.put("key is non-null but value is null", null);

      cache_.putObject("/person/test7", hobbies);
      hobbies = (Map)cache_.getObject("/person/test7");
      assertEquals("Map size", NUMBER_OF_STAGED_HOBBIES, hobbies.size());

      if( !(hobbies instanceof ClassProxy || hobbies instanceof Map) ) {
         fail("testPut(): hobbies is not instance of ClassProxy nor Map");
      }
   }

   /**
    * Test simple put
    * @throws Throwable
    */
   public void testPut() throws Throwable {
      int size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES, size);

      hobbies.put("6", "baseball");
      size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES + 1, size);

   }

   public void testAddAndRemoveIndex() throws Throwable
   {
      hobbies.put("4", "baseball");
      int size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES +1, size);

      assertTrue("Skill contain Golf ", hobbies.containsKey("3"));

      hobbies.remove("3");
      size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES, size);
      assertFalse("Skill does not contain "+NUMBER_OF_STAGED_HOBBIES+" anymore ", hobbies.containsKey("3"));

      assertTrue("search for null key returned non-null value " + hobbies.get(null) ,hobbies.get(null) != null);

      hobbies.remove(null);
      size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES-1, size);
      assertFalse("Skill does not contain "+(NUMBER_OF_STAGED_HOBBIES-1)+" ", hobbies.containsKey(null));

      hobbies.clear();
      size = hobbies.size();
      assertEquals("Size is ", 0, size);

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

   public void testPutAllEtc() throws Throwable {
      Map map = new HashMap();
      map.put("4", "pingpong");
      map.put("5", "handball");

      hobbies.putAll(map);
      int size = hobbies.size();
      assertEquals("Size is ", NUMBER_OF_STAGED_HOBBIES+2, size);

      assertTrue("Key is ", hobbies.containsKey("4"));

      Set keys = hobbies.keySet();
      assertEquals("Key size ", NUMBER_OF_STAGED_HOBBIES+2, keys.size());

      Set entries = hobbies.entrySet();
      assertEquals("Entry size ", NUMBER_OF_STAGED_HOBBIES+2, entries.size());

   }

   public void testEntrySet() throws Throwable {
      System.out.println("Map "+ hobbies.toString());
      for (Iterator i = hobbies.entrySet().iterator(); i.hasNext();) {
         Map.Entry entry = (Map.Entry) i.next();
         System.out.println("Entry key and value "+ entry.getKey()+ " "+ entry.getValue());
      }
   }

   public void testValues() throws Throwable {
      System.out.println("Map "+ hobbies.toString());
      
      Set correct = new HashSet();
      correct.add("golf");
      correct.add("tennis");
      correct.add("polo");
      correct.add("Non-null value but the key is null");
      correct.add(null);

      Collection values = hobbies.values();
      assertEquals("Correct number of elements in value collection", 
                   correct.size(), values.size());
      
      Iterator iter = null;
      for (iter = correct.iterator(); iter.hasNext();)
         assertTrue(values.contains(iter.next()));
         
      for (iter = values.iterator(); iter.hasNext();) {
         Object value = iter.next();
         assertTrue( value + " expected", correct.remove(value));         
      }
      assertTrue("No missing elements from iterator", correct.size() == 0);
      
      iter.remove();
      assertTrue("2 elements left after remove via iter", values.size() == NUMBER_OF_STAGED_HOBBIES-1);
      assertTrue("Iter removal reflected in map", hobbies.size() == NUMBER_OF_STAGED_HOBBIES-1);
      
      Object[] data = values.toArray();
      assertTrue("2 elements in values array", data.length == NUMBER_OF_STAGED_HOBBIES - 1);
      
      values.remove(data[0]);
      assertTrue("1 element left after remove", values.size() == NUMBER_OF_STAGED_HOBBIES-2);
      assertTrue("Removal reflected in map", hobbies.size() == NUMBER_OF_STAGED_HOBBIES-2);

      values.clear();
      assertTrue("0 elements left after clear", values.size() == 0);
      assertTrue("Clear reflected in map", hobbies.size() == 0);
   }
   
   public void testContainsValue() throws Throwable {
      System.out.println("Map "+ hobbies.toString());
      assertTrue("contains golf", hobbies.containsValue("golf"));
      assertTrue("contains tennis", hobbies.containsValue("tennis"));
      assertTrue("contains polo", hobbies.containsValue("polo"));
      assertFalse("does not contain squash", hobbies.containsValue("squash"));
   }

   public void testEquals() throws Throwable {
      Map map = new HashMap();
      map.put("1", "test");
      map.put("4", "test");
      map.put("2", "tennis");
      assertFalse("Map should not be the same ", map.equals(hobbies));

      map.clear();
      map.put( "1", "golf");
      map.put("2", "tennis");
      map.put("3", "polo");
      map.put(null,"Non-null value but the key is null");
      map.put("key is non-null but value is null", null);
      assertTrue("Map should be the same ", map.equals(hobbies));
      assertTrue("Map should be the same, hobbies=" + hobbies.toString() + ", map=" + map.toString(), hobbies.equals(map));
      assertTrue("Map should be the same ", hobbies.equals(hobbies));
   }

   public void testAttachAndDetach() throws Exception
   {
      Map map = new HashMap();
      map.put("1", "English");
      map.put("2", "French");
      map.put("3", "Taiwanese");

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

      map = (Map)cache_.removeObject("/test");  // detach
      assertEquals("Size ", 3, map.size());

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

      // Try to re-attach
      cache_.putObject("/test", map);
      map.remove("3");
      assertEquals("Size ", 2, map.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();
      add1.setCity("Sunnyvale");
      add1.setZip(94086);

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

      Map map = new HashMap();
      map.put("1", add1);
      map.put("2", add2);
      map.put("3", add3);

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

      map = (Map)cache_.removeObject("/test");
      assertEquals("Size ", 3, map.size());

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

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

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

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

