/*
    Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
    и других спецификаций для функционирования компактных приложений на языке
    Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package malik.emulator.i18n;

import java.io.*;
import malik.emulator.i18n.encoding.system.*;
import malik.emulator.util.*;

public final class Helper extends Object
{
    private static final String ENCODING_INTERNAL_NAME_UTF_8 = "system.UTF_8";
    private static final String ENCODING_INTERNAL_NAME_ISO8859_1 = "ISO8859_1";

    private static TextCodec SYSTEM_TEXT_CODEC;

    /* Нельзя добавлять метод static{…} сюда. */

    public static char[] byteToCharArray(byte[] src, int offset, int length) {
        return getSystemTextCodecInstance().decode(src, offset, length);
    }

    public static char[] byteToCharArray(byte[] src, int offset, int length, String encoding) throws UnsupportedEncodingException {
        return createTextCodec(encoding).decode(src, offset, length);
    }

    public static byte[] charToByteArray(char[] src, int offset, int length) {
        return getSystemTextCodecInstance().encode(src, offset, length);
    }

    public static byte[] charToByteArray(char[] src, int offset, int length, String encoding) throws UnsupportedEncodingException {
        return createTextCodec(encoding).encode(src, offset, length);
    }

    public static TextCodec createTextCodec() {
        return new UTF_8_Codec();
    }

    public static TextCodec createTextCodec(String encoding) throws UnsupportedEncodingException {
        TextCodec result;
        String className = (new StringBuilder()).append("malik.emulator.i18n.encoding.").append(getInternalEncodingName(encoding)).append("_Codec").toString();
        try
        {
            result = (TextCodec) Class.forName(className).newInstance();
        }
        catch(Exception e)
        {
            throw new UnsupportedEncodingException((new StringBuilder()).append("Кодировка ").append(encoding).append(" не поддерживается системой.").toString());
        }
        return result;
    }

    public static Reader createReader(InputStream stream) {
        return ((StreamReader) (new UTF_8_Reader())).setInputStream(stream);
    }

    public static Reader createReader(InputStream stream, String encoding) throws UnsupportedEncodingException {
        return createStreamReader(encoding).setInputStream(stream);
    }

    public static Writer createWriter(OutputStream stream) {
        return ((StreamWriter) (new UTF_8_Writer())).setOutputStream(stream);
    }

    public static Writer createWriter(OutputStream stream, String encoding) throws UnsupportedEncodingException {
        return createStreamWriter(encoding).setOutputStream(stream);
    }

    private static char normalizeEncodingCharacter(char character) {
        return
            character <= '\u002f' || character >= '\u003a' && character <= '\u0040' || character >= '\u005b' && character <= '\u0060' || character >= '\u007b' ? '_' : Character.toUpperCase(character)
        ;
    }

    private static String normalizeEncodingName(String encoding) {
        char character;
        int length;
        int i;
        char[] buf;
        if((length = encoding == null ? 0 : (encoding = encoding.trim()).length()) <= 0) length = (encoding = "UTF_8").length();
        for(i = 0; i < length && (character = encoding.charAt(i)) == normalizeEncodingCharacter(character); i++);
        if(i >= length) return encoding;
        for(buf = encoding.toCharArray(); i < length; i++) buf[i] = normalizeEncodingCharacter(buf[i]);
        return new String(buf);
    }

    private static StreamReader createStreamReader(String encoding) throws UnsupportedEncodingException {
        StreamReader result;
        String className = (new StringBuilder()).append("malik.emulator.i18n.encoding.").append(getInternalEncodingName(encoding)).append("_Reader").toString();
        try
        {
            result = (StreamReader) Class.forName(className).newInstance();
        }
        catch(Exception e)
        {
            throw new UnsupportedEncodingException((new StringBuilder()).append("Кодировка ").append(encoding).append(" не поддерживается системой.").toString());
        }
        return result;
    }

    private static StreamWriter createStreamWriter(String encoding) throws UnsupportedEncodingException {
        StreamWriter result;
        String className = (new StringBuilder()).append("malik.emulator.i18n.encoding.").append(getInternalEncodingName(encoding)).append("_Writer").toString();
        try
        {
            result = (StreamWriter) Class.forName(className).newInstance();
        }
        catch(Exception e)
        {
            throw new UnsupportedEncodingException((new StringBuilder()).append("Кодировка ").append(encoding).append(" не поддерживается системой.").toString());
        }
        return result;
    }

    private static String getInternalEncodingName(String encoding) {
        String value;
        String result = normalizeEncodingName(encoding);
        if(
            "ASCII".equals(result) || "US_ASCII".equals(result) || "ISO_8859_1".equals(result) || "CP_1252".equals(result) ||
            "CP1252".equals(result) || "WINDOWS_1252".equals(result) || "WINDOWS1252".equals(result)
        ) return ENCODING_INTERNAL_NAME_ISO8859_1;
        if("UTF8".equals(result) || "UTF_8".equals(result)) return ENCODING_INTERNAL_NAME_UTF_8;
        if(result.startsWith("CP_")) return "CP".concat(result.substring(3));
        if(result.startsWith("WINDOWS")) return "CP".concat(result.substring(7));
        if(result.startsWith("WINDOWS_")) return "CP".concat(result.substring(8));
        if(result.startsWith("ISO_8859_")) return "ISO8859_".concat(result.substring(9));
        return (value = System.getSystemProperty(result.concat("_InternalEncodingName"))) != null ? value : result;
    }

    private static TextCodec getSystemTextCodecInstance() {
        return SYSTEM_TEXT_CODEC == null ? SYSTEM_TEXT_CODEC = new UTF_8_Codec() : SYSTEM_TEXT_CODEC;
    }

    private Helper() {
    }
}
