/*
	Реализация спецификаций 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.util;

import malik.emulator.fileformats.*;

public class StringBuilder extends Object implements DataHolder
{
	public static int optimalCapacity(int length)
	{
		int result;
		if(length <= 7) return 7;
		for(result = length; length != 0; result |= (length >>>= 1));
		return result;
	}


	protected int length;
	protected char[] content;

	public StringBuilder()
	{
		this.content = new char[0x0f];
	}

	public StringBuilder(int initialCapacity)
	{
		this.content = new char[initialCapacity < 0x0f ? 0x0f : initialCapacity];
	}

	public String toString()
	{
		return new String(content, 0, length);
	}

	public void clear()
	{
		length = 0;
	}

	public void copy(int beginPosition, int endPosition, char[] dst, int offset)
	{
		int len = length;
		int length;
		if(beginPosition < 0 || beginPosition > len)
		{
			throw new StringIndexOutOfBoundsException("StringBuilder.copy: аргумент beginPosition выходит из диапазона.");
		}
		if(endPosition < beginPosition || endPosition > len)
		{
			throw new StringIndexOutOfBoundsException("StringBuilder.copy: аргумент endPosition выходит из диапазона.");
		}
		if(dst == null)
		{
			throw new NullPointerException("StringBuilder.copy: аргумент dst равен нулевой ссылке.");
		}
		Array.checkBound("StringBuilder.copy", dst.length, offset, length = endPosition - beginPosition);
		if(length > 0)
		{
			Array.copy(content, beginPosition, dst, offset, length);
		}
	}

	public void set(int position, char character)
	{
		if(position < 0 || position >= length)
		{
			throw new StringIndexOutOfBoundsException("StringBuilder.set: аргумент position выходит из диапазона.");
		}
		content[position] = character;
	}

	public char get(int position)
	{
		if(position < 0 || position >= length)
		{
			throw new StringIndexOutOfBoundsException("StringBuilder.get: аргумент position выходит из диапазона.");
		}
		return content[position];
	}

	public StringBuilder insert(int position, boolean value)
	{
		insertString(position, value ? "true" : "false");
		return this;
	}

	public StringBuilder insert(int position, char value)
	{
		insertChar(position, value);
		return this;
	}

	public StringBuilder insert(int position, float value)
	{
		insertString(position, Float.toString(value));
		return this;
	}

	public StringBuilder insert(int position, double value)
	{
		insertString(position, Double.toString(value));
		return this;
	}

	public StringBuilder insert(int position, int value)
	{
		insertString(position, Integer.toString(value, 10));
		return this;
	}

	public StringBuilder insert(int position, int value, int radix, boolean upperCase)
	{
		String string = Integer.toString(value, radix);
		insertString(position, upperCase ? string.toUpperCase() : string);
		return this;
	}

	public StringBuilder insert(int position, long value)
	{
		insertString(position, Long.toString(value, 10));
		return this;
	}

	public StringBuilder insert(int position, long value, int radix, boolean upperCase)
	{
		String string = Long.toString(value, radix);
		insertString(position, upperCase ? string.toUpperCase() : string);
		return this;
	}

	public StringBuilder insert(int position, char[] src)
	{
		if(src != null)
		{
			insertArray(position, src, 0, src.length);
		}
		return this;
	}

	public StringBuilder insert(int position, char[] src, int offset, int length)
	{
		if(src != null)
		{
			long bound;
			offset = (int) (bound = Array.intersectBound(src.length, offset, length));
			length = (int) (bound >> 32);
			insertArray(position, src, offset, length);
		}
		return this;
	}

	public StringBuilder insert(int position, Object value)
	{
		String string;
		if(value != null && (string = value.toString()) != null)
		{
			insertString(position, string);
		}
		return this;
	}

	public StringBuilder insert(int position, String value)
	{
		if(value != null)
		{
			insertString(position, value);
		}
		return this;
	}

	public StringBuilder append(boolean value)
	{
		appendString(value ? "true" : "false");
		return this;
	}

	public StringBuilder append(char value)
	{
		appendChar(value);
		return this;
	}

	public StringBuilder append(float value)
	{
		appendString(Float.toString(value));
		return this;
	}

	public StringBuilder append(double value)
	{
		appendString(Double.toString(value));
		return this;
	}

	public StringBuilder append(int value)
	{
		appendString(Integer.toString(value, 10));
		return this;
	}

	public StringBuilder append(int value, int radix, boolean upperCase)
	{
		String string = Integer.toString(value, radix);
		appendString(upperCase ? string.toUpperCase() : string);
		return this;
	}

	public StringBuilder append(long value)
	{
		appendString(Long.toString(value, 10));
		return this;
	}

	public StringBuilder append(long value, int radix, boolean upperCase)
	{
		String string = Long.toString(value, radix);
		appendString(upperCase ? string.toUpperCase() : string);
		return this;
	}

	public StringBuilder append(char[] src)
	{
		if(src != null)
		{
			appendArray(src, 0, src.length);
		}
		return this;
	}

	public StringBuilder append(char[] src, int offset, int length)
	{
		if(src != null)
		{
			long bound;
			offset = (int) (bound = Array.intersectBound(src.length, offset, length));
			length = (int) (bound >> 32);
			appendArray(src, offset, length);
		}
		return this;
	}

	public StringBuilder append(Object value)
	{
		String string;
		if(value != null && (string = value.toString()) != null)
		{
			appendString(string);
		}
		return this;
	}

	public StringBuilder append(String value)
	{
		if(value != null)
		{
			appendString(value);
		}
		return this;
	}

	public StringBuilder delete(int position)
	{
		deletePortion(position, position + 1);
		return this;
	}

	public StringBuilder delete(int beginPosition, int endPosition)
	{
		deletePortion(beginPosition, endPosition);
		return this;
	}

	public final boolean isEmpty()
	{
		return length <= 0;
	}

	public final int capacity()
	{
		return content.length;
	}

	public final int length()
	{
		return length;
	}

	protected void insertChar(int position, char character)
	{
		int oldLength = this.length;
		int newLength = 1 + oldLength;
		char[] content = madeLarger(newLength);
		if(position < 0) position = 0;
		if(position > oldLength) position = oldLength;
		if(position < oldLength)
		{
			Array.copy(content, position, content, position + 1, oldLength - position);
		}
		content[position] = character;
		this.length = newLength;
	}

	protected void insertArray(int position, char[] src, int offset, int length)
	{
		int oldLength = this.length;
		int newLength = length + oldLength;
		char[] content = madeLarger(newLength);
		if(position < 0) position = 0;
		if(position > oldLength) position = oldLength;
		if(position < oldLength)
		{
			Array.copy(content, position, content, position + length, oldLength - position);
		}
		Array.copy(src, offset, content, position, length);
		this.length = newLength;
	}

	protected void insertString(int position, String string)
	{
		int length = string.length();
		int oldLength = this.length;
		int newLength = length + oldLength;
		char[] content = madeLarger(newLength);
		if(position < 0) position = 0;
		if(position > oldLength) position = oldLength;
		if(position < oldLength)
		{
			Array.copy(content, position, content, position + length, oldLength - position);
		}
		string.getChars(0, length, content, position);
		this.length = newLength;
	}

	protected void appendChar(char character)
	{
		int oldLength = this.length;
		int newLength = 1 + oldLength;
		madeLarger(newLength)[oldLength] = character;
		this.length = newLength;
	}

	protected void appendArray(char[] src, int offset, int length)
	{
		int oldLength = this.length;
		int newLength = length + oldLength;
		Array.copy(src, offset, madeLarger(newLength), oldLength, length);
		this.length = newLength;
	}

	protected void appendString(String string)
	{
		int length = string.length();
		int oldLength = this.length;
		int newLength = length + oldLength;
		string.getChars(0, length, madeLarger(newLength), oldLength);
		this.length = newLength;
	}

	protected void deletePortion(int beginPosition, int endPosition)
	{
		int oldLength = length;
		if(beginPosition < 0) beginPosition = 0;
		if(beginPosition > oldLength) beginPosition = oldLength;
		if(endPosition < beginPosition) endPosition = beginPosition;
		if(endPosition > oldLength) endPosition = oldLength;
		if(beginPosition < endPosition)
		{
			char[] buffer;
			Array.copy(buffer = content, endPosition, buffer, beginPosition, oldLength - endPosition);
			this.length = oldLength - (endPosition - beginPosition);
		}
	}

	private char[] madeLarger(int length)
	{
		int oldLength;
		char[] result;
		if(length > (oldLength = (result = content).length))
		{
			Array.copy(result, 0, result = content = new char[optimalCapacity(length)], 0, oldLength);
		}
		return result;
	}
}
