/* Charset.java -- 
   Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package java.nio.charset;

import gnu.classpath.ServiceFactory;
import gnu.classpath.SystemProperties;
import gnu.java.nio.charset.Provider;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.spi.CharsetProvider;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author Jesse Rosenstock
 * @since 1.4
 */
public abstract class Charset implements Comparable
{
  private CharsetEncoder cachedEncoder;
  private CharsetDecoder cachedDecoder;
 
  /**
   * Charset providers.
   */
  private static CharsetProvider[] providers;
  
  private final String canonicalName;
  private final String[] aliases;
  
  protected Charset (String canonicalName, String[] aliases)
  {
    checkName (canonicalName);
    if (aliases != null)
      {
        int n = aliases.length;
        for (int i = 0; i < n; ++i)
            checkName (aliases[i]);
      }

    cachedEncoder = null;
    cachedDecoder = null;
    this.canonicalName = canonicalName;
    this.aliases = aliases;
  }

  /**
   * @throws IllegalCharsetNameException  if the name is illegal
   */
  private static void checkName (String name)
  {
    int n = name.length ();

    if (n == 0)
      throw new IllegalCharsetNameException (name);

    char ch = name.charAt (0);
    if (!(('A' <= ch && ch <= 'Z')
          || ('a' <= ch && ch <= 'z')
          || ('0' <= ch && ch <= '9')))
      throw new IllegalCharsetNameException (name);

    for (int i = 1; i < n; ++i)
      {
        ch = name.charAt (i);
        if (!(('A' <= ch && ch <= 'Z')
              || ('a' <= ch && ch <= 'z')
              || ('0' <= ch && ch <= '9')
              || ch == '-' || ch == '.' || ch == ':' || ch == '_'))
          throw new IllegalCharsetNameException (name);
      }
  }

  /**
   * Returns the system default charset.
   *
   * This may be set by the user or VM with the file.encoding
   * property.
   *
   * @since 1.5
   */
  public static Charset defaultCharset()
  {
    String encoding;
    
    try 
      {
	encoding = SystemProperties.getProperty("file.encoding");
      }
    catch(SecurityException e)
      {
	// Use fallback.
	encoding = "ISO-8859-1";
      }
    catch(IllegalArgumentException e)
      {
	// Use fallback.
	encoding = "ISO-8859-1";
      }

    try
      {
	return forName(encoding);
      }
    catch(UnsupportedCharsetException e)
      {
	// Ignore.
      }
    catch(IllegalCharsetNameException e)
      {
	// Ignore.
      }
    catch(IllegalArgumentException e)
      {
	// Ignore.
      }
    
    throw new IllegalStateException("Can't get default charset!");
  }

  public static boolean isSupported (String charsetName)
  {
    return charsetForName (charsetName) != null;
  }

  /**
   * Returns the Charset instance for the charset of the given name.
   * 
   * @param charsetName
   * @return
   * @throws UnsupportedCharsetException if this VM does not support
   * the charset of the given name.
   * @throws IllegalCharsetNameException if the given charset name is
   * legal.
   * @throws IllegalArgumentException if <code>charsetName</code> is null.
   */
  public static Charset forName (String charsetName)
  {
    // Throws IllegalArgumentException as the JDK does.
    if(charsetName == null)
        throw new IllegalArgumentException("Charset name must not be null.");
    
    Charset cs = charsetForName (charsetName);
    if (cs == null)
      throw new UnsupportedCharsetException (charsetName);
    return cs;
  }

  /**
   * Retrieves a charset for the given charset name.
   *
   * @return A charset object for the charset with the specified name, or
   * <code>null</code> if no such charset exists.
   *
   * @throws IllegalCharsetNameException  if the name is illegal
   */
  private static Charset charsetForName(String charsetName)
  {
    checkName (charsetName);
    // Try the default provider first
    // (so we don't need to load external providers unless really necessary)
    // if it is an exotic charset try loading the external providers.
    Charset cs = provider().charsetForName(charsetName);
    if (cs == null)
      {
	CharsetProvider[] providers = providers2();
	for (int i = 0; i < providers.length; i++)
	  {
	    cs = providers[i].charsetForName(charsetName);
	    if (cs != null)
	      break;
	  }
      }
    return cs;
  }

