/***********************************************************************
 * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
 *  
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program 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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 ***********************************************************************/
package org.mt4j.components.visibleComponents.widgets.keyboard;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import org.mt4j.components.MTComponent;
import org.mt4j.components.StateChange;
import org.mt4j.components.StateChangeEvent;
import org.mt4j.components.StateChangeListener;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.components.visibleComponents.shapes.AbstractShape;
import org.mt4j.components.visibleComponents.widgets.MTTextArea;
import org.mt4j.components.visibleComponents.widgets.MTTextArea.ExpandDirection;
import org.mt4j.components.visibleComponents.widgets.buttons.MTSvgButton;
import org.mt4j.input.gestureAction.DefaultDragAction;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.lassoProcessor.LassoProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.MTColor;
import org.mt4j.util.math.Matrix;
import org.mt4j.util.math.Vector3D;

import processing.core.PApplet;

/**
 * A multitouch keyboard with an attached textfield that can be written to.
 * 
 * @author Christopher Ruff
 */
public class MTTextKeyboard extends MTKeyboard {
	
	/** The font for text field. */
	private IFont fontForTextField;
	
	/** The parent to add new text area to. */
	private MTComponent parentToAddNewTextAreaTo;
	
	/** The clustering gesture analyzer. */
	private LassoProcessor lassoProcessor;
	
	//Gesture Actions
	/** The default drag action. */
	private DefaultDragAction defaultDragAction;
//	private DefaultRotateAction defaultRotateAction;
//	private DefaultScaleAction defaultScaleAction;

	/** The drag from keyb action. */
	private DragTextAreaFromKeyboardAction dragFromKeybAction;

	/** The pa. */
	private PApplet pa;
	
