/**
 *	Written 2006-10 By Filip Ekberg
 *	School Project on BTH - Software Engineering
 *
 *	Copyright (C)
 *
 *
 *	This class is used to control input in a textfield ( Text Only )
 *	This is an easy way to control text input.
 */

import javax.swing.*;
import java.awt.event.*;
import java.util.*;

/**
 *	This class Extends JTextField to make it impossible to write other characters than standard Characters A-Ö
 *	It also makes all Characters to upper case
 */
public class FTextField extends JTextField
{
	private char 				m_keyChar;
	private Boolean 	  		m_upperCase = false, m_started = false;
	private char[] 				m_recoString = new char[0];
	private int 				m_recoPos;
	private long[] 				m_userTime;
	private int[]				m_saveTime;
	private int 				m_recoEndPos = 0;
	private double 				m_totalTime = 0.0;
	private int					m_inputCounter = 0;
	private Vector<Object[][]>	m_storeTimes = new Vector<Object[][]>();
	
	/**
	 *	Sets text to upper case
	 */
	public void setUppCase()
	{
		m_upperCase = true;
	}
	
	/**
	 *	Sets text to lower case
	 */
	public void setStandardCase()
	{
		m_upperCase = true;
	}
	
	/**
	 *	Class constructor
	 */
    public FTextField(String text)
    {
    	super(text);
    }
    
   /**
	 *	Stores the validated time in a Vector
	 *
	 *	@param result	the result that was fetched from getResult
	 */
    public void storeTime(Object[][] result)
    {
    	this.m_storeTimes.add(result);
    }
    
    /**
	 *	Clears the time result Vector
	 */
    public void clearTimes()
    {
    	this.m_storeTimes.clear();
    }
    
    /**
	 *	Returns a Vector with all the validated times
	 */
    public Vector<Object[][]> getTimes()
    {
    	return this.m_storeTimes;
    }
    
    /**
	 *	Sets the string to ge recognized
	 *
	 *	@param	input	the string that you want to match
	 */
    public void setRecognizion(String input)
    {
    	m_recoString = input.toCharArray();
    	m_recoEndPos = m_recoString.length - 1;
    	m_recoPos = 0;
    	m_userTime = new long[m_recoString.length];
    }
    
    /**
	 *	Udates the current char possition
	 */
    public void update()
    {
    	if (m_recoPos <= m_recoString.length)
    	{	
    		m_userTime[m_recoPos] = System.currentTimeMillis();
    		if(m_recoPos == m_recoString.length)
    		{
    			m_started = false;
    		}
    			
    			
    		m_recoPos++;
    	}
    }
    
    /**
	 *	Returns true if the text string is within the given marginal of time.
	 *	Run this before you run reset
	 *
	 *	@param	error_marginal	the error_marginal passed as 0 - 100 ( % )
	 */
    public boolean calculateTimeResult(int error_marginal)
    {
    	boolean result = true;
    	
		int[] temp_time = new int[m_saveTime.length];
    	for ( int i = 0; i < this.m_storeTimes.size(); i++)
    	{
    		for ( int j = 0; j < this.m_storeTimes.get(i).length; j++ )
    		{
    			temp_time[j] += ((Integer)(this.m_storeTimes.get(i)[j][1]));
    		}
    	}
    	
    	for ( int i = 0; i < this.m_saveTime.length; i++)
    	{
    		
    		double marginal_max = (100.0 + (double)error_marginal) / 100.0;
    		double marginal_min = (100.0 - (double)error_marginal) / 100.0;
    		
    		int count = this.m_storeTimes.size();
    		if (count<2)
    			count = 2;
    			
    		int time = temp_time[i]/(count-1);
    		
    		int maxTime = (int)(time * marginal_max);
    		int minTime = (int)(time * marginal_min);
    		
    		
    		
    		if ( this.m_saveTime[i] < minTime ||  this.m_saveTime[i] > maxTime && maxTime > 0)
    		{
    			return false;
    		}
    			
    	}
    	return result;
    }
    
    /**
	 *	Returns how many times you have entered your string
	 */
    public int getTryCounter()
    {
    	return this.m_inputCounter;
    }
    
    /**
	 *	Resets the try counter to 0
	 */
    public void resetTryCounter()
    {
    	this.m_inputCounter = 0;
    }
    
    /**
	 *	Clears arrays and values so that you can write the string again
	 */
    public void reset()
    {
    	m_recoString = m_recoString;
    	m_recoEndPos = m_recoString.length - 1;
    	m_recoPos = 0;
    	m_userTime = new long[m_recoString.length];
    	this.setText("");
    	m_totalTime = 0;
    }
    
