package filemanager;

import com.one.AbstractFont;
import com.one.ExtGraphics;
import com.one.PaintableObject;
import javax.microedition.lcdui.*;
import com.vmx.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class cvsContextMenu extends gkcCanvas
{
	protected Object parent;

	protected MenuListener listen;

	protected int w, h;
	protected int sel1, sel2;

	protected int mw1, mw2, mh1, mh2; // width & height для меню и подменю
	protected int mx1, mx2, my1, my2; // положение меню и подменю

	protected AbstractFont mf; // шрифт меню
	protected int mfh; // высота шрифта
	protected int mlh; // высота строки меню
	//protected FontWidthCache mfwc; // кэш ширины шрифта %)))

	protected int[][] menu;
	protected int[][] keyConfig;
	protected boolean[] keyAllowed;
	
	protected boolean enabled[][];
	protected int keyHeld;

	/** Конструктор */
	public cvsContextMenu(int[][] menu, int[][] keyConfig, boolean[] keyAllowed)
	{
		this.menu = menu;
		this.keyConfig = keyConfig;
		this.keyAllowed = keyAllowed;

		sel1 = 0;
		sel2 = -1;
		
		setFullScreenMode(true);
		
		w = getWidth();
		h = getHeight();
		
		mf = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_PLAIN, AbstractFont.SIZE_SMALL);
		mfh = mf.getHeight() + 1;
		
		//mlh = main.max(images.iconHeight + 1, mfh);
		mlh = mfh;
		
		// Подсчёт требуемой ширины и высоты меню ...
		int i, j, tt;
		int add = mf.stringWidth("W0+");
		int add1 = mf.stringWidth("W>");

		for(mw1 = 0, i = 0, tt = 0; i < menu.length; i++)
		{
			tt = mf.stringWidth(Locale.getString(this, menu[i][0])) + add1;
			
			if(tt > mw1)
			{
				mw1 = tt;
			}
		}
		
		mw1 += 4; // по 1 на рамку + по 1 отступ
		mh1 = mlh * menu.length + 3; // по 1 на рамку + 1 отступ сверху, отступ снизу учтен в mfh
		
		//mx1 = 7;
		//my1 = h - mh1 - 7;
		mx1 = my1 = 7;
		
		// ... и подменю
		for(mw2 = 0, i = 0, tt = 0; i < menu.length; i++)
		{
			for(j = 1; j < menu[i].length; j++)
			{
				tt = mf.stringWidth(Locale.getString(this, menu[i][j])) + add;
				
				if(tt > mw2)
				{
					mw2 = tt;
				}
			}
		}
		
		//mw2 += images.iconWidth + 5; // по 1 на рамку + по 1 на отступ + 1 между значком и текстом
		mw2 += 4; // по 1 на рамку + по 1 на отступ
		mh2 = -1;
		//mx2 = 14;
		
		if(mx1 + mw1 + mw2 > w)
		{
			mx2 = w - mw2;
		}
		else
		{
			mx2 = mx1 + mw1 - 1;
		}
		
		//mw1 = main.max(mw1, mw2);
		
		// а также создаём и заполняем enabled
		enabled = new boolean[menu.length][];
		
		for(i = 0; i < menu.length; i++)
		{
			enabled[i] = new boolean[menu[i].length];
			
			for(j = 0; j < menu[i].length; j++)
			{
				enabled[i][j] = true;
			}
		}
	}

	public void setListener(MenuListener listen)
	{
		this.listen = listen;
	}

	public void setEnabledFlags(boolean[][] enabledFlags)
	{
		for(int i = 0; i < enabled.length; i++)
		{
			System.arraycopy(enabledFlags[i], 0, enabled[i], 0, enabledFlags[i].length);
		}

		for(int i = 0; i < enabled.length; i++)
		{
			enabled[i][0] = false;

			for(int j = 1; j < enabled[i].length; j++)
			{
				if(enabled[i][j])
				{
					enabled[i][0] = true;
					break;
				}
			}
		}
	}
	
	public void show(Object parent)
	{
		this.parent = parent;
		
		sel1 = 0;
		sel2 = -1;

		main.dsp.setCurrent(this);
	}
	
	/**
	 * Функция отрисовки
	 */
	public void paint(ExtGraphics g)
	{
		if(parent instanceof PaintableObject)
		{
			((PaintableObject)parent).paint(g);
			g.setClip(0, 0, w, h);
		}
		else
		{
			images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], 0, 0, w, h, options.ditherGradients);
		}
		
		g.setColor(ColorScheme.colors[ColorScheme.mnback1]);
		
		images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx1, my1, mw1, mh1, options.ditherGradients);
		
		g.setColor(ColorScheme.colors[ColorScheme.dkborder]);
		g.drawRect(mx1, my1, mw1 - 1, mh1 - 1);
		g.setFont(mf);

		// Отрисовка меню
		for(int i = 0; i < menu.length; i++)
		{
			if(enabled[i][0])
			{
				if(i == sel1)
				{
					g.setColor(ColorScheme.colors[ColorScheme.mnselback1]);
					
					if(options.frameCursor)
					{
						g.drawRect(mx1 + 1, my1 + 1 + i * mlh, mw1 - 3, mlh);
					}
					else
					{
						images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx1 + 1, my1 + 1 + i * mlh, mw1 - 2, mlh + 1, options.ditherGradients);
					}
					
					g.setColor(ColorScheme.colors[ColorScheme.mnselfore]);
					g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
				}
				else
				{
					g.setColor(ColorScheme.colors[ColorScheme.mnfore]);
					g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
					g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]);
				}
			}
			else
			{
				g.setColor(ColorScheme.colors[ColorScheme.disabled]);
				g.drawString(Locale.getString(this, menu[i][0]), mx1 + 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
			}
			
			g.drawChar('>', mx1 + mw1 - 2, my1 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP);
		}
		
		// Если отображено подменю - рисуем его
		if(sel2 >= 0)
		{
			int m2l = menu[sel1].length - 1;
			
			mh2 = m2l * mlh + 3;
			//my2 = my1 + 2 + sel1 * mlh + mlh / 2;
			my2 = my1 + sel1 * mlh;
			
			if(my2 + mh2 > h - 14)
			{
				my2 = h - mh2 - 14;
			}
			
			if(my2 < 0)
			{
				my2 = 0;
			}
			
			g.setColor(ColorScheme.colors[ColorScheme.mnback1]);
			
			images.drawVGradient(g, ColorScheme.colors[ColorScheme.mnback1], ColorScheme.colors[ColorScheme.mnback2], mx2, my2, mw2, mh2, options.ditherGradients);
			
			g.setColor(ColorScheme.colors[ColorScheme.dkborder]);
			g.drawRect(mx2, my2, mw2 - 1, mh2 - 1);
			
			for(int i = 0; i < m2l; i++)
			{
				if(enabled[sel1][i + 1])
				{
					if(i == sel2)
					{
						g.setColor(ColorScheme.colors[ColorScheme.mnselback1]);
						
						if(options.frameCursor)
						{
							g.drawRect(mx2 + 1, my2 + 1 + i * mlh, mw2 - 3, mlh);
						}
						else
						{
							images.drawHGradient(g, ColorScheme.colors[ColorScheme.mnselback1], ColorScheme.colors[ColorScheme.mnselback2], mx2 + 1, my2 + 1 + i * mlh, mw2 - 2, mlh + 1, options.ditherGradients);
						}
						
						g.setColor(ColorScheme.colors[ColorScheme.mnselfore]);
						g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
					}
					else
					{
						g.setColor(ColorScheme.colors[ColorScheme.mnfore]);
						g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
						g.setColor(ColorScheme.colors[ColorScheme.mnaltfore]);
					}
				}
				else
				{
					g.setColor(ColorScheme.colors[ColorScheme.disabled]);
					g.drawString(Locale.getString(this, menu[sel1][i + 1]), mx2 + 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.LEFT | Graphics.TOP);
				}
				
				//images.drawIcon(g, menu[sel1][i * 2 + 2], mx2 + 2, my2 + 2 + i * mlh + (mlh - images.iconHeight) / 2);
				
				if(keyConfig[sel1][i] != KEY_INVALID)
				{
					g.drawChars(keyToChar(keyConfig[sel1][i]), 0, 2, mx2 + mw2 - 2, my2 + 2 + i * mlh + (mlh - mfh) / 2, Graphics.RIGHT | Graphics.TOP);
				}
			}
		}
	}
	
	protected static char[] chs = new char[2];
	
	public static char[] keyToChar(int keyCode)
	{
		if((keyCode & KEY_HELD) != 0)
		{
			chs[0] = (char)(keyCode & ~KEY_HELD);
			chs[1] = '+';
		}
		else
		{
			chs[0] = ' ';
			chs[1] = (char)keyCode;
		}
		
		return chs;
	}
	
	/** Функция возвращения к предыдущему экрану (к parent) */
	public void ret()
	{
		if(parent != null)
		{
			if(main.dsp.getCurrent() != parent)
			{
				main.dsp.setCurrent(parent);
			}
			
			parent = null;
		}
	}
	
	/**
	 * Обработчик нажатий клавиш.
	 * Формально здесь обрабатывается только джойстик,
	 * но из keyReleased могут быть транслированы
	 * нажатия цифровых клавиш как джойстика.
	 */
	public void keyPressed(int keyCode)
	{
		keyCode = remapKey(keyCode);

		int osel, ml;
		
		if(options.swapSoftKeys)
		{
			if(keyCode == KEY_LSK)
			{
				keyCode = KEY_RSK;
			}
			else if(keyCode == KEY_RSK)
			{
				keyCode = KEY_LSK;
			}
		}

		if(keyCode == KEY_DOWN)
		{
			if(sel2 == -1) // гуляем по меню
			{
				osel = sel1;
				ml = menu.length;
				
				do
				{
					sel1 = (sel1 + 1) % ml;
				}
				while(!enabled[sel1][0] && sel2 != osel);
			}
			else // гуляем по подменю
			{
				osel = sel2;
				ml = menu[sel1].length - 1;
				
				do
				{
					sel2 = (sel2 + 1) % ml;
				}
				while(!enabled[sel1][1 + sel2] && sel2 != osel);
			}
			
			repaint();
		}
		else if(keyCode == KEY_UP)
		{
			if(sel2 == -1) // гуляем по меню
			{
				osel = sel1;
				ml = menu.length;
				
				do
				{
					sel1 = (sel1 - 1 + ml) % ml;
				}
				while(!enabled[sel1][0] && sel2 != osel);
			}
			else // гуляем по подменю
			{
				osel = sel2;
				ml = menu[sel1].length - 1;
				
				do
				{
					sel2 = (sel2 - 1 + ml) % ml;
				}
				while(!enabled[sel1][1 + sel2] && sel2 != osel);
			}
			
			repaint();
		}
		else if(keyCode == KEY_LSK ||
		        keyCode == KEY_LEFT ||
		        keyCode == KEY_CANCEL)
		{
			if(sel2 == -1)
			{
				ret();
			}
			else
			{
				sel2 = -1;
				repaint();
			}
		}
		else if(keyCode == KEY_FIRE ||
		        keyCode == KEY_RIGHT ||
			    keyCode == KEY_RSK ||
			    keyCode == KEY_DIAL)
		{
			if(sel2 == -1)
			{
				sel2 = 0;
				
				while(!enabled[sel1][1 + sel2])
				{
					sel2++;
				}
				
				repaint();
			}
			else if(listen != null)
			{
				listen.menuAction(menu[sel1][1 + sel2]);
			}
		}
	}
	
	/**
	 * Обработчик повторений клавиш.
	 * Если нажатую клавишу можно использовать в качестве горячей,
	 * то ждем трехкратного удержания и переназначаем.
	 * Если нельзя, то обрабатываем это как обычные нажатия.
	 */
	public void keyRepeated(int keyCode)
	{
		keyCode = remapKey(keyCode);
		
		if(isKeyAllowed(keyCode))
		{
			if(++keyHeld == 3)
			{				
				keyConfig[sel1][sel2] = keyCode;
				repaint();
			}
			else if(keyHeld == 7)
			{
				keyConfig[sel1][sel2] |= KEY_HELD;
				repaint();
			}
		}
		else
		{
			keyPressed(translateKey(keyCode));
		}
	}
	
	/**
	 * Обработка отпускания клавиш.
	 * Если отпустили цифровую клавишу и не было удержания,
	 * то транслируем ее к джойстику и передаем keyPressed.
	 */
	public void keyReleased(int keyCode)
	{
		keyCode = remapKey(keyCode);

		if(keyHeld < 3)
		{
			if(isKeyNum(keyCode))
			{
				keyPressed(translateKey(keyCode));
			}
		}
		else
		{
			for(int i = 0; i < keyConfig.length; i++)
			{
				for(int j = 0; j < keyConfig[i].length; j++)
				{
					if(keyConfig[i][j] == keyConfig[sel1][sel2] && !(i == sel1 && j == sel2))
					{
						keyConfig[i][j] = KEY_INVALID;
					}
				}
			}
			
			repaint();
		}
		
		keyHeld = 0;
	}
	
	/**
	 * Совершить действие, которое назначено
	 * для некоторой горячей клавиши
	 * для некоторого типа меню.
	 * Если получилось, возвращается true.
	 */
	public boolean keyAction(int keyCode)
	{
		for(int i = 0; i < keyConfig.length; i++)
		{
			for(int j = 0; j < keyConfig[i].length; j++)
			{
				if(keyConfig[i][j] == keyCode)
				{
					listen.menuAction(menu[i][j + 1]);
					return true;
				}
			}
		}
		
		return false;
	}
	
	/**
	 * Можно ли данную клавишу в данном меню
	 * использовать в качестве горячей.
	 */
	public boolean isKeyAllowed(int keyCode)
	{
		return (keyCode == KEY_STAR && keyAllowed[0]) ||
		       (keyCode == KEY_POUND && keyAllowed[1]) ||
		       (keyCode >= KEY_NUM0 && keyCode <= KEY_NUM9 && keyAllowed[keyCode - KEY_NUM0 + 2]);
	}

	public static void readKeyConfig(int[][] keyConfig, DataInputStream dis) throws IOException
	{
		int i, j;

		for(i = 0; i < keyConfig.length; i++)
		{
			for(j = 0; j < keyConfig[i].length; j++)
			{
				keyConfig[i][j] = dis.readInt();
			}
		}
	}

	public static void writeKeyConfig(int[][] keyConfig, DataOutputStream dos) throws IOException
	{
		int i, j;

		for(i = 0; i < keyConfig.length; i++)
		{
			for(j = 0; j < keyConfig[i].length; j++)
			{
				dos.writeInt(keyConfig[i][j]);
			}
		}
	}
}