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

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

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

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

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


package javax.microedition.lcdui;

import malik.emulator.media.graphics.*;

public class CharList extends ScrollingScreen
{
	private int focusedCharIndex;
	private int charSize;
	private char[] chars;
	private Font font;
	private Object lock;

	public CharList(boolean fullScreenMode, String title, Ticker ticker,
			Command[] commands, Command defaultCommand, CommandListener listener,
			char[] chars)
	{
		super(true, fullScreenMode, title, ticker, commands, defaultCommand, listener, HORIZONTAL);
		int len;
		char[] c;
		Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
		if(chars == null)
		{
			c = new char[0];
		} else
		{
			Array.copy(chars, 0, c = new char[len = chars.length], 0, len);
		}
		this.charSize = ((3 * font.getHeight()) >> 1) + 1;
		this.chars = c;
		this.font = font;
		this.lock = new Object();
	}

	public void setChars(char[] chars)
	{
		int len;
		char[] c;
		synchronized(lock)
		{
			if(chars == null)
			{
				c = new char[len = 0];
			} else
			{
				Array.copy(chars, 0, c = new char[len = chars.length], 0, len);
			}
			this.chars = c;
			if(focusedCharIndex >= len)
			{
				focusedCharIndex = Math.max(0, len - 1);
			}
			correctScrollBarRange(getHeight());
		}
	}

	public void setSelectedIndex(int selected)
	{
		int error = 0;
		synchronized(lock)
		{
			label0:
			{
				if(selected < 0 || selected >= chars.length)
				{
					error = 1;
					break label0;
				}
				focusedCharIndex = selected;
				correctScrollBarPositionToChar();
			}
		}
		if(error == 1)
		{
			throw new IndexOutOfBoundsException("CharList.setSelectedIndex: " +
					"параметр selected выходит из диапазона.");
		}
	}

	public char getChar(int index)
	{
		char result;
		int error;
		char[] c;
		error = 0;
		synchronized(lock)
		{
			label0:
			{
				if(index < 0 || index >= (c = chars).length)
				{
					error = 1;
					result = 0;
					break label0;
				}
				result = c[index];
			}
		}
		if(error == 1)
		{
			throw new IndexOutOfBoundsException("CharList.getChar: " +
					"параметр index выходит из диапазона.");
		}
		return result;
	}

	public int getSelectedIndex()
	{
		return focusedCharIndex;
	}

	public int size()
	{
		return chars.length;
	}

	void paint(Graphics render, ScrollBar horzScrollBar, ScrollBar vertScrollBar)
	{
		int i;
		int t;
		int x;
		int y;
		int len;
		int size;
		int left;
		int right;
		int focused;
		int charsPerColumn;
		char[] c;
		Font font;
		t = ((size = charSize) - (font = this.font).getHeight()) >> 1;
		x = 0;
		y = 0;
		right = (left = horzScrollBar.getPosition()) + horzScrollBar.getPage();
		render.setColor(RasterCanvas.getSystemColor(0x28));
		render.setFont(font);
		synchronized(lock)
		{
			len = (c = chars).length;
			focused = focusedCharIndex;
			charsPerColumn = Math.max(1, getHeight() / size);
			for(i = 0; i < len; )
			{
				label0:
				{
					if(x >= right || x + size <= left)
					{
						break label0;
					}
					if(i == focused)
					{
						render.drawElementOfGUI(1, 0, 0, x, y, size, size);
					}
					render.drawChar(c[i], x + (size >> 1) - 1, y + t,
							Graphics.HCENTER | Graphics.TOP);
				}
				if(++i % charsPerColumn == 0)
				{
					x += size;
					y = 0;
				} else
				{
					y += size;
				}
			}
		}
	}

	void onKeyPressed(int key, int charCode)
	{
		if(!super.keyHandling(key))
		{
			moveCursor(key);
			return;
		}
		super.onKeyPressed(key, charCode);
	}

	void onKeyRepeated(int key, int charCode)
	{
		if(!super.keyHandling(key))
		{
			moveCursor(key);
			return;
		}
		super.onKeyRepeated(key, charCode);
	}

	void onClientPointerPressed(int x, int y, int button)
	{
		pointerHandle(x, y);
	}

	void onClientPointerDragged(int x, int y)
	{
		pointerHandle(x, y);
	}

	void onClientPointerReleased(int x, int y, int button)
	{
		pointerHandle(x, y);
	}

	void onSizeChanged(int width, int height)
	{
		correctScrollBarRange(height);
		super.onSizeChanged(width, height);
	}

	private void moveCursor(int key)
	{
		int len;
		int focused;
		int charsPerColumn;
		MIDletProxy proxy;
		if(key == (proxy = MIDletProxy.getInstance()).getKeyUsedAs(MIDletProxy.DEVICE_KEY_UP))
		{
			synchronized(lock)
			{
				if((len = chars.length) > 0)
				{
					focusedCharIndex = (focusedCharIndex + len - 1) % len;
					correctScrollBarPositionToChar();
				}
			}
			return;
		}
		if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_DOWN))
		{
			synchronized(lock)
			{
				if((len = chars.length) > 0)
				{
					focusedCharIndex = (focusedCharIndex + 1) % len;
					correctScrollBarPositionToChar();
				}
			}
			return;
		}
		if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_LEFT))
		{
			synchronized(lock)
			{
				if((focused = focusedCharIndex) >= (charsPerColumn =
						Math.max(1, getHeight() / charSize)))
				{
					focusedCharIndex = focused - charsPerColumn;
					correctScrollBarPositionToChar();
				}
			}
			return;
		}
		if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_RIGHT))
		{
			synchronized(lock)
			{
				if((focused = focusedCharIndex) < chars.length - (charsPerColumn =
						Math.max(1, getHeight() / charSize)))
				{
					focusedCharIndex = focused + charsPerColumn;
					correctScrollBarPositionToChar();
				}
			}
		}
	}

	private void pointerHandle(int x, int y)
	{
		int col;
		int row;
		int size;
		int index;
		int charsPerColumn;
		synchronized(lock)
		{
			size = charSize;
			col = x / size;
			row = y / size;
			charsPerColumn = Math.max(1, getHeight() / size);
			if((index = row + col * charsPerColumn) >= 0 && index < chars.length)
			{
				focusedCharIndex = index;
				correctScrollBarPositionToChar();
			}
		}
	}

	private void correctScrollBarRange(int height)
	{
		int len = chars.length;
		int size = charSize;
		int charsPerColumn = Math.max(1, height / size);
		getHorzScrollBar().setRange(size * ((len / charsPerColumn) +
				(len % charsPerColumn == 0 ? 0 : 1)));
	}

	private void correctScrollBarPositionToChar()
	{
		int pos;
		int need;
		int size = charSize;
		int charsPerColumn = Math.max(1, getHeight() / size);
		int focusedColumn = focusedCharIndex / charsPerColumn;
		ScrollBar scrollbar = getHorzScrollBar();
		if((pos = scrollbar.getPosition()) > (need = focusedColumn * size))
		{
			scrollbar.setPosition(need);
		}
		else if(pos < (need -= scrollbar.getPage() - size))
		{
			scrollbar.setPosition(need);
		}
		callSeriallyPaintScreen(CLIENT);
	}
}
