/*
 * gkcCanvas.java
 *
 * Get Key Codes canvas
 * (c) 2006, Виталий Филиппов [VMX]
 */

package com.vmx;

import com.one.AbstractFont;
import com.one.ErrScreen;
import com.one.IniRecord;
import com.one.PaintableObject;
import com.one.Renderer;
import com.one.StringPattern;
import java.util.Vector;
import javax.microedition.lcdui.game.Sprite;

public abstract class gkcCanvas extends PaintableObject
{
	public static int KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_FIRE;
	public static int KEY_LSK, KEY_RSK, KEY_DIAL, KEY_CANCEL; // KEY_BACK, KEY_CLEAR, KEY_DIAL, KEY_CANCEL;
	public static final int KEY_INVALID = 0;
	
	public static final int KEY_HELD = 0x80000000 >>> 1;
	public static final int KEY_HOT = KEY_HELD >>> 1;
	
	public static String[] platforms;
	public static int[][] keycodes;
	public static final int KEYS_COUNT = 9;

	public static int PTX = 0;										// смещение указателя по горизонтали
	public static int PTY = 0;										// смещение указателя по вертикали
	public static int PCW = AbstractFont.getDefaultFont().getHeight();		// ширина ячейки указателя
	public static int PCH = AbstractFont.getDefaultFont().getHeight();		// высота ячейки указателя
	public static int PSF = AbstractFont.getDefaultFont().getHeight();		// высота области софт-клавиш

	public static int[][] POINTER_GRID =
	{
		{ KEY_NUM1, KEY_NUM2, KEY_NUM3 },
		{ KEY_NUM4, KEY_NUM5, KEY_NUM6 },
		{ KEY_NUM7, KEY_NUM8, KEY_NUM9 },
		{ KEY_STAR, KEY_NUM0, KEY_POUND }
	};

	protected int pointx, pointy;
	protected boolean ptr_flag;
	protected boolean ptr_mode;
	
	public static int getDisplayWidth()
	{
		return getRenderer().getWidth();
	}
	
	public static int getDisplayHeight()
	{
		return getRenderer().getHeight();
	}
	
	public gkcCanvas()
	{
	}
	
	public static void readKeyMapList()
	{
		Vector vplatform = new Vector();
		Vector vcode = new Vector();
		
		try
		{
			InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/config/keymap.ini");
			IniRecord record = null;
			
			int[] array;
			Vector tokens;
			
			while((record = IniRecord.getNextRecord(ini)) != null)
			{
				try
				{
					vplatform.addElement(record.key);

					array = new int[KEYS_COUNT];
					tokens = StringPattern.tokenizeString(record.value, ' ');
					
					for(int i = 0; i < KEYS_COUNT; i++)
					{
						try
						{
							array[i] = Integer.parseInt(((String)tokens.elementAt(i)).trim());
						}
						catch(NumberFormatException nfe)
						{
							array[i] = 0;
						}
					}
					
					vcode.addElement(array);
				}
				catch(Exception e)
				{
				}
			}
			
			ini.close();
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(96, e);
		}
		
		platforms = new String[vplatform.size()];
		vplatform.copyInto(platforms);
		
		keycodes = new int[vcode.size()][];
		vcode.copyInto(keycodes);
	}
	
