/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.eviction;

import static org.testng.AssertJUnit.assertEquals;

import java.util.Iterator;

import org.jboss.cache.Fqn;
import org.jboss.cache.Region;
import org.jboss.cache.RegionManager;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
 * @author Daniel Huang
 * @version $Revision: 4444 $
 */
@Test(groups = {"functional"})
public class ElementSizeAlgorithmTest
{
   RegionManager regionManager;
   ElementSizeAlgorithm algo;

   @BeforeMethod(alwaysRun = true)
   public void setUp() throws Exception
   {
      algo = new ElementSizeAlgorithm();
      regionManager = new RegionManager();
      ElementSizeConfiguration config = new ElementSizeConfiguration();
      // We have to setCache maxElementsPerNode!!
      config.setMaxElementsPerNode(0);
      config.setEvictionPolicyClass(DummyEvictionPolicy.class.getName());
      regionManager.getRegion("/a/b", true).setEvictionPolicy(config);
   }

   public void testMaxElements() throws Exception
   {
      Region region = regionManager.getRegion("/a/b", true);
      ElementSizeConfiguration config = (ElementSizeConfiguration) region.getEvictionPolicyConfig();
      config.setMaxNodes(10);
      config.setMaxElementsPerNode(6);

      for (int i = 0; i < 10; i++)
      {
         Fqn fqn = Fqn.fromString("/a/b/" + Integer.toString(i));
         region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_NODE_EVENT));
         if (i % 2 == 0)
         {
            for (int k = 0; k < i; k++)
            {
               region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_ELEMENT_EVENT));
            }
         }
      }

      algo.process(region);

      ElementSizeQueue queue = (ElementSizeQueue) algo.evictionQueue;
      assertEquals(9, algo.getEvictionQueue().getNumberOfNodes());
      assertEquals(12, algo.getEvictionQueue().getNumberOfElements());
      // now verify the order.
      Iterator it = queue.iterate();
      int count = 6;
      while (it.hasNext())
      {
         NodeEntry ne = (NodeEntry) it.next();
         System.out.println(ne);

         if (count > 0)
         {
            assertEquals(count, ne.getNumberOfElements());
         }
         else
         {
            assertEquals(0, ne.getNumberOfElements());
         }
         count -= 2;
      }

      for (int i = 0; i < 7; i++)
      {
         region.putNodeEvent(new EvictedEventNode(Fqn.fromString("/a/b/9"), NodeEventType.ADD_ELEMENT_EVENT));
         region.putNodeEvent(new EvictedEventNode(Fqn.fromString("/a/b/7"), NodeEventType.ADD_ELEMENT_EVENT));
      }

      algo.process(region);

      assertEquals(7, queue.getNumberOfNodes());
   }

   public void testMaxNodesAndMaxElements() throws Exception
   {
      Region region = regionManager.getRegion("/a/b", true);
      ElementSizeConfiguration config = (ElementSizeConfiguration) region.getEvictionPolicyConfig();
      config.setMaxNodes(10);
      config.setMaxElementsPerNode(100);

      for (int i = 0; i < 20; i++)
      {
         Fqn fqn = Fqn.fromString("/a/b/" + Integer.toString(i));
         region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_NODE_EVENT));
         for (int k = 0; k < i; k++)
         {
            region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_ELEMENT_EVENT));

         }
      }

      algo.process(region);

      ElementSizeQueue queue = (ElementSizeQueue) algo.evictionQueue;
      assertEquals(10, algo.getEvictionQueue().getNumberOfNodes());
      assertEquals(45, algo.getEvictionQueue().getNumberOfElements());

      // now verify the order.
      Iterator it = queue.iterate();
      int num = 9;
      while (it.hasNext())
      {
         NodeEntry ne = (NodeEntry) it.next();
         assertEquals(num, ne.getNumberOfElements());
         num--;
      }

   }
}
