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

import javax.microedition.lcdui.*;

public class TextOutputMultilinedColor extends TextOutputMultilinedExt
{
	private static int getColorIndex(int[] colorsData, int colorsLength, int charIndex)
	{
		int result;
		int positionA;
		int positionB;
		int posApprox;
		int charIndexApprox;
		positionA = 0;
		positionB = (colorsLength >> 1) - 1;
		do
		{
			posApprox = (positionA + positionB) >> 1;
			charIndexApprox = colorsData[posApprox << 1];
			if(positionA == positionB)
			{
				break;
			}
			if(charIndex < charIndexApprox)
			{
				if((positionB = posApprox - 1) < positionA)
				{
					positionB = positionA;
				}
			}
			else if(charIndex > charIndexApprox)
			{
				if((positionA = posApprox + 1) > positionB)
				{
					positionA = positionB;
				}
			}
			else
			{
				break;
			}
		} while(true);
		return colorsData[result = posApprox << 1] > charIndex ? result - 2 : result;
	}


	private int maximumLines;
	private int color;
	private int colorsLength;
	private int[] colorsData;

	public TextOutputMultilinedColor(int capacity, int maximumLines, int color)
	{
		super(capacity);
		this.maximumLines = maximumLines;
		this.color = color;
		this.colorsLength = 3;
		this.colorsData = new int[] {
				0, color, 0
		};
	}

	public void clear()
	{
		int[] c;
		super.clear();
		colorsLength = 3;
		(c = colorsData)[0] = 0;
		c[1] = color;
		c[2] = 0;
	}

	public void setText(String text)
	{
		int[] c;
		super.setText(text);
		colorsLength = 3;
		(c = colorsData)[0] = 0;
		c[1] = color;
		c[2] = text != null ? text.length() : 0;
	}

	public void append(String data)
	{
		super.append(data);
		append(data != null ? data.length() : 0);
	}

	public void append(char[] data, int offset, int length)
	{
		super.append(data, offset, length);
		append(length);
	}

	public void append(int data, int radix, boolean upperCase)
	{
		int length = this.length;
		super.append(data, radix, upperCase);
		append(this.length - length);
	}

	public void setColor(int color)
	{
		int len;
		int[] c;
		this.color = color;
		if((c = colorsData)[len = colorsLength - 3] == c[len + 2])
		{
			c[len + 1] = color;
		}
	}

	public void deleteStartLines()
	{
		int linesForDelete;
		int charsForDelete;
		int i;
		int lc;
		int len;
		char[] ac;
		int[] l;
		int[] c;
		if((linesForDelete = (lc = linesCount) - maximumLines) <= 0 ||
				(charsForDelete = (l = linesBounds)[linesForDelete << 1]) <= 0)
		{
			return;
		}
		if(charsForDelete >= length)
		{
			clear();
			return;
		}
		for(len = colorsLength - 2, c = colorsData, i = 0; i < len; i += 2)
		{
			if(charsForDelete >= c[i] && charsForDelete < c[i + 2])
			{
				c[i] = charsForDelete;
				Array.copy(c, i, c, 0, len -= i - 2);
				for(i = 0; i < len; i += 2)
				{
					c[i] -= charsForDelete;
				}
				colorsLength = len;
				break;
			}
		}
		Array.copy(l, linesForDelete << 1, l, 0, len = ((lc -= linesForDelete) << 1) + 1);
		for(i = 0; i < len; i += 2)
		{
			l[i] -= charsForDelete;
		}
		linesCount = lc;
		Array.copy(ac = chars, charsForDelete, ac, 0, len = length - charsForDelete);
		length = len;
	}

	public void paintLines(Graphics render, int left, int top, int lineStart, int linesCount)
	{
		int lim;
		int len;
		int llim;
		int llen;
		int cidx;
		int clen;
		int rlen;
		int i;
		int j;
		int x;
		int y;
		int h;
		char[] ac;
		int[] l;
		int[] c;
		Font f;
		if((lim = lineStart + linesCount) > (len = this.linesCount) ||
				lim < lineStart || lineStart > len || lineStart < 0)
		{
			throw new IndexOutOfBoundsException("TextOutputMultilinedColor.paintLines: " +
					"индекс выходит из диапазона.");
		}
		ac = chars;
		l = linesBounds;
		c = colorsData;
		len = colorsLength;
		h = (f = render.getFont()).getHeight();
		y = top;
		for(i = lineStart; i < lim; i++)
		{
			x = left;
			for(llim = (j = l[llim = i << 1]) + (llen = l[llim + 1]); j < llim; j += rlen)
			{
				cidx = getColorIndex(c, len, j);
				clen = c[cidx + 2] - j;
				if((rlen = llen < clen ? llen : clen) <= 0)
				{
					break;
				}
				llen -= rlen;
				render.setColor(c[cidx + 1]);
				render.drawChars(ac, j, rlen, x, y, Graphics.LEFT | Graphics.TOP);
				x += f.charsWidth(ac, j, rlen);
			}
			y += h;
		}
	}

	private void append(int charsCount)
	{
		int col;
		int len;
		int[] c;
		if(charsCount <= 0)
		{
			return;
		}
		if((c = colorsData)[(len = colorsLength - 1) - 1] == (col = color))
		{
			c[len] += charsCount;
			return;
		}
		if(++len == c.length)
		{
			Array.copy(c, 0, c = colorsData = new int[(len << 1) + 1], 0, len);
		}
		c[len++] = col;
		c[len++] = c[len - 3] + charsCount;
		colorsLength = len;
	}
}