	public static int setKeyMap(int plindex, int transform)
	{
		int res = -1;

		if(plindex < 0)
		{
			Renderer rn = getRenderer();
			
			KEY_UP = rn.getKeyCode(UP);
			KEY_DOWN = rn.getKeyCode(DOWN);
			KEY_LEFT = rn.getKeyCode(LEFT);
			KEY_RIGHT = rn.getKeyCode(RIGHT);
			KEY_FIRE = rn.getKeyCode(FIRE);
			
			for(plindex = 0; plindex < keycodes.length; plindex++)
			{
				if(KEY_UP == keycodes[plindex][0] &&
				   KEY_DOWN == keycodes[plindex][1] &&
				   KEY_LEFT == keycodes[plindex][2] &&
				   KEY_RIGHT == keycodes[plindex][3] &&
				   KEY_FIRE == keycodes[plindex][4])
				{
					switch(transform)
					{
						case Sprite.TRANS_ROT90:
						case Sprite.TRANS_MIRROR_ROT90:
							KEY_UP = keycodes[plindex][3];
							KEY_DOWN = keycodes[plindex][2];
							KEY_LEFT = keycodes[plindex][0];
							KEY_RIGHT = keycodes[plindex][1];
							break;

						case Sprite.TRANS_ROT180:
						case Sprite.TRANS_MIRROR_ROT180:
							KEY_UP = keycodes[plindex][1];
							KEY_DOWN = keycodes[plindex][0];
							KEY_LEFT = keycodes[plindex][3];
							KEY_RIGHT = keycodes[plindex][2];
							break;

						case Sprite.TRANS_ROT270:
						case Sprite.TRANS_MIRROR_ROT270:
							KEY_UP = keycodes[plindex][2];
							KEY_DOWN = keycodes[plindex][3];
							KEY_LEFT = keycodes[plindex][1];
							KEY_RIGHT = keycodes[plindex][0];
							break;
					}

					KEY_LSK = keycodes[plindex][5];
					KEY_RSK = keycodes[plindex][6];
					KEY_DIAL = keycodes[plindex][7];
					KEY_CANCEL = keycodes[plindex][8];

					/*
					KEY_DIAL = keycodes[plindex][7];
					KEY_CANCEL = keycodes[plindex][8];
					KEY_BACK = keycodes[plindex][9];
					KEY_CLEAR = keycodes[plindex][10];
					*/

					res = plindex;
					break;
				}
			}
		}
		else if(plindex < keycodes.length)
		{
			switch(transform)
			{
				case Sprite.TRANS_ROT90:
				case Sprite.TRANS_MIRROR_ROT90:
					KEY_UP = keycodes[plindex][3];
					KEY_DOWN = keycodes[plindex][2];
					KEY_LEFT = keycodes[plindex][0];
					KEY_RIGHT = keycodes[plindex][1];
					break;

				case Sprite.TRANS_ROT180:
				case Sprite.TRANS_MIRROR_ROT180:
					KEY_UP = keycodes[plindex][1];
					KEY_DOWN = keycodes[plindex][0];
					KEY_LEFT = keycodes[plindex][3];
					KEY_RIGHT = keycodes[plindex][2];
					break;

				case Sprite.TRANS_ROT270:
				case Sprite.TRANS_MIRROR_ROT270:
					KEY_UP = keycodes[plindex][2];
					KEY_DOWN = keycodes[plindex][3];
					KEY_LEFT = keycodes[plindex][1];
					KEY_RIGHT = keycodes[plindex][0];
					break;

				default:
					KEY_UP = keycodes[plindex][0];
					KEY_DOWN = keycodes[plindex][1];
					KEY_LEFT = keycodes[plindex][2];
					KEY_RIGHT = keycodes[plindex][3];
					break;
			}

			KEY_FIRE = keycodes[plindex][4];
			
			KEY_LSK = keycodes[plindex][5];
			KEY_RSK = keycodes[plindex][6];
			KEY_DIAL = keycodes[plindex][7];
			KEY_CANCEL = keycodes[plindex][8];

			/*
			KEY_DIAL = keycodes[plindex][7];
			KEY_CANCEL = keycodes[plindex][8];
			KEY_BACK = keycodes[plindex][9];
			KEY_CLEAR = keycodes[plindex][10];
			*/

			res = plindex;
		}

		return res;
	}
	
	/**
	 * Устанавливаем везде автоматическую
	 * обработку повторений как нажатий.
	 */
	public void keyRepeated(int keyCode)
	{
		keyPressed(keyCode);
	}

	public void pointerPressed(int x, int y)
	{
		if(ptr_mode)
		{
			gridPointerPressed(x, y);
		}
		else
		{
			listPointerPressed(x, y);
		}
	}

