import java.awt.*;
import java.awt.event.*;
import java.awt.Point;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.event.ListSelectionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.text.AttributedCharacterIterator;
import java.util.Date;
import java.util.Random;
import java.awt.Robot;
import java.io.BufferedWriter;
import java.io.FileWriter;

/**
 * Visual search test for little pebl clone                       <br>
 * v0.7                                                           <br>
 *																  <br>
 * Test runs on design which can be changed from parameters       <br>
 *                                                                <br>
 * Target Char      X | O                                         <br>
 * Target Color Green | White                                     <br>
 * Size            10 | 20 | 30                                   <br>
 * Targets          0 | 1  | 5                                    <br> 
 * Repeats          5                                             <br>
 *                                                                <br>
 * combinations(target,color,size,targets) = 2*2*3*3*5            <br>
 * = 180 trials                                                   <br>
 *                                                                <br>
 * debug value false/true if debug-printing is neccessary.        <br>
 *                                                                <br>
 * results are saved into resultX.txt (X is the subject number    <br>
 * given by main window)                                          <br>
 *                                                                <br>
 * 6.3.2012 Graphical interface and basic idea ready      v0.1    <br>
 * 7.3.2012 More Graphical interface and class structures v0.2    <br>
 * 8.3.2012 Class structures and scenario setting         v0.4    <br>
 * 9.3.2012 First working clone version                   v0.6    <br>
 * 9.3.2012 Results saving is available                   v0.7    <br>
 *															      <br>
 * @author Toni Sanio                                             <br>
 * Source can be copied and modified without author's             <br>
 * permission.                                                 
 */

