/*
 * JBoss, the OpenSource J2EE webOS
 * 
 * Distributable under LGPL license. See terms of license at gnu.org.
 */

package javax.emb;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * This singleton class manages the different header types and allows the
 * generic selection of a format bean suitable for a given media. The selection
 * criterion is the file extension associated with the media, and a media
 * format can be registered multiple times if many file extensions are
 * typically associated with it.
 * 
 * <p>The class has a private default constructor to prevent direct
 * construction of instances in applications. Instead, the <code>SINGLETON</code>
 * constant provides the one and only instance of this class. Implementations
 * are free to initialize the registry with mappings of their choice. However,
 * the design allows applications to plug in additional mappings.
 * 
 * @version <tt>$Revision: 1.7 $</tt>
 * @author <a href="mailto:ricardoarguello@users.sourceforge.net">Ricardo
 *         Argüello</a>
 */
public final class MediaFormatRegistry
{
   public static final MediaFormatRegistry SINGLETON =
      new MediaFormatRegistry();

   private final Map mediaFormats = Collections.synchronizedMap(new HashMap());

   /**
    * Private default constructor to prevent direct construction of instances
    * in applications. Use <code>SINGLETON</code> instead.
    */
   private MediaFormatRegistry()
   {
   }

   /**
    * This operation associates the given file extension with the given media
    * format instance.
    * 
    * @param fileExtension a file extension identifying the format. Note that
    *        such extensions should not start with a leading dot.
    * @param mediaFormat the media format instance to be registered.
    * @throws javax.embFormatAlreadyBoundException if a mapping already exists
    *         for the given file extension.
    * @throws java.lang.NullPointerException if one of the values passed is
    *         <code>null</code>.
    */
   public void bind(String fileExtension, MediaFormat mediaFormat)
      throws FormatAlreadyBoundException
   {
      if (fileExtension == null || mediaFormat == null)
      {
         throw new NullPointerException();
      }

      fileExtension = fileExtension.toLowerCase();

      if (mediaFormats.containsKey(fileExtension))
      {
         throw new FormatAlreadyBoundException();
      }

      mediaFormats.put(fileExtension, mediaFormat);
   }

   /**
    * This operation returns the file extensions for which bindings exist in
    * the registry.
    * 
    * @return the file extensions.
    */
   public Iterator getFileExtensions()
   {
      synchronized (mediaFormats)
      {
         return mediaFormats.keySet().iterator();
      }
   }

   /**
    * Returns the media format instance registered under the given file
    * extension.
    * 
    * @param fileExtension a file extension identifying the format. Note that
    *        such extensions should not start with a leading dot.
    * @param javax.emb.FormatNotFoundException if there is no mapping for the
    *        given file extension.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   public MediaFormat lookup(String fileExtension)
      throws FormatNotFoundException
   {
      fileExtension = fileExtension.toLowerCase();

      if (!mediaFormats.containsKey(fileExtension))
      {
         throw new FormatNotFoundException();
      }

      return (MediaFormat) mediaFormats.get(fileExtension);
   }

   /**
    * This operation associates the given file extension with the given media
    * format instance. If a mapping already exists for the given file
    * extension, it is replaced by the new one.
    * 
    * @param fileExtension a file extension identifying the format. Note that
    *        such extensions should not start with a leading dot.
    * @param mediaFormat the media format instance to be registered.
    * @throws java.lang.NullPointerException if one of the values passed is
    *         <code>null</code>.
    */
   public void rebind(String fileExtension, MediaFormat mediaFormat)
   {
      if (fileExtension == null || mediaFormat == null)
      {
         throw new NullPointerException();
      }

      fileExtension = fileExtension.toLowerCase();

      mediaFormats.put(fileExtension, mediaFormat);
   }

   /**
    * This method removes the mapping defined by the given file extension.
    * 
    * @param fileExtension a file extension identifying the format. Note that
    *        such extensions should not start with a leading dot.
    * @throws javax.emb.FormatNotFoundException if there is no mapping for the
    *         given file extension.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   public void unbind(String fileExtension) throws FormatNotFoundException
   {
      if (fileExtension == null)
      {
         throw new NullPointerException();
      }

      fileExtension = fileExtension.toLowerCase();

      if (!mediaFormats.containsKey(fileExtension))
      {
         throw new FormatNotFoundException();
      }

      mediaFormats.remove(fileExtension);
   }
}