	private ITextInputListener textInputListener;
	
	
	/**
	 * Creates a new keyboard with a default font for its textarea.
	 * 
	 * @param pApplet the applet
	 */
	public MTTextKeyboard(PApplet pApplet) {
		this(pApplet, FontManager.getInstance().createFont(pApplet, 
				"arial.ttf", 35, new MTColor(0,0,0,255), new MTColor(0,0,0,255))); 
//		this(pApplet, FontManager.getInstance().createFont(pApplet, "Eureka90.vlw", 35, new Color(0,0,0,255), new Color(0,0,0,255))); 
//		this(pApplet, FontManager.getInstance().createFont(pApplet, "arial", 35, new Color(0,0,0,255), new Color(0,0,0,255))); 
	}
	
	
	/**
	 * Creates a new keyboard with the specified font for its textarea.
	 * 
	 * @param pApplet the applet
	 * @param fontForTextField the font for text field
	 */
	public MTTextKeyboard(PApplet pApplet, IFont fontForTextField) {
		super(pApplet);
		this.pa = pApplet;
		
		this.fontForTextField = fontForTextField;
		
		lassoProcessor 	= null;
		
		//Set up gesture actions
		defaultDragAction 	= new DefaultDragAction();
//		defaultRotateAction = new DefaultRotateAction();
//		defaultScaleAction 	= new DefaultScaleAction();
		dragFromKeybAction 	= new DragTextAreaFromKeyboardAction();
		
		
		MTSvgButton newTextFieldSvg = new MTSvgButton(MT4jSettings.getInstance().getDefaultSVGPath()
				+ "keybNewTextField.svg", pa);
		newTextFieldSvg.setBoundsPickingBehaviour(AbstractShape.BOUNDS_ONLY_CHECK);
		newTextFieldSvg.scale(0.8f, 0.8f, 1, new Vector3D(0,0,0));
		newTextFieldSvg.translate(new Vector3D(10,5,0));

		newTextFieldSvg.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if (arg0.getSource() instanceof MTComponent){
						MTComponent clickedComp = (MTComponent)arg0.getSource();

						switch (arg0.getID()) {
						case TapEvent.BUTTON_CLICKED:
							//should always be keyboard
							MTComponent parent = clickedComp.getParent();
							if (parent instanceof MTTextKeyboard){
								MTTextKeyboard keyboard = (MTTextKeyboard)parent;

								//Remove old Textfield from keyboard if there is any
								if (textInputListener != null){
									
									if (textInputListener instanceof MTTextArea){
										MTTextArea ta = (MTTextArea)textInputListener;
										ta.setGestureAllowance(DragProcessor.class, true);
										ta.setGestureAllowance(RotateProcessor.class, true);
										ta.setGestureAllowance(ScaleProcessor.class, true);
										
										ta.setEnableCaret(false);
										
										//Add to clusteranylyzer for clustering the tarea
										if (getLassoProcessor() != null){
											getLassoProcessor().addClusterable(ta);
										}

//										keyboard.setTextInputAcceptor(null);
										removeTextInputListener(textInputListener);
										textInputListener = null;
										
										ta.removeAllGestureEventListeners(DragProcessor.class);
										ta.addGestureListener(DragProcessor.class, defaultDragAction);
//										ta.unassignGestureClassAndAction(DragGestureAnalyzer.class);
//										ta.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);

										//The direction, in which the textarea will float off 
										Vector3D v = new Vector3D(0,-100, 0);

										//Add the textarea to the set parent
										if (getParentToAddNewTextAreaTo() != null){
											//Transform the textarea so it appears at the same world coords after its added to another parent
											Matrix m = MTComponent.getTransformToDestinationParentSpace(ta, getParentToAddNewTextAreaTo());
											ta.transform(m);
											//Transform the direction vector for the translation animation 
											//to preserve the direction from the old reference frame to the new parents one
//											v.transformNormal(m);
											v.transformDirectionVector(m);

											ta.tweenTranslate(v, 500, 0.3f, 0.7f);

											getParentToAddNewTextAreaTo().addChild(ta);
										}else{
											//If that isnt set, try to add it to the keyboards parent
											if (getParent() != null){
												/////////////////////////
												// Transform the textarea so it appears at the same place after its added to another parent
												Matrix m = MTComponent.getTransformToDestinationParentSpace(ta, getParent());
												ta.transform(m);
												//Transform the direction vector to preserve the global direction
												//from the old reference frame to the new parents one
												//The translation part has to be removed from the matrix because we're transforming 
												//a translation vector not a point vector
												v.transformDirectionVector(m);

												ta.tweenTranslate(v, 500, 0.3f, 0.7f);
												/////////////////////
												getParent().addChild(ta);
											}else{
												//do nothing..?
												throw new RuntimeException("Dont know where to add text area to!");
											}
										}
									}//if (text instanceof MTTextArea){
								}//if (keyboard.getTextInputAcceptor() != null){
								//Create a new textarea
								keyboard.createNewTextArea();
							}//if (parent instanceof MTTextKeyboard){
							break;
						default:
							break;
						}
					}
				}
			});
		this.addChild(newTextFieldSvg);
	}
	
