package gpsalarmclock.util;

/*
 * VKey.java
 *
 * @author Shawn Fitzgerald
 * @version 1.0
 * License: LGPL  (see notice below)
 */
/*
	© 2006, Shawn Fitzgerald 
	info@OnShoreSystems.com   

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.


	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
import java.awt.Button;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.TextComponent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * VKey - is a virtual keyboard for the BugLab display
 * this component provide a QWERTY keyboard that can inject
 * characters into a TextComponent type object, or any component 
 * that supports taking text using a setText(String _text) method
 * and maintains the cursor position using the setCaretPosition(int _pos)
 * method.
 * The Keyboard can be closed by clicking on the close button 
 * at the upper left corner of the keyboard, or by setting the focused
 * item to null using the method setFocusedItem(null); 
 * The keyboard can be positioned on the screen by dragging it
 * using a stylus to select and drag to the desired location.
 * Once the stylus is lifted the keyboard will be displayed in 
 * the new location.
 * 
 */
public class VKey extends Dialog implements FocusListener, MouseListener, ActionListener
{
	private static final String TITLE = "VKeyboard";
	
	private Component focusedItem;	
	private Frame myFrame;
	private Button done = new Button("close");
	private boolean shifted = false;
	
	private String[] special = {"Shft","Del ","Tab","Rtn","   Space   ", "<-","->"};
	
	private char[][] unshiftRow = 
	{ {'`','1','2','3','4','5','6','7','8','9','0','-','='},
	  {'\002','q','w','e','r','t','y','u','i','o','p','[',']','\\',},
	  {'\000','a','s','d','f','g','h','j','k','l',';','\'','\003'},
	  {'\001','z','x','c','v','b','n','m',',','.','/',},
	  {'\004','\005','\006'}
	};
	
	private char[][] shiftRow = 
	{ {'~','!','@','#','$','%','^','&','*','(',')','_','+'},
	  {'\002','Q','W','E','R','T','Y','U','I','O','P','{','}','|'},
	  {'\000','A','S','D','F','G','H','J','K','L',':','"','\003'},
	  {'\001','Z','X','C','V','B','N','M','<','>','?',},
	  {'\004','\005','\006'}
	};
	
	private Object[][] keyCoord = 
	{
			new Object[unshiftRow[0].length],
			new Object[unshiftRow[1].length],
			new Object[unshiftRow[2].length],
			new Object[unshiftRow[3].length],
			new Object[unshiftRow[4].length],
			
	};

	private int charWidth;
	private int charHeight;
	private int boxHeight;
	private Insets ins;
	private int specialWidth;
	private int maxWidth =0;
	private FontMetrics fm ;
	
	private void setupUI()
	{
		ins = getInsets();
		
		charWidth = fm.charWidth('W'); 
		charHeight = fm.getHeight();
		boxHeight = fm.getHeight()+6; 
		specialWidth = charWidth+4;
		specialWidth *= 3;  
	   specialWidth -= 8; 
		
		int row =0;
		keyCoord[row][0] = new int[]{specialWidth+5,boxHeight*(row+1)+ins.top};
		
		for(row=1; row < 4; row++)
		  keyCoord[row][0] = new int[]{5,boxHeight*(row+1)+ins.top};
				
		int[] lastCoord = null;
		for(int i=1; i<14; i++)
		{			
			for(row=0; row < 4; row++)
			{
				if(i < unshiftRow[row].length)
				{
					int cw = charWidth+4;
					if(unshiftRow[row][i-1]<10)
					  cw = specialWidth; 
					lastCoord = (int[]) keyCoord[row][i-1];
					keyCoord[row][i] = (Object) new int[]{lastCoord[0]+cw,lastCoord[1]};
					int tmpMax = lastCoord[0]+cw+specialWidth;
					if(tmpMax > maxWidth)
						maxWidth = tmpMax;
				}
			}			
		}
		// setup last row info.
		int one4th = getWidth()/4;
		keyCoord[4][0] = (Object) new int[]{one4th,boxHeight*5+ins.top};
		keyCoord[4][1] = (Object) new int[]{one4th*2,boxHeight*5+ins.top};
		keyCoord[4][2] = (Object) new int[]{((int[])keyCoord[4][1])[0]+specialWidth,boxHeight*5+ins.top};
		
		setSize(maxWidth,boxHeight*6+ins.top);
		Button b = new Button("X");
		add(b);
		b.setBounds(5,0,charWidth*2,boxHeight);
		b.addActionListener(this);
	}
	