     /**
	 *	Returns a string like this
	 *	<STRING>;time1;time2;time3;time-n;
	 */
    public String toString()
    {
    	String returnValue;
    	if(this.m_recoString.length > 0)
    	{
    		String str = new String(m_recoString, 0, m_recoString.length);
    		returnValue = "<" + str +">;";
    	
    		int[] temp_time = new int[m_saveTime.length];
    		for ( int i = 0; i < this.m_storeTimes.size(); i++)
    		{
    			for ( int j = 0; j < this.m_storeTimes.get(i).length; j++ )
    			{
    				temp_time[j] += ((Integer)(this.m_storeTimes.get(i)[j][1]));
    			}
    		}
    	
    		for ( int i = 0; i < this.m_saveTime.length; i++)
    		{
    			int count = this.m_storeTimes.size();
    			if (count<2)
    				count = 2;
    		
    			int time = temp_time[i]/(count-1);
    		
    			returnValue += time + ";";
    			
    		}
    	}
    	else
    		returnValue = "Null";
    		
    	return returnValue;
    }
    
    /**
     *	Returns the username and sets the time to
	 *	creates a new user from a String that looks like this:
	 *	<STRING>;time1;time2;time3;time-n;
	 *
	 *	@param input	The string loaded from a file
	 */
    public String fromString(String input)
    {
    	String[] username = input.split(">");
    	username[0] = username[0].substring(1, username[0].length());
    	
    	String[] times = input.split(";");
    	    	
    	Object[][] ghost = new Object[times.length-1][2];
    	for(int i = 1; i < times.length; i++)
    	{
    		ghost[i-1][0] = username[0];
    		ghost[i-1][1] = Integer.parseInt(times[i]);
    	}
    	
    	this.m_storeTimes.add(ghost);
    	
    	return username[0];
    }
    
    /**
	 *	Returns an Object[][] with { "Char -> Char", Integer MS }
	 */
    public Object[][] getResult()
    {
    	int dataLenght = m_userTime.length-1;
    	if (dataLenght < 1)
    		dataLenght = 1;
    	
    	Object[][] data = new Object[dataLenght][2];
    	this.m_saveTime = new int[dataLenght];
    	
    	int arrPos = 0;
    	int arrEndPos = m_recoEndPos;
    	if (arrEndPos == 0)
    		arrEndPos = 1;
    		
		for(int i = 0; i < arrEndPos; i++)
		{
			arrPos = i+1;
			if (arrPos > arrEndPos+2)
				arrPos = arrEndPos;
			
			if(m_userTime.length < 2)
				data[i][0] = m_recoString[i];
			else if (arrEndPos >= 1)
				data[i][0] = m_recoString[i] +" > "+ m_recoString[arrPos];
				
			if (m_userTime.length < 2)
			{
				data[i][1] = "No Data";
			}
			else
			{
				int time = (int)(m_userTime[i+1]-m_userTime[i]);
				data[i][1] = time;
				m_saveTime[i] = time;
				this.m_totalTime = this.m_totalTime + time;
			}
		}
		
		m_inputCounter += 1;
		
    	return data;
    }
    
    /**
	 *	Returns the total time that it took to write the string
	 */
    public double getTotalTime()
    {
    	return this.m_totalTime;
    }
    
    /**
	 *	Reset the current char possition
	 */
    public void resetPos()
    {
    	m_recoPos = 0;
    }
    
    /**
	 *	Process the key that was typed
	 */
    public void processKeyEvent(KeyEvent e)
    {
    	if(m_recoString.length >= 1)
    	{
	    	m_keyChar = e.getKeyChar();
	    	if (Character.isLetter(m_keyChar) || Character.isSpace(m_keyChar))
	    	{
    			if (m_upperCase)
    			{
    				e.setKeyChar(Character.toUpperCase(m_keyChar));
    			}
    			
    			try
    			{
    				if (m_recoPos <= m_recoEndPos)
    				{
			    		if(Character.toUpperCase(m_keyChar) == m_recoString[m_recoPos])
			    		{
			    			m_started = true;
			    			super.processKeyEvent(e);
			    		}
			    		else
			    		{
			    			e.consume();
			    		}
    				}
    				else if(m_keyChar == KeyEvent.VK_ENTER)
    				{
			    			super.processKeyEvent(e);
    				}
    			}
    			catch(Exception ex)
    			{
    				//JOptionPane.showMessageDialog(null, "Pos: " + m_recoPos + "\r\n" + ex);
    			}
	    	}
	    	else
	    	{
	    		e.consume();
	    	}
    	}
    	else
    	{
    		e.consume();
    	}
    	
    }
}