/**
*******************************************************************************
* Copyright (C) 1996-2005, International Business Machines Corporation and    *
* others. All Rights Reserved.                                                *
*******************************************************************************
*
*******************************************************************************
*/ 

package com.ibm.icu4jni.charset;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.HashMap;
import java.util.Map;

// BEGIN android-removed
// import com.ibm.icu4jni.common.ErrorCode;
// import com.ibm.icu4jni.converters.NativeConverter;
// END android-removed


public final class CharsetICU extends Charset{
    private String icuCanonicalName;
    /**
     * Constructor to create a the CharsetICU object
     * @param canonicalName the canonical name as a string
     * @param aliases the alias set as an array of strings
     * @stable ICU 2.4
     */
    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
         super(canonicalName,aliases);
         icuCanonicalName = icuCanonName;
        
    }
    /**
     * Returns a new decoder instance of this charset object
     * @return a new decoder object
     * @stable ICU 2.4
     */
    public CharsetDecoder newDecoder(){
        // the arrays are locals and not
        // instance variables since the
        // methods on this class need to 
        // be thread safe
        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
        return new CharsetDecoderICU(this,converterHandle);
    };
    
    // hardCoded list of replacement bytes
    private static final Map subByteMap = new HashMap();
    static{
        subByteMap.put("UTF-32",new byte[]{0x00, 0x00, (byte)0xfe, (byte)0xff});
        subByteMap.put("ibm-16684_P110-2003",new byte[]{0x40, 0x40}); // make \u3000 the sub char
        subByteMap.put("ibm-971_P100-1995",new byte[]{(byte)0xa1, (byte)0xa1}); // make \u3000 the sub char
    }
    /**
     * Returns a new encoder object of the charset
     * @return a new encoder
     * @stable ICU 2.4
     */
    public CharsetEncoder newEncoder(){
        // the arrays are locals and not
        // instance variables since the
        // methods on this class need to 
        // be thread safe
        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
        
        //According to the contract all converters should have non-empty replacement
        byte[] replacement = NativeConverter.getSubstitutionBytes(converterHandle);

       try{
            return new CharsetEncoderICU(this,converterHandle, replacement);
        }catch(IllegalArgumentException ex){
            // work around for the non-sensical check in the nio API that
            // a substitution character must be mappable while decoding!!
            replacement = (byte[])subByteMap.get(icuCanonicalName);
            if(replacement==null){
                replacement = new byte[NativeConverter.getMinBytesPerChar(converterHandle)];
                for(int i=0; i<replacement.length; i++){
                    replacement[i]= 0x3f;
                }
            }
            NativeConverter.setSubstitutionBytes(converterHandle, replacement, replacement.length);
            return new CharsetEncoderICU(this,converterHandle, replacement);
        }
    } 
    
    /**
     * Ascertains if a charset is a sub set of this charset
     * @param cs charset to test
     * @return true if the given charset is a subset of this charset
     * @stable ICU 2.4
     * 
     * //CSDL: major changes by Jack
     */
    public boolean contains(Charset cs){
        if (null == cs) {
        return false;
        } else if (this.equals(cs)) {
            return true;
        }
        
        long converterHandle1 = 0;
        long converterHandle2 = 0;

        try {
            converterHandle1 = NativeConverter.openConverter(this.name());
            if (converterHandle1 > 0) {
                converterHandle2 = NativeConverter.openConverter(cs.name());
                if (converterHandle2 > 0) {
                    return NativeConverter.contains(converterHandle1,
                            converterHandle2);
                }
            }
            return false;
        } finally {
            if (0 != converterHandle1) {
                NativeConverter.closeConverter(converterHandle1);
                if (0 != converterHandle2) {
                    NativeConverter.closeConverter(converterHandle2);
                }
            }
        }
    }
}