	public void pointerDragged(int x, int y)
	{
		if(ptr_mode)
		{
			gridPointerDragged(x, y);
		}
		else
		{
			listPointerDragged(x, y);
		}
	}

	public void pointerReleased(int x, int y)
	{
		if(ptr_mode)
		{
			gridPointerReleased(x, y);
		}
		else
		{
			listPointerReleased(x, y);
		}
	}

	/**
	 * Переключение режимов перевода событий указателя в события клавиш.
	 * @param mode true - используется кнопочная сетка, false - используется список и софт-кнопки
	 */
	public void setPointerMode(boolean mode)
	{
		ptr_mode = mode;
	}

	public void gridPointerPressed(int x, int y)
	{
		x += PTX;
		y += PTY;

		x /= getDisplayWidth() / POINTER_GRID[0].length;
		y /= getDisplayHeight() / POINTER_GRID.length;

		keyPressed(POINTER_GRID[y][x]);
	}

	public void gridPointerDragged(int x, int y)
	{
		x += PTX;
		y += PTY;

		x /= getDisplayWidth() / POINTER_GRID[0].length;
		y /= getDisplayHeight() / POINTER_GRID.length;

		keyRepeated(POINTER_GRID[y][x]);
	}

	public void gridPointerReleased(int x, int y)
	{
		x += PTX;
		y += PTY;

		x /= getDisplayWidth() / POINTER_GRID[0].length;
		y /= getDisplayHeight() / POINTER_GRID.length;

		keyReleased(POINTER_GRID[y][x]);
	}

	/**
	 * Здесь запоминаем начальную точку.
	 */
	public void listPointerPressed(int x, int y)
	{
		x += PTX;
		y += PTY;

		if(y > getDisplayHeight() - PSF)
		{
			if(x < getDisplayWidth() / 2)
			{
				keyPressed(KEY_LSK);
			}
			else
			{
				keyPressed(KEY_RSK);
			}

			ptr_flag = false;
		}
		else
		{
			pointx = x;
			pointy = y;

			ptr_flag = true;
		}
	}

	/**
	 * Здесь обрабатываем сдвиг указателя.
	 */
	public void listPointerDragged(int x, int y)
	{
		x += PTX;
		y += PTY;
		
		int deltaX = x - pointx;
		int deltaY = y - pointy;

		if(Math.abs(deltaX) > Math.abs(deltaY))
		{
			if(deltaX >= PCW)
			{
				while(deltaX >= PCW)
				{
					keyPressed(KEY_RIGHT);
					deltaX -= PCW;
				}

				deltaY = 0;

				ptr_flag = false;
			}
			else if(deltaX <= -PCW)
			{
				deltaX = -deltaX;

				while(deltaX >= PCW)
				{
					keyPressed(KEY_LEFT);
					deltaX -= PCW;
				}

				deltaX = -deltaX;
				deltaY = 0;

				ptr_flag = false;
			}
		}
		else
		{
			if(deltaY >= PCH)
			{
				while(deltaY >= PCH)
				{
					keyPressed(KEY_DOWN);
					deltaY -= PCH;
				}

				deltaX = 0;

				ptr_flag = false;
			}
			else if(deltaY <= -PCH)
			{
				deltaY = -deltaY;

				while(deltaY >= PCH)
				{
					keyPressed(KEY_UP);
					deltaY -= PCH;
				}

				deltaY = -deltaY;
				deltaX = 0;

				ptr_flag = false;
			}
		}

		pointx = x - deltaX;
		pointy = y - deltaY;
	}

	public void listPointerReleased(int x, int y)
	{
		x += PTX;
		y += PTY;

		if(y > getDisplayHeight() - PSF)
		{
			if(x < getDisplayWidth() / 2)
			{
				keyReleased(KEY_LSK);
			}
			else
			{
				keyReleased(KEY_RSK);
			}

			ptr_flag = false;
		}
		else
		{
			if(ptr_flag)
			{
				keyPressed(KEY_FIRE);
				keyReleased(KEY_FIRE);
			}
		}
	}
	
