// ============================================================================
// File:               $File$
//
// Project:            DXF viewer
//
// Purpose:            An action which knows about resources.
//
// Author:             Rammi
//
// Copyright Notice:   (c) 2003  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================

package de.caff.gimmicks.swing;

import de.caff.i18n.I18n;
import de.caff.i18n.Localizable;
import de.caff.util.Utility;

import javax.swing.*;
import java.util.Locale;
import java.util.MissingResourceException;

/**
 *  An action which knows about resources.
 *  @author <a href="mailto:rammi@caff.de">Rammi</a>
 *  @version $Revision$
 */
public abstract class ResourcedAction
        extends AbstractAction
        implements Localizable
{
  /** Use this as a prefix for resources of standard names, so they are updated automatically on locale changes. */
  protected static final String RESOURCE_PREFIX = "i18n.";
  /** Internally used length of RESOURCE_PREFIX. */
  private   static final int    RESOURCE_PREFIX_LENGTH = RESOURCE_PREFIX.length();
  /** Use this as a prefix for resources of icon pathes, so they are updated automatically on locale changes. */
  protected static final String ICON_PREFIX     = RESOURCE_PREFIX+"icon.";
  /** Internally used length of ICON_PREFIX. */
  private   static final int    ICON_PREFIX_LENGTH = ICON_PREFIX.length();
  /** The key for accelerator resources. Compare {@link #ACCELERATOR_KEY} */
  public static final String ACCELERATOR_KEY_RESOURCE    = RESOURCE_PREFIX+ACCELERATOR_KEY;
  /** The key for action command resources. Compare {@link #ACTION_COMMAND_KEY} */
  public static final String ACTION_COMMAND_KEY_RESOURCE = RESOURCE_PREFIX+ACTION_COMMAND_KEY;
  /** The key for long description resources. Compare {@link #LONG_DESCRIPTION} */
  public static final String LONG_DESCRIPTION_RESOURCE   = RESOURCE_PREFIX+LONG_DESCRIPTION;
  /** The key for mnemonic resources. Compare {@link #MNEMONIC_KEY} */
  public static final String MNEMONIC_KEY_RESOURCE       = RESOURCE_PREFIX+MNEMONIC_KEY;
  /** The key for name resources. Compare {@link #NAME} */
  public static final String NAME_RESOURCE               = RESOURCE_PREFIX+NAME;
  /** The key for short description resources. Compare {@link #SHORT_DESCRIPTION} */
  public static final String SHORT_DESCRIPTION_RESOURCE  = RESOURCE_PREFIX+SHORT_DESCRIPTION;
  /** The key for small icon path resources. Compare {@link #SMALL_ICON} */
  public static final String SMALL_ICON_RESOURCE         = ICON_PREFIX+SMALL_ICON;
  /** The current locale. */
  private Locale locale;


  /**
   *  Create a resourced action with the default locale.
   *
   *  @param baseTag basic i18n tag.The settings of this action are tried to set by evaluating this
   *                 resource tag with one of the following suffixes:
   *                 <ul>
   *                 <li>{@link I18n#SUFFIX_TEXT}</li>
   *                 <li>{@link I18n#SUFFIX_TOOLTIP}</li>
   *                 <li>{@link I18n#SUFFIX_DESCRIPTION}</li>
   *                 <li>{@link I18n#SUFFIX_ACCELERATOR}</li>
   *                 <li>{@link I18n#SUFFIX_MNEMONIC}</li>
   *                 </ul>
   */
  protected ResourcedAction(String baseTag)
  {
    this(baseTag, null);
  }

  /**
   *  Create a resourced action.
   *
   *  @param baseTag basic i18n tag.The settings of this action are tried to set by evaluating this
   *                 resource tag with one of the following suffixes:
   *                 <ul>
   *                 <li>{@link I18n#SUFFIX_TEXT}</li>
   *                 <li>{@link I18n#SUFFIX_TOOLTIP}</li>
   *                 <li>{@link I18n#SUFFIX_DESCRIPTION}</li>
   *                 <li>{@link I18n#SUFFIX_ACCELERATOR}</li>
   *                 <li>{@link I18n#SUFFIX_MNEMONIC}</li>
   *                 </ul>
   *  @param l       locale to use
   */
  protected ResourcedAction(String baseTag, Locale l)
  {
    setLocale(l);
    try {
      putValue(NAME_RESOURCE, baseTag+I18n.SUFFIX_TEXT);
    } catch (MissingResourceException e) {
    }
    try {
      putValue(SHORT_DESCRIPTION_RESOURCE, baseTag+I18n.SUFFIX_TOOLTIP);
    } catch (MissingResourceException e) {
    }
    try {
      putValue(LONG_DESCRIPTION_RESOURCE, baseTag+I18n.SUFFIX_DESCRIPTION);
    } catch (MissingResourceException e) {
    }
    try {
      putValue(ACCELERATOR_KEY_RESOURCE, baseTag+I18n.SUFFIX_ACCELERATOR);
    } catch (MissingResourceException e) {
    }
    try {
      putValue(MNEMONIC_KEY_RESOURCE, baseTag+I18n.SUFFIX_MNEMONIC);
    } catch (MissingResourceException e) {
    }
    try {
      putValue(SMALL_ICON_RESOURCE, baseTag+I18n.SUFFIX_ICON);
    } catch (MissingResourceException e) {
    }
    I18n.addLocalizationChangeListener(this);
  }

  /**
   *  Set the locale. This updates all internal resources which depend on locales.
   *  @param l  new locale
   */
  public void setLocale(Locale l)
  {
    if (l == null) {
      l = I18n.getDefaultLocale();
    }
    if (!l.equals(locale)) {
      locale = l;
      Object[] keys = getKeys();
      if (keys != null) {
        for (int k = 0;  k < keys.length;  ++k) {
          String key = keys[k].toString();
          if (key.startsWith(RESOURCE_PREFIX)) {
            putValue(key, getValue(key));  // this reevaluates the locale
          }
        }
      }
    }
  }

  /**
   *  Get the current locale of this action.
   *  @return current locale
   */
  public Locale getLocale()
  {
    return locale;
  }

  /**
   * Sets the <code>Value</code> associated with the specified key.
   * This takes care of setting depending keys for localized keys.
   *
   * @param key  the <code>String</code> that identifies the stored object
   * @param newValue the <code>Object</code> to store using this key
   * @see Action#putValue
   */
  public void putValue(String key, Object newValue)
  {
    if (key.startsWith(RESOURCE_PREFIX)) {
      final String resolved = I18n.getString(newValue.toString(), locale);

      if (key.startsWith(ICON_PREFIX)) {
        super.putValue(key.substring(ICON_PREFIX_LENGTH),
                       new ImageIcon(Utility.loadImage(resolved)));
      }
      else if (MNEMONIC_KEY_RESOURCE.equals(key)) {
        super.putValue(MNEMONIC_KEY, new Integer(resolved.charAt(0)));
      }
      else if (ACCELERATOR_KEY_RESOURCE.equals(key)) {
        super.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(resolved));
      }
      else {
        super.putValue(key.substring(RESOURCE_PREFIX_LENGTH),
                       resolved);
      }
    }
    super.putValue(key, newValue);
  }


  /**
   * Clones the abstract action. This gives the clone
   * its own copy of the key/value list,
   * which is not handled for you by <code>Object.clone()</code>.
   */

  protected Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }
}
