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

import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.EvictionPolicyConfig;
import org.jboss.cache.config.EvictionRegionConfig;
import org.jboss.cache.eviction.EvictedEventNode;
import org.jboss.cache.eviction.EvictionPolicy;
import org.jboss.cache.eviction.LRUPolicy;

/**
 * Defines characteristics such as class loading and eviction of {@link org.jboss.cache.Node}s belonging to a Region in a {@link Cache}.
 * A Region is described by an {@link #getFqn() Fqn} relative to the root of the cache.
 * All nodes and child nodes of this Fqn belong to this region.
 * <p/>
 * If a region is to be recognised as an eviction region (region of type {@link Type#EVICTION} then
 * it <b>must</b> have an {@link org.jboss.cache.config.EvictionPolicyConfig} set using {@link #setEvictionPolicy(org.jboss.cache.config.EvictionPolicyConfig)}.
 * <p/>
 * Similarly, to be recognised as a marshalling region (region of type {@link Type#MARSHALLING} then it <b>must</b> have a
 * {@link ClassLoader} registered using {@link #registerContextClassLoader(ClassLoader)}.
 * <p/>
 * Note that a single region can be both an eviction and marshalling region at the same time.
 * <p/>
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 * @see org.jboss.cache.RegionManager
 * @since 2.0.0
 */
public interface Region extends Comparable<Region>, Cloneable
{

   /**
    * Types of regions.
    */
   static enum Type
   {
      EVICTION, MARSHALLING, ANY
   }

   /**
    * Region status
    */
   static enum Status
   {
      ACTIVATING, ACTIVE, INACTIVATING, INACTIVE
   }

   /**
    * Registers a specific {@link ClassLoader} for this region,
    * overridding the default cache class loader.
    *
    * @param classLoader specific class loader
    */
   void registerContextClassLoader(ClassLoader classLoader);

   /**
    * @return the cache-wide configuration
    * @since 2.1.0
    */
   Configuration getCacheConfiguration();

   /**
    * Unregisters a registered {@link ClassLoader}s for this region.
    */
   void unregisterContextClassLoader();

   /**
    * Activates this region for replication.
    * By default, the entire cache is activated for replication at start-up.
    *
    * @throws RegionNotEmptyException if the {@link Fqn} that represents this region already exists and contains data or children.
    */
   void activate() throws RegionNotEmptyException;

   /**
    * Activates this region for replication, but if the {@link Fqn} that represents this region already exists and
    * either contains data or children, no state transfers take place.  The region is simply marked as active in this
    * case.
    */
   void activateIfEmpty();

   /**
    * Deactivates this region from being replicated.
    */
   void deactivate();

   /**
    * Sets this region as active - this only marks a flag
    * and does not actually activates or
    * deactivates this region.  Use {@link #activate()}
    * and {@link #deactivate()} for the full process.
    *
    * @param b
    */
   void setActive(boolean b);

   /**
    * Returns true if this region has been activated.
    *
    * @return true if this region has been activated.
    */
   boolean isActive();

   /**
    * Returns the configured {@link ClassLoader} for this region.
    *
    * @return a ClassLoader
    */
   ClassLoader getClassLoader();

   /**
    * Configures an eviction policy for this region.
    *
    * @param evictionPolicyConfig configuration to set
    */
   void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig);

   /**
    * Returns an eviction policy configuration.
    *
    * @return an eviction policy configuration
    */
   EvictionPolicyConfig getEvictionPolicyConfig();

   /**
    * Returns an eviction policy.
    *
    * @return an eviction policy
    */
   EvictionPolicy getEvictionPolicy();

   /**
    * Returns an eviction region configuration for this region.
    *
    * @return an eviction region configuration
    */
   EvictionRegionConfig getEvictionRegionConfig();

   /**
    * Clears the node event queue used for processing eviction.
    *
    * @see #nodeEventQueueSize()
    */
   void resetEvictionQueues();

   /**
    * Returns the size of the node event queue, used by the eviction thread.
    *
    * @return number of events
    */
   int nodeEventQueueSize();

   /**
    * Returns the most recent {@link org.jboss.cache.eviction.EvictedEventNode} added to the event queue by
    * {@link #putNodeEvent(EvictedEventNode)}.
    *
    * @return the last {@link org.jboss.cache.eviction.EvictedEventNode}, or null if no more events exist
    */
   EvictedEventNode takeLastEventNode();

   /**
    * Adds an {@link org.jboss.cache.eviction.EvictedEventNode} to the internal queue for processing
    * by the eviction thread.
    *
    * @param event event to add
    */
   void putNodeEvent(EvictedEventNode event);

   /**
    * Marks a {@link org.jboss.cache.Node} as currently in use, by adding an event to the eviction queue.
    * If there is an {@link EvictionPolicy} associated with this region, and
    * it respects this event (e.g., {@link LRUPolicy} does), then the {@link org.jboss.cache.Node} will not
    * be evicted until {@link #unmarkNodeCurrentlyInUse(Fqn)} is invoked.
    * <p/>
    * This mechanism can be used to prevent eviction of data that the application
    * is currently using, in the absence of any locks on the {@link org.jboss.cache.Node} where the
    * data is stored.
    *
    * @param fqn Fqn of the node.
    * @see #unmarkNodeCurrentlyInUse(Fqn)
    */
   void markNodeCurrentlyInUse(Fqn fqn, long timeout);

   /**
    * Adds an event to the eviction queue indicating that a node is no longer in use.
    *
    * @param fqn Fqn of the node.
    * @see #markNodeCurrentlyInUse(Fqn,long)
    */
   void unmarkNodeCurrentlyInUse(Fqn fqn);

   /**
    * Returns the {@link org.jboss.cache.Fqn} of this region.
    *
    * @return the Fqn
    */
   Fqn getFqn();

   /**
    * A mechanism to set status of a region, more fine grained control than just setActive();
    *
    * @param status status of the region
    * @since 2.1.0
    */
   void setStatus(Status status);

   /**
    * @return the region's status
    */
   Status getStatus();

   Region clone(Fqn cloneFqn);

}
