/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.pojo;

import org.jboss.cache.CacheImpl;
import org.jgroups.Address;

import java.util.List;

/**
 * Utilities for unit testing JBossCache.
 *
 * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
 * @version $Revision: 4456 $
 */
public class TestingUtil
{

   /**
    * @param caches  caches which must all have consistent views
    * @param timeout max number of ms to loop
    * @throws RuntimeException if <code>timeout</code> ms have elapse without
    *                          all caches having the same number of members.
    */
   public static void blockUntilViewsReceived(PojoCache[] caches, long timeout)
   {
      long failTime = System.currentTimeMillis() + timeout;

      while (System.currentTimeMillis() < failTime)
      {
         org.jboss.cache.pojo.TestingUtil.sleepThread(100);
         if (org.jboss.cache.pojo.TestingUtil.areCacheViewsComplete(caches))
            return;
      }

      throw new RuntimeException("timed out before caches had complete views");
   }

   /**
    */
   public static void blockUntilViewReceived(PojoCache cache, int groupSize, long timeout)
   {
      long failTime = System.currentTimeMillis() + timeout;

      CacheImpl<Object, Object> tcache = (CacheImpl<Object, Object>) cache.getCache();
      while (System.currentTimeMillis() < failTime)
      {
         org.jboss.cache.pojo.TestingUtil.sleepThread(100);
         if (org.jboss.cache.pojo.TestingUtil.isCacheViewComplete(tcache, groupSize))
            return;
      }

      throw new RuntimeException("timed out before caches had complete views");
   }

   /**
    * Checks each cache to see if the number of elements in the array
    * returned by {@link org.jboss.cache.CacheImpl#getMembers()} matches the size of
    * the <code>caches</code> parameter.
    *
    * @param caches caches that should form a View
    * @return <code>true</code> if all caches have
    *         <code>caches.length</code> members; false otherwise
    * @throws IllegalStateException if any of the caches have MORE view
    *                               members than caches.length
    */
   public static boolean areCacheViewsComplete(PojoCache[] caches)
   {
      int memberCount = caches.length;

      for (int i = 0; i < memberCount; i++)
      {
         CacheImpl<Object, Object> cache = (CacheImpl<Object, Object>) caches[i].getCache();
         return org.jboss.cache.pojo.TestingUtil.isCacheViewComplete(cache, memberCount);
      }

      return true;
   }

   /**
    * FIXME Comment this
    *
    * @param cache
    * @param memberCount
    */
   public static boolean isCacheViewComplete(CacheImpl<Object, Object> cache, int memberCount)
   {
      List<Address> members = cache.getMembers();
      if (members == null || memberCount > members.size())
      {
         return false;
      }
      else if (memberCount < members.size())
      {
         // This is an exceptional condition
         StringBuffer sb = new StringBuffer("Cache at address ");
         sb.append(cache.getLocalAddress());
         sb.append(" had ");
         sb.append(members.size());
         sb.append(" members; expecting ");
         sb.append(memberCount);
         sb.append(". Members were (");
         for (int j = 0; j < members.size(); j++)
         {
            if (j > 0)
               sb.append(", ");
            sb.append(members.get(j));
         }
         sb.append(')');

         throw new IllegalStateException(sb.toString());
      }

      return true;
   }


   /**
    * Puts the current thread to sleep for the desired number of ms, suppressing
    * any exceptions.
    *
    * @param sleeptime number of ms to sleep
    */
   public static void sleepThread(long sleeptime)
   {
      try
      {
         Thread.sleep(sleeptime);
      }
      catch (InterruptedException ie)
      {
      }
   }
}
