package users;

import java.util.Locale;
import java.util.ResourceBundle;

/**
  * Convenience class implementing basic capability behavior.
  *
  * <p>For convenience you can derive all your capability classes from
  * <code>AbstractCapability</code>, which will manage names and display names.</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 05/05/1999
  * @since v2.0
  */
public abstract class AbstractCapability implements Capability {

  /**
    * The name of the capability.
    *
    * <p><strong>IMMUTABLE</strong></p>
    *
    * @serial
    */
  private final String m_sName;

  /**
    * Create a new capability with a given name.
    *
    * @param sName the name of the capability.
    */
  public AbstractCapability(String sName) {
    super();

    m_sName = sName;
  }

  // Capability interface methods

  /**
    * Get the capability's name.
    *
    * @override Never
    *
    * @return the capability's name.
    */
  public String getName() {
    return m_sName;
  }

  /**
    * Get the display name of this capability using the default locale.
    *
    * <p>This is identical to</p>
    *
    * <pre>
    * &nbsp; getDisplayName (Locale.getDefault());
    * </pre>
    *
    * @override Never
    *
    * @return the display name of this capability according to the default locale.
    */
  public String getDisplayName() {
    return getDisplayName (Locale.getDefault());
  }

  /**
    * Get the display name of this capability according to a locale. You can set the base name of the resource
    * bundle to be used by calling {@link #setDisplayNameResourceBundleName}.
    *
    * @override Never
    *
    * @param l the locale according to which to get the display name
    *
    * @return the display name according to the locale.
    */
  public String getDisplayName (Locale l) {
    return getCapabilityDisplayName (getName(), l);
  }

  /**
    * Return the grant state of this capability. This method is <i>abstract</i>
    * and you'll have to redefine it in subclasses.
    *
    * @override Always
    *
    * @return true if this capability grants rights.
    */
  public abstract boolean isGranted();
  /**
    * Get the capability that is the inverse to this one. This method is abstract and
    * you'll have to redefine it in subclasses.
    *
    * @override Always
    *
    * @return the capability that is the inverse to this one.
    */
  public abstract Capability getToggled();

  // general object methods

  /**
    * Return a string representation of this capability.
    *
    * <p>The format of the returned string is:</p>
    *
    * <p><i>display name</i> &lt;<i>name</i>&gt;: <i>grant state</i></p>
    *
    * @override Sometimes
    *
    * @return a string representation of this capability.
    */
  public String toString() {
    return getDisplayName() + " <" + getName() + ">: " + isGranted();
  }

  /**
    * The resource bundle that contains the display names for the capabilities. CACHE.
    */
  private static ResourceBundle s_rbDisplayNames = null;
  /**
    * The least recently used locale for looking up display names.
    */
  private static Locale s_lLRU = null;

  /**
    * The base name for the resource bundles containing the capabilities' display names.
    */
  private static String s_sBaseName = null;

  /**
    * Get a capabilities display name depending on a locale. This will lookup the capability's display name
    * in the resource bundle specified through {@link #setDisplayNameResourceBundleName} and the locale.
    * The key will be:
    * <pre>capabilities.display_names.<i>sName</i></pre>
    *
    * @param sName the programmatical name of the capability
    * @param l the locale that determines which resource bundle to use.
    *
    * @see java.util.ResourceBundle
    */
  private static final String getCapabilityDisplayName (String sName, Locale l) {
    if (l != s_lLRU) {
      s_lLRU = l;

      s_rbDisplayNames = ResourceBundle.getBundle (s_sBaseName, l);
    }

    return s_rbDisplayNames.getString ("capabilities.display_names." + sName);
  }

  /**
    * Set the base name for the resouce bundle that contains the capabilities' display names. The resource
    * must contain a String for each Capability. The key for the String must be:
    *
    *  <code>capabilities.display_names.<i>capability_name</i></code>
    */
  public static final void setDisplayNameResourceBundleName (String sBaseName) {
    s_sBaseName = sBaseName;
    s_lLRU = null;
  }
}