public class vsearch    extends JPanel
                        implements TestInterface {
     
	/**
	* Debugmode: false - no debug, true - debug
    */
    public static boolean debug              = false;
    /**
	* How many times the algorithm tries to generate new point for each symbol.
	* It chooses the best distance anyway.
    */
	public static int POINT_FINDER_LOOP_LOAD = 100;

    // Layout defaults
	/**
	* Screen width
    */
    public static int SCREEN_W               = 800;
	/**
	* Screen height
    */
    public static int SCREEN_H               = 600;

	/**
	* The boarder's width which tells how far from the edge the symbols are placed.
	* This makes the random area smaller or bigger.
    */
	public static int BOARDER_W              = 40;
    /**
	* The boarder's height which tells how far from the edge the symbols are placed.
	* This makes the random area smaller or bigger.
    */
	public static int BOARDER_H              = 40;

	/**
	* OK-Button location's x-coordinate
    */
    int OK_BUTTON_LEFT                       = 365;
    /**
	* OK-Button location's y-coordinate
    */
	int OK_BUTTON_TOP                        = 500;
	/**
	* OK-Button size width
    */
    int OK_BUTTON_W                          = 60;
    /**
	* OK-Button size height
    */
	int OK_BUTTON_H                          = 40;
    
	
	/**
	* NONE-Button location's x-coordinate
    */
    static int NONE_BUTTON_LEFT              = 300;
	/**
	* NONE-Button location's y-coordinate
    */
    static int NONE_BUTTON_TOP               = 15;
	/**
	* NONE-Button size width
    */
    static int NONE_BUTTON_W                 = 165;
	/**
	* NONE-Button size height
    */
    static int NONE_BUTTON_H                 = 62;
    
	/**
	* The X-coordinate of the trial number debug-text 
    */
    int TRIAL_INFO_X                         = 650;
    /**
	* The Y-coordinate of the trial number debug-text 
    */
	int TRIAL_INFO_Y                         = 50;
    
	
	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* Print greeting is the mode when test starts and the greeting text is printed.
	* @see #printMode
    */	
    public int PRINT_GREETING                = 0;
	
	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* If printMode is set to this the target will be shown for the user for a period of time 
	* to help him recognize what must be searched next.
	* @see #printMode
    */	
    public int PRINT_SEARCH_TARGET           = 1;
	
	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* if printMode is set to this it brings the trial to be shown so that user can search target.
	* @see #printMode
    */
    public int PRINT_SEARCH_SET              = 2;

	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* if printMode is set to this the program will wait until user chooses his answer from the circles.
	* @see #printMode
    */
    public int PRINT_SEARCH_WAIT_REPLAY      = 3;
    
	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* if printMode is set to this the program draws break-text and waits till the user is ready.
	* @see #printMode
    */
	public int PRINT_BREAK                   = 4;
	
	/**
	* Sentence starting with PRINT_ tells what mode the test is currently doing.<br>
	* if printMode is set to this the program draws outro text to mark the end of the test.
	* @see #printMode
    */
    public int PRINT_OUTRO                   = 5;
    
	/**
	* The current trial number on going. ie. it can be from 0 to 180.
    */
    public int currentTrial                  = 0;

	/**
	* Tells the program if mouse is pressed.
    */
    boolean mPressed                         = false;  
    
	/**
	* This variable tells the time when test was started.
    */	
    static long testStartTime;     
	/**
	* This variable tells the time when last printmode was changed ie. when the visual search begun.
    */	
    static long screenStartTime;
    
	/**
	* This variable is the printMode which tells what phase the test is going through at the moment.
	* @see #PRINT_GREETING
	* @see #PRINT_SEARCH_TARGET
	* @see #PRINT_SEARCH_SET
	* @see #PRINT_SEARCH_WAIT_REPLAY
	* @see #PRINT_BREAK
	* @see #PRINT_OUTRO
    */
    public int printMode                     = 0;
    
	/**
	* The JFrame which holds the graphical frameset and helps with the layout.
	* @see javax.swing.JFrame
    */		
    static JFrame frame;
	
	/**
	* JComponent to help with the layout system.
	* @see JComponent
    */		
    static JComponent newContentPane;
	
	/**
	* Transparent 16 x 16 pixel cursor image.
    */		
    static BufferedImage cursorImg           = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);    
	
	/**
	* Create a new blank cursor.
    */		
    static Cursor blankCursor                = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor");
    
	/**
	* Robot class for moving mouse to center without user's effort..
    */		
    public static Robot robot;
    
	/**
	* Takes care that mouse press won't piss on next window..
    */		
    public static boolean mClicksor          = false;
    
	/**
	* For saving the results a bufferedwriter is neccessary.
	* @see java.io.BufferedWriter
    */		
    static BufferedWriter bw;
    
    
	// Design parameters  
    /**
	* Amount of repeats in the design	
    */
    public static int repeats                = 5; // Repeat every case x amount
    /**
	* Target characters ie. {"X","O"}
    */
	public static String targChars[]         = {"X","O"};
    /**
	* Different colors to use in test, default {"white","green"}
    */
	public static String colors[]            = {"white","green"};
    /**
	* Different sizes of various trials.
    */
	public static int sizes[]                = {10,20,30};
	/**
	* Amount of targets in trials.
    */
    public static int targets[]              = {0,1,5};            
    /**
	* Different kinds of foils to use in trials ie. letters {"U","D","G","C","Q"}
    */
	public static String foils[]             = {"U","D","G","C","Q"};    
    /**
	* The amount of trials which is followed by a break window.
    */
	public static int BREAK_INTERVAL         = 30;
    /**
	* How long the target is shown in the middle of screen before the current actual trial is shown.
    */    
    public int SHOW_TARGET_WAIT_TIME         = 800; // Show 800ms the next target for subject
    
	/**
	* Holds the subject-number.
    */		
	public static String subjectGuy          = "James Bond";
	
	/**
	* design is the object of DesignContainer and holds the information and functions to do the actual test.
    */    
    public static DesignContainer design;
        
        
	/**
	* Contains the trials included in this design. It also does the shuffling of   
	* of trials and initializes the trial objects according the design setup.	   
	* User's choices like clicks and the timing is captured here and parameterized 
	* to each individual trial when test is running.							   	
	* @see 		Trial															   
	*/	
    public static class DesignContainer {
        
        int amountOfTrials = targChars.length*colors.length*sizes.length*targets.length*repeats;
        Trial trialsTmp[]  = new Trial[amountOfTrials];
        Trial trials[]     = new Trial[amountOfTrials];                
        
		/**
		* The constructor generates the trials according the design parameters which  
		* are defined earlier in the static variables. Each trial takes care of it's  
		* own initialization when it's constructor is called here.					  
		* After generating the array of trials is mixed randomly.					  
		* Array of trials is named trials[]. 									      
		* @see #foils
		* @see #targChars
		*/	
        public DesignContainer() {           
            // Generate trials for not suffled array
            int index = 0;
            for (int targChar=0;targChar<targChars.length;targChar++) {
                for (int color=0;color<colors.length;color++) {
                    for (int size=0;size<sizes.length;size++) {
                        for (int target=0;target<targets.length;target++) {
                            for (int repeat=0;repeat<repeats;repeat++) {                                                                                              
                                 trialsTmp[index] = new Trial(targChar,color,size,target); 
                                 trials[index]    = new Trial();
                                 index++;
                            }
                        }
                    }
                }
            }                     
            // Suffle the array: Loop and insert into new random places
            boolean trySuffle;
            for (int i=0;i<amountOfTrials;i++) { 
                trySuffle=true;
                while (trySuffle) { 
                    int randomIndex = getRandomNumber(amountOfTrials);
                    if ( trials[randomIndex].suffled == false ) {
                         trials[randomIndex] = trialsTmp[i]; // Copy the generated trial into this array
                         trials[randomIndex].suffled = true; // Merge to avoid inserting again..
                         trials[randomIndex].setTrialNumber(randomIndex+1);
                         trySuffle=false; // Okay ready to go next index!
                         if (debug) System.out.println("Suffled n shaked but not mixed: tmp[" + i + "] to trial[" + randomIndex + "]");
                    }
                }
            }
        }

		/**
		* User clicks none, what happens? The function is declared in trial's function
		* userClicksNone which is called here.										  
		* @param	trialNum     The trial number.										  
		*/
        public void userClicksNone(int trialNum) {
            trials[trialNum].userClicksNone();
        }
        
		/**
		* User clicks, what happens? This is called when user clicks on some point in 
		* the screen. This also checks if the point was inside of NONE_BUTTON.		  
		* The result is asked from trials userClicks(x,y) function. So it means that  
		* this function returns true if user clicked a symbol. This is very important
		* function as the user's clicks make the test ongoing.
		* @param 		x 			mouse's x-coordinate.							  
		* @param 		y 			mouse's y-coordinate.							  
		* @param		trialNum 	The trial number.							      
		* @return		if the cursor was over any symbol this returns true, otherwise
		* false.																	  
		*/		
        public boolean userClicks(int x, int y, int trialNum) {
            if (x > NONE_BUTTON_LEFT && y > NONE_BUTTON_TOP && x < NONE_BUTTON_LEFT+NONE_BUTTON_W && y < NONE_BUTTON_TOP+NONE_BUTTON_H) {
                    userClicksNone(trialNum);
                    return true;
            } else {
                if (trials[trialNum].userClicks(x,y))
                    return true;
                else
                    return false;
            }
        }    
		
		/**
		* Response1 means the first response user had made in current trial. In other 
		* words the click when the user had done visual searching and is ready to pick
		* the symbol. This calls the current trials trialResponse1() -function.		  		
		*/
        public void response1(int trialNum) {
            trials[trialNum].trialResponse1();
        }
        
		/*
		* Response2 means the second response user had made in current trial. In other
		* words the click when the user moves the mouse to over circle and clicks.    
		* This calls the current trials trialResponse2() -function and the logging    
		* function in Trial class called printLog() because this trial is finished.   
		*/
		public void response2(int trialNum) {
            trials[trialNum].trialResponse2();
            trials[trialNum].printLog();
        }
    }

      
	  
	/**
	* This class resembles one trial of the study experiment. 					  
	* It keeps information of the symbols, coordinates and type what this trial   
	* really includes. It also gathers the information of user selections and the 
	* correctness of the answer. Also it generates and does the initialization and
	* some drawing functions for the symbols and circles.						  
	* The most important function here is the logging which logs the trial made.  
	* This class is used in the design ie. "design that contains 10 trials".	  
	* @see 		DesignContainer													  
	*/	
    public static class Trial {
	
        // Notes to real values in array of design
		/**
		* This trial's target character
		*/
        public int targChar;
		
        /**
		* This trial's target character's color
		*/
		public int targColor;
		
        /**
		* This trial's size / amount of letters
		*/
 	    public int size;
		
        /**
		* This trial's target character's index number
		*/
		public int targ;
        
		// Real values of the trial taken from design array by index
		/**
		* The string representation of target character.
		*/
        public String targCharReal;
		
		/**
		* The string representation of target's color. ie. "white"
		*/
        public String targColorReal;
		
		/**
		* the real size of the trial ie. 10.
		*/
        public int sizeReal;
				
		/**
		* The actual amount of targets.
		*/
        public int targetsReal;
       
	    /**
		* This trial's generated characters.
		*/
        public String[] generatedChars;
		
        /**
		* Character or foil foil coordinates.
		*/
		
		public Point[] charCoords;
		
		/**
		* This trial's amount of foil characters.
		*/
        public int amountOfFoils;

		/**
		* This trial's targets coordinates
		*/
        public Point[] targetCoords;
		
		/**
		* The actual amount of targets used in calculations.
		*/
        public int amountOfTargets;
		
		/**
		* The actual amount of characters used in calculations.
		*/
        public int amountOfChars;
		
		/**
		* Generetated char string. This helps to print the trial's info. The chars's will be generated into this string also.
		*/
        public String generatedCharStr="";
        
        // Keeps track if the element is processed already to suffled list or just initialized
        public boolean suffled = false;                 
        
		/**
		* Character's or symbol's size. This is the hittesting size to know if user clicked near enough. 
		* If changed to bigger, the area when user's click is regocnized as a press on symbol gets bigger.
		* And in the other hand if the variable is set smaller it needs more accuracy and it helps to prevent
		* two symbols not to cover each other.
		* @see userClicks(int x, int y)
		*/		
		int circleSize         = 35;
        
		/**
		* Character's size. This is used when drawing characters to find character's centerpoint.
		*/		
		int charSize           = 20;
        
		/**
		* The current test time after the test had begun.
		*/		
        long currentTestTime   = 0;
		
        /**
		* @see #trialResponse1()
		*/
		long responseTime1     = 0;
        /**
		* @see #trialResponse2()
		*/
		long responseTime2     = 0;
		/**
		* The user's given answer. The number means the index which symbol was picked. 0 means user had chosen none -button.
		*/
        int  answer            = 0;
		/**
		* The correctness of user's answer.
		*/
        int  correct           = 0;
		/**
		* The index of this trial.
		*/
        int  thisTrialNumber   = 0;
        
        public Trial() {}
		
		/**
		* The constructor for trial. This takes care of calling the methods generating
		* foils and the coordinates for characters. Also the trial's variables are set
		* here.																		  
		* This is called when initializing the trial ie. from design.				  
		* The easiest way to handle these are to change the values that define the de-
		* design earlier. To understand this more you can drive this with debug=1 and 
		* you should see Added trial: -lines that describe what's happening.		  
		* @param v1		target's character index. ie. 0=X, 1=O according targChars[]  
		* @param v2		target's color index to use									  
		* @param v3		tells how much symbols are in this trial (sizes[index])		  
		* @param v4		tells how many symbols of this trial are targets. This is also index from table called targets[].										  
		*/
        public Trial(int v1, int v2, int v3, int v4) {
            // Copy the index values as well for further needs
            this.targChar      = v1;
            this.targColor     = v2;
            this.size          = v3;
            this.targ          = v4;
            // For real tablevalues
            this.targCharReal  = targChars[v1];
            this.targColorReal = colors[v2];
            this.sizeReal      = sizes[v3];
            this.targetsReal   = targets[v4];            
            if (debug) System.out.print("Added trial: "+v1+" "+v2+" "+v3+" "+v4+ " which means: "+ targCharReal + " " + targColorReal + " " + sizeReal + " " + targetsReal);
            generateFoils();
            generateCharCoords();
            if (debug) System.out.println("");
        }
        
		/**
		* Set the trialNumber -variable of this trial which tells this trials index.  
		* @param	num 	The trial number.										  
		*/
        public void setTrialNumber(int num) {
            thisTrialNumber = num;
        }               
        
        /**
		* Log the results into debug or file according subject's number.			  
		* Filename is made from subjectnumber.										  
		* This is called after trial is done to make sure all informatin is complete.
		* Does io exception if something went horribly wrong.					  
		*/				
        public void printLog() {            
            String logLine = subjectGuy + " " + thisTrialNumber + " " + currentTestTime + " " + targetsReal+ " " + sizeReal + " "+ targCharReal + " " + targColorReal + " " + 
                     generatedCharStr + " " + answer + " " + correct + " " + responseTime1 + " " + responseTime2;
            if (debug) System.out.println(logLine);
            try {
                bw.write(logLine);
                bw.newLine();
                bw.flush();
            } catch(Exception e) { System.out.println("Problems saving results.."); }            
        }
        
        /**
		* This function captures the time user had gone through when looking at the   
		* symbols. In other words this function is called when the user's visual 	  
		* searching is completed and he's ready to answer.							  
		* @see 		#getTestTimeMs()													  
		* @see 		#getScreenTimeMs()												  
		* @see		#trialResponse2()												  
		*/
		public void trialResponse1() {
            responseTime1   = getScreenTimeMs();
        }
        
		
		/**
		* When user clicks the second time this is called. The second time is the dis-
		* play when user chooses what he saw in last screen. This is called response- 
		* Time2 and the time is get by getScreenTime() function. Also the test-time is
		* captured here by getTestTimeMs() function.								  
		* @see 		#getTestTimeMs()													  
		* @see 		#getScreenTimeMs()												  
		* @see 		#trialResponse1()												  
		*/
        public void trialResponse2() {
            currentTestTime = getTestTimeMs();
            responseTime2   = getScreenTimeMs();            
        }
        
		/**
		* This is called when user clicks the none-button. After this checkCorrectness
		* must be done to check if it was correct answer.							  
		*/
        public void userClicksNone() {            
            answer          = 0;
            checkCorrectness();
        }

		/**
		* This function checks the correctness of user's answer.					  
		* This is called from userClicks -function.									  
		* The result is put into correct -varible of this class for later usage.	  
		*/
        public void checkCorrectness() {            
            // Check for none-selection correctness
            if (answer==0) {
                if (targetsReal==0) correct=1;
                else correct = 0;
            } else {
                int trueAnswer = answer-1; 
                if (targCharReal.equals(generatedChars[trueAnswer]))   
                    correct = 1;
                else
                    correct = 0;
            }
        }

		/**
		* The hit test for user's click. This tests through all the trial's symbols if 
		* some symbol was under the cursor when clicked.							   
		* The size of the test circle is defined in variable circleSize. If the user   
		* clicked on right place the answer is captured to variable named answer and   
		* the function checkCorrectness() is used to see if it was correct.			   
		* @param 		x 	mouse's x-coordinate.									   
		* @param 		y 	mouse's y-coordinate.									   
		* @return		if the cursor was over any symbol this returns true, otherwise 
		* false.																	   
		*/
        public boolean userClicks(int x, int y) {
            
            boolean heTrulyHit=false;
            
            for (int i=0;i<amountOfChars;i++) {
                Point p = charCoords[i];
                if (distance(x,y,p.getX(),p.getY()) < circleSize) {
                    heTrulyHit=true;                    
                    answer = i+1;
                    checkCorrectness();
                }
            }                        
            
            return heTrulyHit;
        }
        
		/**
		* Generates the characters for the test. The real ones like X, O and the fake 
		* characters randomly. The fake characters are found from foils[]-table and   
		* the real targChar and color is defined previously when this object is cons- 
		* tructed for example from design-class. This should be called in constructor.		
		* The result is also put into string to help printing it. The result string is
		* generatedCharStr.	And the generatedChars[] -table is where the actual chars 
		* can be found.																  
		* @see 	Trial.Trial(int v1, int v2, int v3, int v4)								  	
		*/
        private void generateFoils() {
            Random randomGenerator     = new Random();
            amountOfChars              = this.sizeReal;
            amountOfFoils              = this.sizeReal-this.targetsReal;
            generatedChars             = new String[amountOfChars];
            if (debug) System.out.print(" Generated random chars:" );
            String rndChar             = "";
            for (int i=0;i<amountOfChars;i++) {
                if (i<amountOfFoils) { // First elements in array are foils
                    int randomInt      = randomGenerator.nextInt(foils.length);
                    rndChar            = foils[randomInt];
                } else {               // Other elements are the targets if there is any
                    rndChar            = targCharReal;                
                }
                if (debug) System.out.print(" " + rndChar + " " );
                generatedChars[i]      = rndChar;                
                generatedCharStr       += rndChar;                
            }
            
        }
		
		/**
		* Generates charcoords. These are the coordinates where each trials' symvbols 
		* are placed. The function tries to find always the most far points randomly. 
		* The points are generated again and again and it always accept the distance  
		* which is more far away from each other point. The repetitions used to do    
		* this loop is defined variable POINT_FINDER_LOOP_LOAD.						  		
		* The result generated table is charCoords and is used in draw functions and  
		* to check the user's answer's correctness/rightness.						  
		* This function should be driven right in the start of trial to set the       
		* coordinates.																  
		* @see #drawChars(Graphics g)															  
		*/
        public void generateCharCoords() {            
            charCoords                 = new Point[amountOfChars];
            Point[] tmpCharCoords      = new Point[amountOfChars]; // Used for temporary in keeping track of minimum distance set of foils            
            
            if (debug) System.out.print(" Generate points... " );
            
            // Loop and get the collection which has smallest gap between two points            
            for (int i=0;i<amountOfChars;i++) {                
                double minimumDist      = 0;
                
                for (int l=0;l<POINT_FINDER_LOOP_LOAD;l++) {                     
                    double thisMinimum  = 1000000;
                    int rndX            = (int)(BOARDER_W*2.5 + getRandomNumber(SCREEN_W - BOARDER_W*5));
                    int rndY            = (int)(BOARDER_H*2.5 + getRandomNumber(SCREEN_H - BOARDER_H*5));
                    Point p             = new Point(rndX,rndY);
                    //charCoords[i]       = new Point(rndX, rndY);                    
                                    
                    // Calculate minimum distance between just generated foils and new point                    
                    for (int a=0;a<i;a++) {
                        Point aPoint    = tmpCharCoords[a];                        
                        double dist     = distance(aPoint.getX(),aPoint.getY(),p.getX(),p.getY());
                        if (dist < thisMinimum) {
                               thisMinimum = dist;                                  
                        }
                    }
                    // If we found a new point containing minimum distance which is greater than before, let's use it till we found another one..                
                    if (thisMinimum > minimumDist) {
                        tmpCharCoords[i]= p;                                
                        minimumDist     = thisMinimum; // Mark new minimum distance
                    }
                
                } // Loop point finder 
            } // Chars            
            // And copy the best distance set offcourse! It's meant to be good spread set..
            charCoords = tmpCharCoords;                        
        }     
        
   		/**
		* Draws characters(symbols) across the screen. The positions are gathered from
		* charCoods table.															  	
		* @param 		g Graphics to draw the stuff.								  	 
		*/
        public void drawChars(Graphics g) {
            for (int c=0;c<amountOfChars;c++) {
                 Point p    = charCoords[c];
                 if (c<amountOfFoils) g.setColor(Color.white);  
                 else {
                     if ("white".equals(targColorReal)) g.setColor(Color.white);  
                     if ("green".equals(targColorReal)) g.setColor(Color.green); 
                 }
                 g.drawString( generatedChars[c] ,(int)(p.getX()-charSize/2),(int)(p.getY()+charSize/2));
            }
        }
		
		/**
		* Draws circles across the screen. The positions are gathered from charCoods  
		* table. Circles are used in this test to show the previous place of the now  
		* hidden symbol.															  
		* @param 		g Graphics to draw the stuff.								  	 
		*/
        public void drawCircles(Graphics g) {
            for (int c=0;c<amountOfChars;c++) {                 
                 Point p    = charCoords[c];
                 g.setColor(Color.white);                                                   
                 g.drawOval( (int)(p.getX()-circleSize/2),(int)(p.getY()-circleSize/2), circleSize, circleSize);
                 
            }
        }
		
    }
    
	
	/**
     * Generates a random number from given range.								  
	 * @param 		range which should be positive number ie. 100				  	 
	 * @return		Randomly generated number from range ie. 0-100  			  
	 */
    public static int getRandomNumber(int range) {
       Random randomGenerator = new Random();
       return randomGenerator.nextInt(range);
    }
    
	/**
     * This function tells the distance between two points. Here it's used mostly 
	 * for recognizing if the user clicked on symbol. In this case the input is   
	 * mouse coordinates and symbol's coordinates.								  	 	 
	 * @param 		x1 X-coordinate of point1 as double.						  
	 * @param 		y1 Y-coordinate of point1 as double.						  
	 * @param 		x2 X-coordinate of point2 as double.						  
	 * @param 		y2 Y-coordinate of point2 as double.						  
	 * @return		The distance between points as double.						  
	 */
    public static double distance(double x1, double y1, double x2, double y2) {
        return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
    }
    
	/**
	 * Nothing overwhelming..													   
     * Start function for the test. Subject number will be given also via this.   
	 * The test-file is started to write in this function as also the design      
	 * object which is DesignContainer's object will be set up here.			  
	 * This function should be called when starting the test and the subject's    
	 * number is known.															  
	 * @param       subjectNumber subject's individual number 					  
	 * @see         java.lang.Thread														  
	 */
    public static void runTest(String subjectNumber) {
        
        subjectGuy = subjectNumber;
        design     = new DesignContainer();
        if (debug) System.out.println("sub trial time numtargs size targchar targcol stim resp corr rt1 rt2");
        
        try {
            bw         = new BufferedWriter(new FileWriter("vsearch-"+subjectGuy+".txt",true));           
            bw.write("sub trial time numtargs size targchar targcol stim resp corr rt1 rt2");
            bw.newLine();
            bw.flush();
        } catch(Exception e) { System.out.println("Problems loading and setting up the filewriter or file.."); }
        
        
        try {
            robot = new Robot();
        } catch(Exception robotEx) {}
        
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {                               
               // Set up user GUI 
               createAndShowGUI();                                                  
            }
        });                
        
        // Set up test-updater              
        Thread upd = new testUpdater();
        upd.start();
        
    }
    
	/**
     * Test updater holds the main loop for the test. It takes care of updating   
	 * the graphical interface again and again and making the thread sleep in     
	 * each cycle for 50ms.											  			  
	 * It also extends the Thread-class and overrides the run()-method.			  
	 * @see         #paint()														  
	 * @see         java.lang.Thread														  
	 */
    static class testUpdater extends Thread {         
         public void run() {            
            while(true) { // Test MAIN LOOP
                
                // Graphical delay 
                try 
                {
                     Thread.sleep(50);
                }
                catch (Exception e) {}      

                newContentPane.repaint();            
            
            } // Test mainloop            
         }
    }
    
    
	/**
     * Resets screen time. Should be called	when the time taking starts.		  
	 * For example when trial starts each time.									   
	 * @see         #getScreenTimeMs()											  
	 * @see         #resetTestTime()   											  
	 * @see         #getTestTimeMs()												  
	 */	 
    public static void resetScreenTime() {
        screenStartTime = new Date().getTime(); 
    }
	
	/**
     * Returns the screentime which is the time past after resetScreenTime() was  
     * called. For example get the time of last trial.							  	 
	 * @see         #resetScreenTime()											  
	 * @see         #resetTestTime()    											  
	 * @see         #getTestTimeMs()												  
	 * @return      the time in milliseconds after resetScreenTime() was called.  
	 */
    public static long getScreenTimeMs() {
        return (new Date().getTime() - screenStartTime ); 
    }
	
	/**
     * Resets test time. Should be used right after the total test begins.		  
	 * @see         #getScreenTimeMs()											  
	 * @see         #resetScreenTime()   										  
	 * @see         #getTestTimeMs()												  
	 */
    public static void resetTestTime() {
        testStartTime = new Date().getTime(); 
    }
	
	/**
     * Returns the test time which is the time past after resetTestTime() was     
     * called. For example get the time when person started doing the test.		  	 
	 * @see         #resetScreenTime()											  
	 * @see         #resetTestTime()    											  
	 * @see         #getScreenTimeMs()											  
	 * @return      the time in milliseconds after resetTestTime() was called.    
	 */
	public static long getTestTimeMs() {
        return (new Date().getTime() - testStartTime ); 
    }
    
     
	 
	/**
    * vSearch class construcor.												  
    * Mouse listener and user's mouse events and timing settings.				  
	* If need to change events happened after mouse clicks you're in right place.	 
	* @see        java.awt.event.MouseAdapter											  
	*/	 
    public vsearch() {

       addMouseListener(
         new MouseAdapter() {
			/**
			* Mouse adapter's mouse press handler.					
			* Here're the different events that happens 
			* after user clicks on something on the     
			* screen.									
			* The events are handled with printMode vari
			* able which is also changed according the  
			* desired state.							
			* The clicks mostly affects the design which
			* is a DesignContainer-classes object.      
			* @param e     MouseEvent, which tells x,y,b			
			* @see         java.awt.event.MouseAdapter
			* @see         DesignContainer				
			*/
            public void mousePressed( MouseEvent e )
            {
                
                if (!mClicksor) {
                    mPressed=true;
                    
                    if (printMode == PRINT_GREETING) {
                        if (e.getX() > OK_BUTTON_LEFT && e.getY() > OK_BUTTON_TOP && e.getX() < OK_BUTTON_LEFT+OK_BUTTON_W && e.getY() < OK_BUTTON_TOP+OK_BUTTON_H) {
                            printMode = PRINT_SEARCH_TARGET; // Start test if user pressed OK-Button
                            resetScreenTime();
                        }
                    }
                    else if (printMode == PRINT_SEARCH_TARGET) {
                               // Timer controlled..
                    }        
                    else if (printMode == PRINT_SEARCH_SET) {
                        design.response1(currentTrial); // Marge the time of first click
                        printMode = PRINT_SEARCH_WAIT_REPLAY;
                        resetScreenTime();
                        // Set the cursor for good place to start selecting item
                        robot.mouseMove(frame.getX() + SCREEN_W/2, frame.getY() + SCREEN_H/2); 
                    }        
                    else if (printMode == PRINT_SEARCH_WAIT_REPLAY) {
                        // Hit the NONE-button or a circle in design's trial?                                                
                        if (design.userClicks(e.getX(),e.getY(),currentTrial)) {                            
                            design.response2(currentTrial); // Marge the time of second click                            
                            printMode = PRINT_SEARCH_TARGET;
                            resetScreenTime();
                            currentTrial++;
                        
                            // Exception is here when it's time for user to take a break
                            if ( ((currentTrial+1) % BREAK_INTERVAL) == 0 && (design.amountOfTrials-currentTrial > (BREAK_INTERVAL/2)) ) {
                                printMode = PRINT_BREAK;
                            }
                        
                            if (currentTrial>design.amountOfTrials-1)
                                printMode = PRINT_OUTRO;
                        }
                        
                    }
                    else if (printMode == PRINT_BREAK) {
                        // Hit the OK-button?
                        if (e.getX() > OK_BUTTON_LEFT && e.getY() > OK_BUTTON_TOP && e.getX() < OK_BUTTON_LEFT+OK_BUTTON_W && e.getY() < OK_BUTTON_TOP+OK_BUTTON_H) {
                            printMode = PRINT_SEARCH_TARGET;
                            resetScreenTime();
                        }
                    }
                    else if (printMode == PRINT_OUTRO) {
                        // Hit the OK-button?
                        if (e.getX() > OK_BUTTON_LEFT && e.getY() > OK_BUTTON_TOP && e.getX() < OK_BUTTON_LEFT+OK_BUTTON_W && e.getY() < OK_BUTTON_TOP+OK_BUTTON_H) {
                            frame.dispose();
                        }
                   }

               }
                
                mClicksor = true; // Make sure we won't press until mouse is released!
            }
			
			/**
			* Mouse adapter's mouse released handler.			
			* Just couple of variables are set to false 
			* to gain information that the mouse is not 
			* beign pressed anymore.						
			* @see         java.awt.event.MouseAdapter					
			*********************************************/
            public void mouseReleased( MouseEvent e )
            {        
                mPressed = false;
                mClicksor = false;
            }
			
			/**
			* Not used in this version for anything.    
			* @see         java.awt.event.MouseAdapter				
			*/
            public void mouseClicked( MouseEvent e )
            {
            }
			
         }
      );
        
    }

    /**
     * Create the GUI and show it. 												 
	 * Nothing special. Just setting basic things like window-size and title.	 
	 * @see javax.swing.JFrame 														 
	 */
    private static void createAndShowGUI() {
        //Create and set up the window.
        frame = new JFrame("VSearch Test");
        //frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        
        //Create and set up the content pane.
        newContentPane = new vsearch();
        newContentPane.setOpaque(true); //content panes must be opaque               
        newContentPane.setBackground(Color.black);
        newContentPane.setLayout(null); // Helps for absolute positioning which is neccessary here..       
               
        frame.setContentPane(newContentPane);
                        
        //Display the window.
        frame.pack();
        frame.setVisible(true);
        frame.setSize(800, 600);
                
    }
    

	 /**
     * This function draws according the current situation of the test.		     
	 * The drawn window is managed with global printMode-attribute.				 
	 * printMode attribute is changed according the time and user input.		 
	 * Some draw functions are used from the current 
	 * All drawing is done here.												 
	 * @param g     The Graphics to draw.										 	
	 * @see         #printMode													 
	 */
    public void paint(Graphics g)
    {       
        
       g.setColor(Color.black);            
       g.fillRect(0,0,SCREEN_W,SCREEN_H);
            
       // Print Greeting windows
       if (printMode == PRINT_GREETING) {                    
            g.setColor(Color.white);
            g.fillRect(BOARDER_W*2,BOARDER_H*2,SCREEN_W-BOARDER_W*4,SCREEN_H-BOARDER_H*5);
        
            g.setColor(Color.black);            
            ghostWriter("You are about to take part in a study where you see a screen with many letters on it, and are searching for a particular target.  At the start of each trial, you will be shown the target.  Then, a screen will appear, and you will need to search for the target.  On some trials, the target will be present; on other trials it will be absent.  When you find the target or determine that it is absent, click the mouse button.  Following the mouse click, At this point, the targets will all be replaced by boxes so that you can no longer see what they were.  When this is done, click on the location of the target or the 'None' button.",BOARDER_W*2+15,BOARDER_H*2+15,600,500,g);        

            // OK-button down
            g.setColor(Color.white);              
            g.drawRect(OK_BUTTON_LEFT, OK_BUTTON_TOP, OK_BUTTON_W, OK_BUTTON_H);
            g.setFont(new Font("Dialog", Font.BOLD, 32));
            g.drawString("OK",370,530);                        
            
       } else {

       // Draw trial number
       if (debug) {
		if (printMode != PRINT_BREAK && printMode != PRINT_OUTRO) {
			g.setColor(Color.white);                        
            g.setFont(new Font("Dialog", Font.PLAIN, 12));
            g.drawString("Trial ["+(currentTrial+1)+"] of [" + (design.amountOfTrials) + "]",TRIAL_INFO_X, TRIAL_INFO_Y); 
		}
	   }
       
       // Set defaultFont
       g.setFont(new Font("Dialog", Font.PLAIN, 26));
       
       
       // Print Search target windows.. 
       if (printMode == PRINT_SEARCH_TARGET) {     
            frame.getContentPane().setCursor(blankCursor);              
            g.setColor(Color.white);            
            g.drawString("Target ",SCREEN_W/2-60, SCREEN_H/2-65);           
            
            if ("white".equals(design.trials[currentTrial].targColorReal)) g.setColor(Color.white);  
            if ("green".equals(design.trials[currentTrial].targColorReal)) g.setColor(Color.green); 
            
            g.drawString(design.trials[currentTrial].targCharReal,SCREEN_W/2-30, SCREEN_H/2);           
            
            // This window will close after small time
            if (getScreenTimeMs() > SHOW_TARGET_WAIT_TIME)
                printMode = PRINT_SEARCH_SET;
            // If this was the first time showing target
            // It means it's time to start measuring test time!
            if (currentTrial==0) 
                resetTestTime();
       }
       
       // Print Search set to user for visual searching..
       if (printMode == PRINT_SEARCH_SET) {   
            g.setColor(Color.white); 
            g.drawString("Click mouse button when search is complete",138, SCREEN_H-55);             
            // Set the blank cursor to the JFrame.
            frame.getContentPane().setCursor(blankCursor);           
            design.trials[currentTrial].drawChars(g);      
       }
       
       // Wait for user's answer screen ...
       if (printMode == PRINT_SEARCH_WAIT_REPLAY) {                   
            frame.getContentPane().setCursor(Cursor.getDefaultCursor());           
            design.trials[currentTrial].drawCircles(g);
            g.setColor(Color.white);
            g.drawString("Click on circle at location of target or NONE",133, SCREEN_H-55);  
            g.drawRect(NONE_BUTTON_LEFT, NONE_BUTTON_TOP, NONE_BUTTON_W, NONE_BUTTON_H);
            g.setFont(new Font("Dialog", Font.PLAIN, 32));
            g.drawString("NONE",NONE_BUTTON_LEFT+35, NONE_BUTTON_TOP+43);                                   
       }
       
       // Print Break-windows 
       if (printMode == PRINT_BREAK) {
            g.setColor(Color.white);
            g.fillRect(BOARDER_W*2,BOARDER_H*2,SCREEN_W-BOARDER_W*4,SCREEN_H-BOARDER_H*5);
        
            g.setColor(Color.black);            
            ghostWriter("You may take a short break.",BOARDER_W*2+15,BOARDER_H*2+15,600,500,g);        
            
            // OK-button down
            g.setColor(Color.white);              
            g.drawRect(OK_BUTTON_LEFT, OK_BUTTON_TOP, OK_BUTTON_W, OK_BUTTON_H);
            g.setFont(new Font("Dialog", Font.BOLD, 32)); //SansSerif
            g.drawString("OK",370,530);  
       }

       // Print outro window to notify the user end of the study
       if (printMode == PRINT_OUTRO) {
            g.setColor(Color.white);
            g.fillRect(BOARDER_W*2,BOARDER_H*2,SCREEN_W-BOARDER_W*4,SCREEN_H-BOARDER_H*5);
        
            g.setColor(Color.black);            
            ghostWriter("Thank you for taking part in the study.",BOARDER_W*2+15,BOARDER_H*2+15,600,500,g);        
            
            // OK-button down
            g.setColor(Color.white);              
            g.drawRect(OK_BUTTON_LEFT, OK_BUTTON_TOP, OK_BUTTON_W, OK_BUTTON_H);
            g.setFont(new Font("Dialog", Font.BOLD, 32));
            g.drawString("OK",370,530);  
       }
       
       } // end of drawing screens..
       
    }
    
    
    /**
     * Draws a text to screen into specified x,y position and the paragraph size 
	 * For example "Thank you for taking part in the study" inthe middle.        
     * Text is printed in a reader friendly way and not cutted stupidly..        
	 * @param  str  String that contains the text to print.					     
	 * @param  x    The starting X-position of text to print.   				 
	 * @param  y    The starting Y-position of text to print.   				 
	 * @param  w    The width of the area for printing.			  				 
	 * @param  h    The heigth of the text-area.				   				 
	 * @param  g    This holds the graphic-class where text is drawn.			 	 
	 * @see         java.awt.Graphics													 
	 */
    public void ghostWriter(String str,  int x, int y, int w, int h, Graphics g) {                
    
        int paragraphStart;
        int paragraphEnd;
    
        Graphics2D graphics2D = (Graphics2D) g;
        peblUtils util;
        AttributedCharacterIterator paragraph = peblUtils.getText(str);    
    
    
        FontRenderContext frc = peblUtils.getDefaultFontRenderContext();

        paragraphStart = paragraph.getBeginIndex();
        paragraphEnd = paragraph.getEndIndex();

        // Create a new LineBreakMeasurer from the paragraph.
        LineBreakMeasurer lineMeasurer;
        lineMeasurer = new LineBreakMeasurer(paragraph, frc);
     
        Dimension size = new Dimension(w, h);
        float formatWidth = (float) size.width;
        float drawPosY = y;

        lineMeasurer.setPosition(paragraphStart);
        
        while (lineMeasurer.getPosition() < paragraphEnd) {

            TextLayout layout = lineMeasurer.nextLayout(formatWidth);
            drawPosY += layout.getAscent();
            float drawPosX;
            if (layout.isLeftToRight()) {
                drawPosX = x;
            }
            else {
                drawPosX = formatWidth - layout.getAdvance();
            }
       
            layout.draw(graphics2D, drawPosX, drawPosY);
            drawPosY += layout.getDescent() + layout.getLeading();
        }
     
    
    } // ghostwriter

} // end of this funky class

