package org.jboss.cache.eviction;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.TreeCache;
import org.jboss.cache.xml.XmlHelper;
import org.w3c.dom.Element;

/**
 * Region Manager unit tests.
 *
 * @author Ben Wang, Feb 11, 2004
 * @author Daniel Huang (dhuang@jboss.org)
 * @version $Revision: 1852 $
 */
public class RegionManagerTest extends TestCase
{
   private final String DEFAULT_REGION = "/_default_/";

   EvictionPolicy policy;
   EvictionConfiguration config;

   public RegionManagerTest(String s)
   {
      super(s);
   }

   public void setUp() throws Exception
   {
      super.setUp();
      policy = new DummyEvictionPolicy();
      config = new DummyEvictionConfiguration();
   }

   public void tearDown() throws Exception
   {
      super.tearDown();
   }

   public void testCreateRegion()
   {
      String fqn1 = "/a/b/c";
      String fqn2 = "/a/b";
      String fqn3 = "/aop";

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(DEFAULT_REGION, policy, config);
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
         regionManager.createRegion(fqn3, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         fail("Failed to create region");
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }

      Region[] regions = regionManager.getRegions();
      assertEquals("Region size ", 4, regions.length);
   }

   public void testCreateRegion2()
   {
      String fqn1 = DEFAULT_REGION;
      String fqn2 = "/a/b/c";
      String fqn3 = "/a/b/";

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
         regionManager.createRegion(fqn3, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         fail("Failed to create region");
      }

      Region[] regions = regionManager.getRegions();
      assertEquals("Region size ", 3, regions.length);
      assertEquals("Region 0", DEFAULT_REGION, regions[0].getFqn());
      assertEquals("Region 1 ", "/a/b/c/", regions[1].getFqn());
      assertEquals("Region 2 ", "/a/b/", regions[2].getFqn());
      Region region = regionManager.getRegion("/a/b/c/d");
      assertNotNull("Region ", region);
      assertEquals("Region ", "/a/b/c/", region.getFqn());
      region = regionManager.getRegion("/a/b");
      assertNotNull("Region ", region);
      assertEquals("Region ", "/a/b/", region.getFqn());
      region = regionManager.getRegion("/a");
      // Should be default.
      assertNotNull("Region ", region);
   }

   public void testNoDefaultRegion()
   {
      String fqn1 = "/a/b/c";
      String fqn2 = "/a/b/";

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         fail("Failed to create region");
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }

      try
      {
         regionManager.getRegion("/a");
      }
      catch (Exception e)
      {
         // This is ok. Should throw an runtime exception
         return;
      }
      fail("If we don't configure the default region, we should throw a RTE!");
   }

   public void testRegionConflict()
   {
      String fqn1 = "/a/b";
      String fqn2 = "/a/b/c";
      String fqn3 = "/aop";
      String fqn4 = DEFAULT_REGION;

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(fqn4, policy, config);
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
         regionManager.createRegion(fqn3, policy, config);
         regionManager.createRegion(fqn4, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         Region[] regions = regionManager.getRegions();
         assertEquals("Region size ", 2, regions.length);
         return;
      }
      fail("testRegionConflict failed");
   }

   public void testRegionConflict2()
   {
      String fqn1 = "/a/b/";
      String fqn2 = "/a/b/c/";
      String fqn3 = "/a/bc";

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
         regionManager.createRegion(fqn3, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         Region[] regions = regionManager.getRegions();
         assertEquals("Region size ", 1, regions.length);
         return;
      }
      fail("testRegionConflict failed");
   }

   public void testGetRegion()
   {
      String fqn1 = DEFAULT_REGION;
      String fqn2 = "/a/bc";
      String fqn3 = "/a/b";

      RegionManager regionManager = new RegionManager();
      try
      {
         regionManager.createRegion(fqn1, policy, config);
         regionManager.createRegion(fqn2, policy, config);
         regionManager.createRegion(fqn3, policy, config);
      }
      catch (RegionNameConflictException e)
      {
         fail("testRegionConflict3 failed " + e);
      }

      Region region = regionManager.getRegion(fqn2);
      assertNotSame("Region ", fqn1, region.getFqn());
   }

   public void testConfigureWithXML() throws Exception
   {
      // test the new style configuration
      String xml = "<region name=\"/test/\" policyClass=\"org.jboss.cache.eviction.LFUPolicy\">" +
            "<attribute name=\"minNodes\">10</attribute>" +
            "<attribute name=\"maxNodes\">20</attribute>" +
            "</region>";
      Element element = XmlHelper.stringToElement(xml);
      RegionManager regionManager = new RegionManager();
      Region region = regionManager.createRegion("/test", element);

      assertTrue(region.getEvictionPolicy() instanceof LFUPolicy);
      assertTrue(region.getEvictionConfiguration() instanceof LFUConfiguration);
      LFUConfiguration config = (LFUConfiguration) region.getEvictionConfiguration();
      assertEquals(20, config.getMaxNodes());
      assertEquals(10, config.getMinNodes());
      assertEquals("/test/", region.getFqn());

      TreeCache cache = new TreeCache();
      cache.setEvictionPolicyClass("org.jboss.cache.eviction.LFUPolicy");

      // test the 1.2.x style configuration
      xml = "<region name=\"abc\">" +
            "<attribute name=\"minNodes\">10</attribute>" +
            "<attribute name=\"maxNodes\">20</attribute>" +
            "</region>";
      element = XmlHelper.stringToElement(xml);
      regionManager = new RegionManager();
      regionManager.setTreeCache(cache);
      region = regionManager.createRegion("/abc/", element);

      assertTrue(region.getEvictionPolicy() instanceof LFUPolicy);
      assertTrue(region.getEvictionConfiguration() instanceof LFUConfiguration);
      config = (LFUConfiguration) region.getEvictionConfiguration();
      assertEquals(20, config.getMaxNodes());
      assertEquals(10, config.getMinNodes());
      assertEquals("/abc/", region.getFqn());
   }

   public void testIsUsingNewStyleConfiguration() throws Exception
   {
      String xml = "<config>\n" +
            "  <attribute name=\"wakeUpIntervalSeconds\">5</attribute>\n" +
            "  <region name=\"/_default_\">\n" +
            "    <attribute name=\"maxNodes\">5000</attribute>\n" +
            "    <attribute name=\"minNodes\">10</attribute>\n" +
            "  </region>\n" +
            "  <region name=\"/org/jboss/data\">\n" +
            "    <attribute name=\"maxNodes\">5000</attribute>\n" +
            "    <attribute name=\"minNodes\">4000</attribute>\n" +
            "  </region>\n" +
            "  <region name=\"/org/jboss/test/data\">\n" +
            "    <attribute name=\"minNodes\">5</attribute>\n" +
            "  </region>\n" +
            "</config>";
      Element element = XmlHelper.stringToElement(xml);

      assertFalse(RegionManager.isUsingNewStyleConfiguration(element));

      xml = "<config>\n" +
            "  <attribute name=\"wakeUpIntervalSeconds\">5</attribute>\n" +
            "  <region name=\"/_default_\">\n" +
            "    <attribute name=\"maxNodes\">5000</attribute>\n" +
            "    <attribute name=\"minNodes\">10</attribute>\n" +
            "  </region>\n" +
            "  <region name=\"/org/jboss/data\" policyClass=\"org.jboss.cache.eviction.MRUPolicy\">\n" +
            "    <attribute name=\"maxNodes\">5000</attribute>\n" +
            "    <attribute name=\"minNodes\">4000</attribute>\n" +
            "  </region>\n" +
            "  <region name=\"/org/jboss/test/data\">\n" +
            "    <attribute name=\"minNodes\">5</attribute>\n" +
            "  </region>\n" +
            "</config>";

      element = XmlHelper.stringToElement(xml);

      assertTrue(RegionManager.isUsingNewStyleConfiguration(element));
   }

   public void testRegionOrdering() throws Exception
   {
      String fqn1 = DEFAULT_REGION;
      String fqn2 = "/a/b/c/d/e/";
      String fqn3 = "/a/b/c/d/";
      String fqn4 = "/a/b/c/";

      RegionManager rm = new RegionManager();
      rm.createRegion(fqn1, policy, config);
      rm.createRegion(fqn2, policy, config);
      rm.createRegion(fqn3, policy, config);
      rm.createRegion(fqn4, policy, config);

      Region region = rm.getRegion("/a/b/c/d/e/f");
      Region region2 = rm.getRegion("/e/f/g");

      assertEquals(fqn2, region.getFqn());
      assertEquals(fqn1, region2.getFqn());

      Region[] regions = rm.getRegions();
      for (int i = 0; i < regions.length; i++)
      {
         switch (i)
         {
            case 0:
               assertEquals(fqn1, regions[i].getFqn());
               break;
            case 1:
               assertEquals(fqn2, regions[i].getFqn());
               break;
            case 2:
               assertEquals(fqn3, regions[i].getFqn());
               break;
            case 3:
               assertEquals(fqn4, regions[i].getFqn());
               break;
            default:
               fail("This error condition should never be reached");
               break;
         }
      }
   }

   void log(String msg)
   {
      System.out.println("-- " + msg);
   }

   public static Test suite()
   {
      return new TestSuite(RegionManagerTest.class);
   }

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

}
