/*
	Реализация спецификаций 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 Gauge extends Item
{
	public static final int INDEFINITE = -1;
	public static final int CONTINUOUS_IDLE = 0;
	public static final int INCREMENTAL_IDLE = 1;
	public static final int CONTINUOUS_RUNNING = 2;
	public static final int INCREMENTAL_UPDATING = 3;
	private static final int TRACK_HEIGHT;
	private static final int THUMB_WIDTH;
	private static final int THUMB_HEIGHT;
	private static final Font FONT;

	static
	{
		int b;
		int c = RasterCanvas.getElementOfGUISizes(11, 0, 0);
		TRACK_HEIGHT = (b = RasterCanvas.getElementOfGUISizes(11, 3, 0) >> 16) == -1 ? 8 : b;
		THUMB_WIDTH = (b = (short) c) == -1 ? 8 : b;
		THUMB_HEIGHT = (b = c >> 16) == -1 ? 16 : b;
		FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
	}


	private boolean controlFocused;
	private boolean sliderFocused;
	private boolean interactive;
	private boolean newInput;
	private boolean pressed;
	private int contentWidth;
	private int argument;
	private long fields;
	private TextOutput output;

	public Gauge(String label, boolean interactive, int maximum, int position)
	{
		this(LAYOUT_DEFAULT, -1, -1, label, null, null, null, interactive, maximum, position);
	}

	public Gauge(int layout, int lockedWidth, int lockedHeight, String label,
			Command[] commands, Command defaultCommand, ItemCommandListener listener,
			boolean interactive, int maximum, int position)
	{
		super(layout, lockedWidth, lockedHeight, label, commands, defaultCommand, listener);
		boolean f;
		if((f = interactive || maximum != INDEFINITE) ?
				maximum <= 0 : (position < 0 || position > 3))
		{
			throw new IllegalArgumentException("Gauge: " +
					"неправильные параметры для создания полосы прогресса.");
		}
		if(f)
		{
			position = position < 0 ? 0 : (position > maximum ? maximum : position);
		}
		this.interactive = interactive;
		this.newInput = true;
		this.fields = (((long) maximum) << 32) | (long) position;
		this.output = interactive ? new TextOutput(23) : null;
	}

	public void setMaxValue(int maximum)
	{
		boolean needPaint;
		int position;
		int current;
		long fields;
		position = (int) (fields = this.fields);
		current = (int) (fields >> 32);
		if(interactive)
		{
			if(maximum <= 0)
			{
				throw new IllegalArgumentException("Gauge.setMaxValue: " +
						"параметр maximum для интерактивной полосы прогресса может быть " +
						"только положительным.");
			}
		} else
		{
			if(maximum <= 0 && maximum != INDEFINITE)
			{
				throw new IllegalArgumentException("Gauge.setMaxValue: " +
						"параметр maximum для неинтерактивной полосы прогресса может быть " +
						"положительным или равняться специальному значению INDEFINITE.");
			}
			if(current > 0 && maximum == INDEFINITE)
			{
				setFields(INDEFINITE, CONTINUOUS_IDLE);
				notifyPaint();
				return;
			}
			if(current == INDEFINITE)
			{
				if(maximum > 0)
				{
					if(isVisible() && position == CONTINUOUS_RUNNING)
					{
						stopUpdating();
					}
					setFields(maximum, 0);
					notifyPaint();
				}
				return;
			}
		}
		needPaint = false;
		if(position > maximum)
		{
			needPaint = true;
			position = maximum;
		}
		if(current != maximum || needPaint)
		{
			setFields(maximum, position);
			notifyPaint();
		}
	}

	public void setValue(int position)
	{
		int current;
		int maximum;
		long fields;
		current = (int) (fields = this.fields);
		maximum = (int) (fields >> 32);
		if(interactive || maximum != INDEFINITE)
		{
			position = position < 0 ? 0 : (position > maximum ? maximum : position);
		}
		else if(position < 0 || position > 3)
		{
			throw new IllegalArgumentException("Gauge.setValue: " +
					"недопустимое значение параметра position для неинтерактивной " +
					"неопределённой полосы прогресса.");
		}
		if(current != position)
		{
			if(isVisible() && maximum == INDEFINITE)
			{
				if(position == CONTINUOUS_RUNNING)
				{
					startUpdating();
				} else
				{
					stopUpdating();
				}
			}
			setFields(maximum, position);
			notifyPaint();
		}
	}

	public boolean isInteractive()
	{
		return interactive;
	}

	public int getMaxValue()
	{
		return (int) (fields >> 32);
	}

	public int getValue()
	{
		return (int) fields;
	}

	void paintContent(Graphics render, int contentWidth, int contentHeight)
	{
		boolean focused;
		double dtw;
		int itw;
		int i;
		int len;
		int position;
		int maximum;
		long fields;
		char[] chars;
		TextOutput output;
		focused = controlFocused;
		position = (int) (fields = this.fields);
		maximum = (int) (fields >> 32);
		if(interactive)
		{
			(output = this.output).clear();
			output.append(position, 10, true);
			output.append(" / ");
			output.append(maximum, 10, true);
			chars = output.getChars();
			len = output.getLength();
			render.drawElementOfGUI(11, 3, focused ? 1 : 0,
					(THUMB_WIDTH / 2) - 1, (THUMB_HEIGHT - TRACK_HEIGHT) / 2,
					contentWidth - THUMB_WIDTH + 2, TRACK_HEIGHT);
			render.drawElementOfGUI(11, 0, focused ? (pressed ? 1 : 3) : 0,
					(int) (((long) position) * ((long) (contentWidth - THUMB_WIDTH)) /
					(long) maximum), 0, THUMB_WIDTH, THUMB_HEIGHT);
			render.setFont(FONT);
			render.setColor(RasterCanvas.getSystemColor(0x28));
			render.drawChars(chars, 0, len,
					Math.max(contentWidth - FONT.charsWidth(chars, 0, len), 0), THUMB_HEIGHT,
					Graphics.LEFT | Graphics.TOP);
			return;
		}
		if(maximum > 0)
		{
			render.drawElementOfGUI(9, 0, 0, 0, 0, contentWidth, contentHeight);
			render.drawElementOfGUI(9, 1, 0, 2, 2,
					(int) (((long) position) * ((long) (contentWidth - 4)) / (long) maximum),
					contentHeight - 4);
			return;
		}
		switch(position)
		{
		default:
			return;
		case CONTINUOUS_IDLE:
		case INCREMENTAL_IDLE:
			itw = (int) (dtw = (1.d / 7.d) * ((double) (contentWidth - 4)));
			render.drawElementOfGUI(9, 0, 0, 0, 0, contentWidth, contentHeight);
			for(i = 1; i < 7; i += 2)
			{
				render.drawElementOfGUI(9, 1, 0, ((int) (dtw * (double) i)) + 2, 2,
						itw, contentHeight - 4);
			}
			return;
		case CONTINUOUS_RUNNING:
			itw = (contentWidth - 4) / 5;
			render.drawElementOfGUI(9, 0, 0, 0, 0, contentWidth, contentHeight);
			render.drawElementOfGUI(9, 1, 0,
					((int) Math.round(0.5d * ((double) (contentWidth - itw - 4)) *
					(1.d + Math.sin((0.0625d * Math.PI) * (double) argument)))) + 2, 2,
					itw, contentHeight - 4);
			return;
		case INCREMENTAL_UPDATING:
			itw = (contentWidth - 4) / 5;
			render.drawElementOfGUI(9, 0, 0, 0, 0, contentWidth, contentHeight);
			render.drawElementOfGUI(9, 1, 0, ((contentWidth - itw - 4) / 2) + 2, 2,
					itw, contentHeight - 4);
			return;
		}
	}

	void onUpdate()
	{
		argument = (argument + 1) & 0x1f;
	}

	void onShow()
	{
		if(fields == ((((long) INDEFINITE) << 32) | (long) CONTINUOUS_RUNNING))
		{
			startUpdating();
		}
	}

	void onHide()
	{
		if(fields == ((((long) INDEFINITE) << 32) | (long) CONTINUOUS_RUNNING))
		{
			stopUpdating();
		}
	}

	void onSizeChanged(int contentWidth, int contentHeight)
	{
		this.contentWidth = contentWidth;
	}

	void onKeyPressed(int key, int charCode)
	{
		keyHandle(key);
	}

	void onKeyRepeated(int key, int charCode)
	{
		keyHandle(key);
	}

	void onContentPointerPressed(int x, int y, int button)
	{
		int l;
		int newPos;
		int position;
		int maximum;
		long fields;
		if((!interactive) || button != MIDletProxy.BUTTON_MAIN)
		{
			return;
		}
		if(y < THUMB_HEIGHT)
		{
			position = (int) (fields = this.fields);
			maximum = (int) (fields >> 32);
			newInput = true;
			l = (int) (((long) position) * ((long) (contentWidth - THUMB_WIDTH)) / (long) maximum);
			if(x >= l + THUMB_WIDTH)
			{
				if((newPos = position + (maximum < 10 ? 1 : maximum / 10)) < 0)
				{
					newPos = 0;
				}
				else if(newPos > maximum)
				{
					newPos = maximum;
				}
			}
			else if(x < l)
			{
				if((newPos = position - (maximum < 10 ? 1 : maximum / 10)) < 0)
				{
					newPos = 0;
				}
				else if(newPos > maximum)
				{
					newPos = maximum;
				}
			}
			else
			{
				pressed = true;
				notifyPaint();
				return;
			}
			if(newPos != position)
			{
				setFields(maximum, newPos);
				notifyPaint();
				super.notifyStateChanged();
			}
		}
	}

	void onContentPointerDragged(int x, int y)
	{
		int w;
		int newPos;
		int position;
		int maximum;
		long fields;
		if((!interactive) || (!pressed) || (w = contentWidth - THUMB_WIDTH) <= 0)
		{
			return;
		}
		position = (int) (fields = this.fields);
		maximum = (int) (fields >> 32);
		newInput = true;
		if((newPos = (int) (((long) (x - (THUMB_WIDTH / 2))) * ((long) maximum) / (long) w)) < 0)
		{
			newPos = 0;
		}
		else if(newPos > maximum)
		{
			newPos = maximum;
		}
		if(newPos != position)
		{
			setFields(maximum, newPos);
			notifyPaint();
			super.notifyStateChanged();
		}
	}

	void onContentPointerReleased(int x, int y, int button)
	{
		int w;
		int newPos;
		int position;
		int maximum;
		long fields;
		if((!interactive) || (!pressed) || button != MIDletProxy.BUTTON_MAIN ||
				(w = contentWidth - THUMB_WIDTH) <= 0)
		{
			return;
		}
		position = (int) (fields = this.fields);
		maximum = (int) (fields >> 32);
		newInput = true;
		pressed = false;
		if((newPos = (int) (((long) (x - (THUMB_WIDTH / 2))) * ((long) maximum) / (long) w)) < 0)
		{
			newPos = 0;
		}
		else if(newPos > maximum)
		{
			newPos = maximum;
		}
		setFields(maximum, newPos);
		notifyPaint();
		if(newPos != position)
		{
			super.notifyStateChanged();
		}
	}

	void onTraverseOut()
	{
		if(!interactive)
		{
			return;
		}
		controlFocused = false;
		pressed = false;
		notifyPaint();
	}

	boolean onTraverseNeedStayOn(int direction, int viewportWidth, int viewportHeight,
			int[] visibleRectangle)
	{
		boolean cfocused;
		int position;
		int maximum;
		long fields;
		if(!interactive)
		{
			return false;
		}
		if((cfocused = controlFocused) != (controlFocused = true))
		{
			newInput = true;
			notifyPaint();
		}
		if(sliderFocused)
		{
			return true;
		}
		switch(direction)
		{
		case Canvas.LEFT:
			if(cfocused)
			{
				position = (int) (fields = this.fields);
				maximum = (int) (fields >> 32);
				newInput = true;
				if(position > 0)
				{
					setFields(maximum, position - 1);
					notifyPaint();
					super.notifyStateChanged();
				}
			}
			return true;
		case Canvas.RIGHT:
			if(cfocused)
			{
				position = (int) (fields = this.fields);
				maximum = (int) (fields >> 32);
				newInput = true;
				if(position < maximum)
				{
					setFields(maximum, position + 1);
					notifyPaint();
					super.notifyStateChanged();
				}
			}
			return true;
		case Canvas.UP:
		case Canvas.DOWN:
			return !cfocused;
		}
		return true;
	}

	boolean keyHandling(int key)
	{
		int keyCode;
		return (keyCode = MIDletProxy.getInstance().getKeyCode(key)) >= Canvas.KEY_NUM0 &&
				keyCode <= Canvas.KEY_NUM9;
	}

	boolean isMatchForAlert()
	{
		return (!interactive) && super.isMatchForAlert();
	}

	int getPreferredContentWidth(int contentHeight, int containerClientWidth)
	{
		return containerClientWidth;
	}

	int getPreferredContentHeight(int contentWidth)
	{
		return interactive ? FONT.getHeight() + THUMB_HEIGHT : 16;
	}

	private void setFields(int maximum, int position)
	{
		fields = (((long) maximum) << 32) | (long) position;
	}

	private void keyHandle(int key)
	{
		int digit;
		int newPos;
		int keyCode;
		int position;
		int maximum;
		long fields;
		if(!interactive)
		{
			return;
		}
		if((keyCode = MIDletProxy.getInstance().getKeyCode(key)) >= Canvas.KEY_NUM0 &&
				keyCode <= Canvas.KEY_NUM9)
		{
			digit = keyCode - Canvas.KEY_NUM0;
			position = (int) (fields = this.fields);
			maximum = (int) (fields >> 32);
			if((newPos = newInput ? digit : (10 * position) + digit) >= maximum ||
					newPos < 0)
			{
				newPos = maximum;
				newInput = true;
			} else
			{
				newInput = false;
			}
			if(newPos != position)
			{
				setFields(maximum, newPos);
				notifyPaint();
				super.notifyStateChanged();
			}
		}
	}
}