  public static SortedMap availableCharsets()
  {
    TreeMap charsets = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    for (Iterator i = provider().charsets(); i.hasNext(); )
      {
	Charset cs = (Charset) i.next();
	charsets.put(cs.name(), cs);
      }

    CharsetProvider[] providers = providers2();
    for (int j = 0; j < providers.length; j++)
      {
        for (Iterator i = providers[j].charsets(); i.hasNext(); )
          {
            Charset cs = (Charset) i.next();
            charsets.put(cs.name(), cs);
          }
      }

    return Collections.unmodifiableSortedMap(charsets);
  }

  private static CharsetProvider provider()
  {
    try
      {
	String s = System.getProperty("charset.provider");
	if (s != null)
	  {
	    CharsetProvider p =
	      (CharsetProvider) ((Class.forName(s)).newInstance());
	    return p;
	  }
      }
    catch (Exception e)
      {
	// Ignore.
      }
    
    return Provider.provider();
  }

  /**
   * We need to support multiple providers, reading them from
   * java.nio.charset.spi.CharsetProvider in the resource directory
   * META-INF/services. This returns the "extra" charset providers.
   */
  private static CharsetProvider[] providers2()
  {
    if (providers == null)
      {
        try
          {
            Iterator i = ServiceFactory.lookupProviders(CharsetProvider.class);
            LinkedHashSet set = new LinkedHashSet();
            while (i.hasNext())
              set.add(i.next());

            providers = new CharsetProvider[set.size()];
            set.toArray(providers);
          }
        catch (Exception e)
          {
            throw new RuntimeException(e);
          }
      }
    return providers;
  }

  public final String name ()
  {
    return canonicalName;
  }

  public final Set aliases ()
  {
    if (aliases == null)
      return Collections.EMPTY_SET;

    // should we cache the aliasSet instead?
    int n = aliases.length;
    HashSet aliasSet = new HashSet (n);
    for (int i = 0; i < n; ++i)
        aliasSet.add (aliases[i]);
    return Collections.unmodifiableSet (aliasSet);
  }

  public String displayName ()
  {
    return canonicalName;
  }

  public String displayName (Locale locale)
  {
    return canonicalName;
  }

  public final boolean isRegistered ()
  {
    return (!canonicalName.startsWith ("x-")
            && !canonicalName.startsWith ("X-"));
  }

  public abstract boolean contains (Charset cs);

  public abstract CharsetDecoder newDecoder ();

  public abstract CharsetEncoder newEncoder ();

  public boolean canEncode ()
  {
    return true;
  }

  // NB: This implementation serializes different threads calling
  // Charset.encode(), a potential performance problem.  It might
  // be better to remove the cache, or use ThreadLocal to cache on
  // a per-thread basis.
  public final synchronized ByteBuffer encode (CharBuffer cb)
  {
    try
      {
	if (cachedEncoder == null)
	  {
	    cachedEncoder = newEncoder ()
	      .onMalformedInput (CodingErrorAction.REPLACE)
	      .onUnmappableCharacter (CodingErrorAction.REPLACE);
	  } else
	  cachedEncoder.reset();
	return cachedEncoder.encode (cb);
      }
    catch (CharacterCodingException e)
      {
        throw new AssertionError (e);
      }
  }
  
  public final ByteBuffer encode (String str)
  {
    return encode (CharBuffer.wrap (str));
  }

  // NB: This implementation serializes different threads calling
  // Charset.decode(), a potential performance problem.  It might
  // be better to remove the cache, or use ThreadLocal to cache on
  // a per-thread basis.
  public final synchronized CharBuffer decode (ByteBuffer bb)
  {
    try
      {
	if (cachedDecoder == null)
	  {
	    cachedDecoder = newDecoder ()
	      .onMalformedInput (CodingErrorAction.REPLACE)
	      .onUnmappableCharacter (CodingErrorAction.REPLACE);
	  } else
	  cachedDecoder.reset();

	return cachedDecoder.decode (bb);
      }
    catch (CharacterCodingException e)
      {
        throw new AssertionError (e);
      }
  }

  public final int compareTo (Object ob)
  {
    return canonicalName.compareToIgnoreCase (((Charset) ob).canonicalName);
  }

  public final int hashCode ()
  {
    return canonicalName.hashCode ();
  }

  public final boolean equals (Object ob)
  {
    if (ob instanceof Charset)
      return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName);
    else
      return false;
  }

  public final String toString ()
  {
    return canonicalName;
  }
}