//	@Override
//	protected void keyboardButtonDown(MTKey clickedKey, boolean shiftPressed){
//		ITextInputAcceptor textArea = getTextInputAcceptor();
//		if (textArea != null){
//			if (clickedKey.getCharacterToWrite().equals("back")){
//				textArea.removeLastCharacter();
//			}else if (clickedKey.getCharacterToWrite().equals("shift")){
//					//no nothing
//			}else{
//				String charToAdd = shiftPressed ? clickedKey.getCharacterToWriteShifted() : clickedKey.getCharacterToWrite();
//				textArea.appendCharByUnicode(charToAdd);
//			}
//		}
//	}
	
	
	/**
 * Creates a new textarea at the keyboard.
 * Fails if there is still one attached to it.
 */
	public void createNewTextArea(){
		if (this.textInputListener == null){
			final MTTextArea t = new MTTextArea(pa, fontForTextField);
			this.textInputListener = t;
			
			t.setExpandDirection(ExpandDirection.UP);
			t.setStrokeColor(new MTColor(0,0 , 0, 255));
			t.setFillColor(new MTColor(205,200,177, 255));
			
			t.setGestureAllowance(DragProcessor.class, true);
			t.setGestureAllowance(RotateProcessor.class, false);
			t.setGestureAllowance(ScaleProcessor.class, false);
			
			t.removeAllGestureEventListeners(DragProcessor.class);
			t.addGestureListener(DragProcessor.class, dragFromKeybAction);
			
			t.setEnableCaret(true);
			t.snapToKeyboard(this);
			
			this.addTextInputListener(this.textInputListener);
			//Remove textarea from listening if destroyed
			t.addStateChangeListener(StateChange.COMPONENT_DESTROYED, new StateChangeListener() {
				public void stateChanged(StateChangeEvent evt) {
					removeTextInputListener(t);
				}
			});
		}else{
			System.err.println("Cant create new textarea - Keyboard still has a textarea attached.");
		}
	}
	


	/**
	 * Gets the parent to add new text area to.
	 * 
	 * @return the parent to add new text area to
	 */
	public MTComponent getParentToAddNewTextAreaTo() {
		return parentToAddNewTextAreaTo;
	}

	/**
	 * Determines to which parent the textarea of the keyboard will be added to after
	 * decoupling it from the keyboard.
	 * 
	 * @param parentToAddNewTextAreaTo the parent to add new text area to
	 */
	public void setParentToAddNewTextAreaTo(MTComponent parentToAddNewTextAreaTo) {
		this.parentToAddNewTextAreaTo = parentToAddNewTextAreaTo;
	}

	/**
	 * Gets the clustering gesture analyzer.
	 * 
	 * @return the clustering gesture analyzer
	 */
	public LassoProcessor getLassoProcessor() {
		return lassoProcessor;
	}

	/**
	 * Sets the clustering gesture analyzer.
	 * 
	 * @param clusteringGestureAnalyzer the new clustering gesture analyzer
	 */
	public void setLassoProcessor(LassoProcessor clusteringGestureAnalyzer) {
		this.lassoProcessor = clusteringGestureAnalyzer;
	}
	
	
	
	/**
	 * Gesture action class to be used when a textarea is dragged away from the keyboard.
	 * 
	 * @author C.Ruff
	 */
	private class DragTextAreaFromKeyboardAction extends DefaultDragAction {
		
		/* (non-Javadoc)
		 * @see com.jMT.input.gestureAction.DefaultDragAction#processGesture(com.jMT.input.inputAnalyzers.GestureEvent)
		 */
		public boolean processGestureEvent(MTGestureEvent g) {
			
			super.processGestureEvent(g);
			
			if (g.getId() == MTGestureEvent.GESTURE_ENDED){
				if (g instanceof DragEvent){
					DragEvent dragEvent = (DragEvent)g;
					
					if (dragEvent.getTargetComponent() instanceof MTTextArea){
						MTTextArea text = (MTTextArea)dragEvent.getTargetComponent();

						//Add default gesture actions to textfield
//						text.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);
//						text.assignGestureClassAndAction(ScaleGestureAnalyzer.class, defaultScaleAction);
//						text.assignGestureClassAndAction(RotateGestureAnalyzer.class, defaultRotateAction);
						
						text.setGestureAllowance(DragProcessor.class, true);
						text.setGestureAllowance(RotateProcessor.class, true);
						text.setGestureAllowance(ScaleProcessor.class, true);
						
						//Disable caret showing
						text.setEnableCaret(false);
						
						//Add to clusteranylyzer for clustering the tarea
						if (getLassoProcessor() != null){
							getLassoProcessor().addClusterable(text);
						}
						
						removeTextInputListener(textInputListener);
						textInputListener = null;
						
						text.removeAllGestureEventListeners(DragProcessor.class);
						text.addGestureListener(DragProcessor.class, defaultDragAction);
						
//						text.unassignGestureClassAndAction(DragGestureAnalyzer.class);
//						text.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);
						
//						/*
						//Add the textare to the set parent
						if (getParentToAddNewTextAreaTo() != null){
							text.transform(MTComponent.getTransformToDestinationParentSpace(text, getParentToAddNewTextAreaTo()));
							getParentToAddNewTextAreaTo().addChild(text);
						}else{
							//If that isnt set, try to add it to the keyboards parent
							if (getParent() != null){
								text.transform(MTComponent.getTransformToDestinationParentSpace(text, getParent()));
								getParent().addChild(text);
							}else{
								//do nothing..
//								throw new RuntimeException("Dont know where to add text area to!");
								System.err.println("Dont know where to add text area to!");
							}
						}
//						*/
					}
				}
			}
			return false;
		}
	}
	

}