	public void paint(Graphics _gfx)
	{
	
		
		if(fm == null)
		{
			fm = _gfx.getFontMetrics();
			setupUI();
		}
		char[][] keyChars = (shifted?shiftRow:unshiftRow);
		
		
		for(int i=0; i<14; i++)
		{			
			for(int row=0; row < 4; row++)
			{
				if(i < keyCoord[row].length)
				{					
					int[] coords = (int[]) keyCoord[row][i];
					if(keyChars[row][i]<10 )
					{						
						_gfx.drawString(special[(int)keyChars[row][i]], coords[0]+2, (coords[1]+3)-(boxHeight/2));
						_gfx.drawRoundRect(coords[0], coords[1]-boxHeight,specialWidth, boxHeight, 5, 5);
					}else
					{						
						_gfx.drawChars(keyChars[row],i,1, coords[0]+2, (coords[1]+3)-(boxHeight/2));
						_gfx.drawRoundRect(coords[0],coords[1]-boxHeight,charWidth+2, boxHeight, 5, 5 );
					}
				}
			}
		}
		int[] coords = (int[]) keyCoord[4][0];

		int one4th = getWidth()/4;
		_gfx.drawString(special[(int)keyChars[4][0]], coords[0]+2, (coords[1]+3)-(boxHeight/2));
		_gfx.drawRoundRect(coords[0], coords[1]-boxHeight,one4th, boxHeight, 5, 5);
	
		coords = (int[]) keyCoord[4][1];
		_gfx.drawString(special[(int)keyChars[4][1]], coords[0]+2, (coords[1]+3)-(boxHeight/2));
		_gfx.drawRoundRect(coords[0], coords[1]-boxHeight,specialWidth, boxHeight, 5, 5);
		
		coords = (int[]) keyCoord[4][2];
		_gfx.drawString(special[(int)keyChars[4][2]], coords[0]+2, (coords[1]+3)-(boxHeight/2));
		_gfx.drawRoundRect(coords[0], coords[1]-boxHeight,specialWidth, boxHeight, 5, 5);
	}
	
    public void setFocusedItem(Component _comp)
    {
    	focusedItem = _comp;
    	if( focusedItem == null)
    		hide();
    }
	
	//********** FocusListener methods ***************/
	public void focusGained(FocusEvent _evt) 
	{
		if(_evt.getComponent() == this)
			return;

		 focusedItem = _evt.getComponent();

		  if(!isVisible())
			  show();
		  else
		  {
			  hide();
			  show();
		  }

//		}
		
	}

	public void focusLost(FocusEvent _evt) 
	{
	}
	

	//********** Constructors ***************/
	public VKey(Frame _frame) 
	{
		this(_frame,TITLE, false);		
	}

	public VKey(Frame _frame, boolean _model) 
	{
		this(_frame,TITLE, _model);	
	}

	public VKey(Frame _frame, String _title) {
		this(_frame,_title, false);		
	}

	public VKey(Frame _frame, String _title, boolean _model) {
		super(_frame, _title, _model);
		myFrame = _frame;
		setSize(myFrame.getWidth(),(int)(myFrame.getHeight()*.6));
		addMouseListener(this);
		setLayout(null);
		setUndecorated(true);
		//addFocusListener(this);
//		setupUI();
	}

	public void mouseClicked(MouseEvent _evt)
	{
	
		char[][] keyChars = (shifted?shiftRow:unshiftRow);
		Point pt = _evt.getPoint();
 
		int row = (pt.y)/boxHeight;
 
		int	col = ((pt.x-5)-(charWidth*2))/(charWidth+4);		
			
		if( col < 0 )
			col = 0;
		if( row < 0 )
			row = 0;
		if( !(row < shiftRow.length-1) )
		{
			row = shiftRow.length-1;	
			if( pt.x >= ((int[])keyCoord[4][0])[0] && pt.x < (((int[])keyCoord[4][0])[0]+(getWidth()/4) ))
				col = 0;
			else if( pt.x >= ((int[])keyCoord[4][1])[0] && pt.x < ((int[])keyCoord[4][1])[0]+specialWidth)
			    col = 1;
			else if( pt.x >= ((int[])keyCoord[4][2])[0] && pt.x < ((int[])keyCoord[4][2])[0]+specialWidth)
			    col = 2;
		}else
		{
		  if( col >= shiftRow[row].length)
			col = shiftRow[row].length-1;
			if(row == 0 && col > 0)
				col--;
		}

		
		char val = keyChars[row][col];
		if( val == 0)
		{		 
			shifted = !shifted;
			repaint();		 
			return;
		}
		
		if( focusedItem != null)
		{
			TextComponent comp = (TextComponent)focusedItem;	
			StringBuffer buf = new StringBuffer(comp.getText());
			int carPos = comp.getCaretPosition();

			
			switch(val)
			{
			case 0:
				return;
			case 1:  // del			
				if(carPos > 0)
					buf.deleteCharAt(--carPos);
				break;
			case 2:  // tab
				buf.insert(carPos,'\t');
				carPos++;
				break;
			case 3:  // enter
				buf.insert(carPos,'\n');
				carPos++;
				break;
			case 4:  // space
				buf.insert(carPos,' ');
				carPos++;
				break;
			case 5:  // <- left
				carPos--;
				break;
			case 6:  // -> right
				carPos++;
				break;
			default:
				buf.insert(carPos,val);
			    carPos++;

			}
			comp.setText(buf.toString());
			if( carPos < 0)
				carPos = 0;
			comp.setCaretPosition(carPos);
		}

	}

	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	private int stX = 0;
    private int stY = 0;
	public void mousePressed(MouseEvent _evt) 
	{
		
	  stX = _evt.getX();
	  stY = _evt.getY();
		
	}

	public void mouseReleased(MouseEvent _evt)
	{

	  if(stX == 0 && stY == 0)
		  return;
      int endX = _evt.getX();
      int endY = _evt.getY();
	  Point where  = getLocation();
      where.x += (endX-stX);
      where.y += (endY-stY);
      setLocation(where);
      
      stX = 0;
      stY = 0;
	}

	public void actionPerformed(ActionEvent _evt)
	{	
		hide();
	}
	



}