	/**
	 * Проверка, является ли нажатая клавиша цифровой.
	 */
	public static boolean isKeyNum(int keyCode)
	{
		keyCode &= ~(KEY_HELD | KEY_HOT);
		return (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9) || keyCode == KEY_STAR || keyCode == KEY_POUND;
	}
	
	/**
	 * Транслировать нажатия цифровых клавиш
	 * к нажатиям джойстика.
	 */
	public static int translateKey(int keyCode)
	{
		switch(keyCode)
		{
			case KEY_NUM2:
				return KEY_UP;
			
			case KEY_NUM4:
				return KEY_LEFT;
			
			case KEY_NUM5:
				return KEY_FIRE;
			
			case KEY_NUM6:
				return KEY_RIGHT;
			
			case KEY_NUM8:
				return KEY_DOWN;
			
			default:
				return keyCode;
		}
	}

	/**
	 * Повернуть джойстик.
	 */
	public static int rotateKey(int keyCode, int transform)
	{
		if(keyCode == KEY_UP)
		{
			switch(transform)
			{
				case Sprite.TRANS_ROT90:
				case Sprite.TRANS_MIRROR_ROT90:
					return KEY_LEFT;

				case Sprite.TRANS_ROT180:
				case Sprite.TRANS_MIRROR_ROT180:
					return KEY_DOWN;

				case Sprite.TRANS_ROT270:
				case Sprite.TRANS_MIRROR_ROT270:
					return KEY_LEFT;
			}
		}
		else if(keyCode == KEY_DOWN)
		{
			switch(transform)
			{
				case Sprite.TRANS_ROT90:
				case Sprite.TRANS_MIRROR_ROT90:
					return KEY_RIGHT;

				case Sprite.TRANS_ROT180:
				case Sprite.TRANS_MIRROR_ROT180:
					return KEY_UP;

				case Sprite.TRANS_ROT270:
				case Sprite.TRANS_MIRROR_ROT270:
					return KEY_RIGHT;
			}
		}
		else if(keyCode == KEY_LEFT)
		{
			switch(transform)
			{
				case Sprite.TRANS_ROT90:
				case Sprite.TRANS_MIRROR_ROT90:
					return KEY_DOWN;

				case Sprite.TRANS_ROT180:
				case Sprite.TRANS_MIRROR_ROT180:
					return KEY_RIGHT;

				case Sprite.TRANS_ROT270:
				case Sprite.TRANS_MIRROR_ROT270:
					return KEY_UP;
			}
		}
		else if(keyCode == KEY_RIGHT)
		{
			switch(transform)
			{
				case Sprite.TRANS_ROT90:
				case Sprite.TRANS_MIRROR_ROT90:
					return KEY_UP;

				case Sprite.TRANS_ROT180:
				case Sprite.TRANS_MIRROR_ROT180:
					return KEY_LEFT;

				case Sprite.TRANS_ROT270:
				case Sprite.TRANS_MIRROR_ROT270:
					return KEY_DOWN;
			}
		}

		return keyCode;
	}

	/**
	 * Преобразовать пункт меню в код клавиши.
	 */
	public static int convertKeyAction(int action)
	{
		if(action >= Locale.KEY_NUM1 &&
		   action < Locale.KEY_NUM0)
		{
			return KEY_NUM1 + action - Locale.KEY_NUM1;
		}
		else if(action == Locale.KEY_NUM0)
		{
			return KEY_NUM0;
		}
		else if(action == Locale.KEY_STAR)
		{
			return KEY_STAR;
		}
		else if(action == Locale.KEY_POUND)
		{
			return KEY_POUND;
		}
		else
		{
			return KEY_INVALID;
		}
	}

	/**
	 * Преобразовать код одной кнопки
	 * в код другой кнопки...
	 */
	public static int remapKey(int keyCode)
	{
		int newCode = convertKeyAction(keyConfig.getAction(keyCode));
		return newCode != KEY_INVALID ? newCode : keyCode;
	}
}
