/* 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 gnu.java.nio.charset.iconv.IconvProvider;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.spi.CharsetProvider;
import java.util.Collections;
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
 * @status updated to 1.5
 */
public abstract class Charset implements Comparable<Charset>
{
  private CharsetEncoder cachedEncoder;
  private CharsetDecoder cachedDecoder;
  
  /**
   * Extra 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 the Charset instance for the indicated charset
   * @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<String, Charset> availableCharsets()
  {
    TreeMap<String, Charset> charsets
      = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    for (Iterator<Charset> i = provider().charsets(); i.hasNext(); )
      {
	Charset cs = i.next();
	charsets.put(cs.name(), cs);
      }

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

    return Collections.unmodifiableSortedMap(charsets);
  }

  private static CharsetProvider provider()
  {
    String useIconv = SystemProperties.getProperty
      ("gnu.classpath.nio.charset.provider.iconv");

    if (useIconv != null)
      return IconvProvider.provider();

    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<String> aliases ()
  {
    if (aliases == null)
      return Collections.<String>emptySet();

    // should we cache the aliasSet instead?
    int n = aliases.length;
    HashSet<String> aliasSet = new HashSet<String> (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 (Charset other)
  {
    return canonicalName.compareToIgnoreCase (other.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;
  }
}
