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

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

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

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

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


package malik.emulator.i18n;

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

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 final String ENCODING_INTERNAL_NAME_ISO8859_5 = "ISO8859_5";
	private static final Codec SYSTEM_CODEC;

	static
	{
		SYSTEM_CODEC = new UTF_8_Codec();
	}

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

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

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

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

	public static Reader getStreamReader(InputStream stream)
	{
		return ((StreamReader) (new UTF_8_Reader())).open(stream);
	}

	public static Reader getStreamReader(InputStream stream, String encoding)
			throws UnsupportedEncodingException
	{
		return getReader(encoding).open(stream);
	}

	public static Writer getStreamWriter(OutputStream stream)
	{
		return ((StreamWriter) (new UTF_8_Writer())).open(stream);
	}

	public static Writer getStreamWriter(OutputStream stream, String encoding)
			throws UnsupportedEncodingException
	{
		return getWriter(encoding).open(stream);
	}

	private static char normalizeEncodingChar(char c)
	{
		return c == '-' || c == ':' || c == 32 ? '_' : Character.toUpperCase(c);
	}

	private static String normalizeEncodingName(String encoding)
	{
		char c;
		int i;
		int len;
		char[] buf;
		String val;
		if(encoding == null || encoding.length() == 0)
		{
			encoding = "UTF_8";
		}
		len = (val = encoding.trim()).length();
		for(i = 0; i < len && (c = val.charAt(i)) == normalizeEncodingChar(c); i++);
		if(i < len)
		{
			for(buf = val.toCharArray(); i < len; i++)
			{
				buf[i] = normalizeEncodingChar(buf[i]);
			}
			return new String(buf);
		}
		return val;
	}

	private static String getInternalName(String encoding)
	{
		String prop;
		String result = normalizeEncodingName(encoding);
		if("US_ASCII".equals(result) || "ISO_8859_1".equals(result) ||
				"CP1252".equals(result) || "CP_1252".equals(result) ||
				"WINDOWS_1252".equals(result))
		{
			return ENCODING_INTERNAL_NAME_ISO8859_1;
		}
		if("ISO_8859_5".equals(result))
		{
			return ENCODING_INTERNAL_NAME_ISO8859_5;
		}
		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(8));
		}
		if(result.startsWith("WINDOWS"))
		{
			return "CP".concat(result.substring(7));
		}
		return (prop = System.getSystemProperty(result.concat("_InternalEncodingName"))) != null ?
				prop : result;
	}

	private static Codec getCodec(String encoding)
			throws UnsupportedEncodingException
	{
		Codec result;
		String className = "malik.emulator.i18n.encoding." +
				(encoding = getInternalName(encoding)) + "_Codec";
		try
		{
			result = (Codec) Class.forName(className).newInstance();
		}
		catch(Exception e)
		{
			throw new UnsupportedEncodingException("Кодировка " +
					encoding + " не поддерживается.");
		}
		return result;
	}

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

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


	private Helper()
	{
	}
}
