//  package Tests;

import java.awt.event.*; // for mouseEvent and InputEvent
import java.beans.*;
import RemoteInterface.*; // for Move

public class GameBoardTest 
    extends AbstractTest {
    
    
    public GameBoardTest(String logFile) {
	super(logFile); // report file
	 
	className = "GameBoard";        // CUT
	fileName =  "GameBoard.java";   // CUT file name
    }

    // Preconditions: called by AbstractTest::testProcess via inheritance
    // Symantics: showTestMenu is to be used together with testDispatch
    // Postconditions: Displays super.showTestMenu and then displays
    //                 tests available in this class
    protected void showTestMenu(){
	super.showTestMenu();
    
	System.out.println("1.3 set Game won");
	System.out.println("1.4 set Game Lost");
	System.out.println("1.5 set Game tied");
	System.out.println("1.6 set Game playing");
	System.out.println("1.7 resize GameBoard(increment +50x50 pixels)");
	System.out.println("1.8 Test mouse up (x=25, y=25)");
	System.out.println("1.9 Test mouse Script ");
	System.out.println("1.10 set Player ID == 0 ");
	System.out.println("1.11 set Player ID == 1 ");
	System.out.println("1.12 setMove(2) test ");
	System.out.println();
	
    }
    
    // Preconditions: called by AbstractTest::testProcess via inheritance
    //                called after a user has input "which" test to run
    //                the tests are numbered in showTestMenu.
    // Symantics: testDispatch is to be used with showTestMenu
    // Postconditions: Executes the user selected test
    //                 if the test is not listed here check 
    //                 super.testDispatch()
    protected void testDispatch(int which[])
	throws Exception {
	
	if ( which.length != 2 || which[0] != 1 ) {
	    super.testDispatch(which);
	    return;
	}

	switch (which[1]) {
	case 3 :			// 3. set Game won
	    logTestResult( "1.3 test Game Status 1", 
			   setGameStatusTest(1) );  // 1 = won
	    break;
	case 4 :			// 4. set Game Lost
	    logTestResult( "1.4 test Game Status 0", 
			   setGameStatusTest(0) );	// 0 = Lost
	    break;
	case 5 :                  // 5. set Game tied 
	    logTestResult( "1.5 test Game Status 2", 
			   setGameStatusTest(2) );	// 2 = draw
	    break;
	case 6 :			// 6. set Game playing
	    logTestResult( "1.6 test Game Status -1", 
			   setGameStatusTest(-1) );	// -1 = playing
	    break;
	case 7 :			// 7. resize GameBoard(increment +50x50 pixels)
	    logTestResult( "1.7 resize GameBoard",
			   setSizeTest(((GameBoard)OUT).getWidth() + 50, 
				       ((GameBoard)OUT).getHeight() + 50) );
	    break;
	case 8:			// 8. Test mouse up (x=25, y=25)
	    logTestResult( "1.8 Test mouse up (x=25, y=25)",
			   mouseUpTest(25,25) );
	    break;
	case 9:			// 9. Test mouse Script 
	    logTestResult( "1.9 Test mouse up (x=25, y=25)",
			   mouseUpScript() );
	    break;
	case 10:			// 10. set Player ID == 0 
	    logTestResult( " 1.10 set Player ID == 0",
			   setPlayerIDTest(0) );
	    break;
	case 11:			// 11. set Player ID == 1
	    logTestResult( " 1.11 set Player ID == 1",
			   setPlayerIDTest(1) );
	    break;
	case 12:			// 12. setMove(2) test 
	    logTestResult( " 1.12 setMove(2) test  ",
			   setMoveTest(2) );
	    break;
	default :
	    super.testDispatch(which);
	    break;  
	}
	
    }
 
    //--------------------------------------------------------------
    // The following are test scripts to be used with GameBoard.java
    // tests Scripts return boolean and do not take parameters.
  
    public boolean functionalSuite(){
        instantiateOUT();
	
	//  testScript2();
	//  testScript3();
	//  testScript4();
	
	return true;
    }

    // shape of code for coverage
    public boolean structuralSuite(){return false;}

    // interaction w/ another class
    public boolean interactionSuite(){return false;}
    
    // Preconditions: N/A
    // Symantics: getters and setters - anything that you use latter
    // Postcondition: GameBoard object, OUT, is instantiated
    //                playerID is set to 1
    //                gameStatus is playing, -1
    public boolean baselineSuite(){
	boolean result, tmp;

	logInfo("baseline test suit results: " );

	tmp = instantiateOUT();
	logTestResult ( "creating GameBoard", tmp );
	result = tmp && classInvariant();

	tmp = setPlayerIDTest(0);
	logTestResult ( "setPlayerIDTest(0)", tmp );
	result &= tmp && classInvariant();

	tmp = setPlayerIDTest(1); 
	logTestResult ( "setPlayerIDTest(1)", tmp );
	result &= tmp && classInvariant();

	tmp = setGameStatusTest(0); // Game is lost
	logTestResult ( "setGameStatusTest(0)", tmp );
	result &= tmp && classInvariant();

	tmp = setGameStatusTest(2); // Game is a draw
	logTestResult ( "setGameStatusTest(2)", tmp );
	result &= tmp && classInvariant();

	tmp = setGameStatusTest(-1); // Game is a playing
	logTestResult ( "setGameStatusTest(-1)", tmp );
	result &= tmp && classInvariant();

	return result;
    }

    // small representative test
    public boolean regressionSuite(){
	boolean result, tmp;

	logInfo("\tRegression suit results: " );

	tmp = instantiateOUT();
	logTestResult ( "creating GameBoard", tmp );
	result = tmp && classInvariant();

	tmp = mouseUpScript();
	logTestResult ( "MouseUpScript", tmp );
	result &= tmp && classInvariant();

	tmp = setGameStatusTest(1);
	logTestResult ( "setGameStatusTest(1)", tmp );
	result &= tmp && classInvariant();

	return result;
    }
    
    // -------------------------------------------------------------
    // The following are tests scripts which use the individual tests.  
    // Most of these take do not take a paramater and return a boolean.
    // The test scripts attempt to follow a nameing convention
    // which is the name method they followed by the postfix - script.

    // Precondition: The GameBoard object, OUT, is instantiated.
    // Postcondition:  Returns boolean value of the classInvariant test.
    //                 classInvariant will also print to the log if the 
    //                 test has failed.
    public boolean classInvariant(){
	
	boolean result;
	
	try {
	    int gameStatus 
		= ((Integer)(getPrivateField(OUT, "GameBoard","gameStatus"))).intValue();
	    boolean invariant1 =  ( gameStatus >= -1 && 
				    gameStatus <= 2 );
	    
	    boolean invariant2 = ((GameBoard)OUT).playerID >= -1 ;
	    
	    result = (invariant1 && invariant2);
	    
	} catch (Exception e) {
	    e.printStackTrace();
	    result = false;
	}

	if ( !result ) {
	    logTestResult("GameBoard::classInvariant", result);
	    showFieldValues(OUT, "GameBoard");  
	}

	return result;
    }
   
    public boolean instantiateOUT(){
	boolean result;
	
	try{
	    OUT = new GameBoard();
	    result = showGameBoardTest();
	    logTestResult("instantiateOUT",result);
	}
	catch(Exception e) {
	    e.printStackTrace();
	    result = false;
	}
	
	return result;
    }
    
    // Precondition: The GameBoard object, OUT, is instantiated
    // Postcondition: playerID is set to either 0 or 1
    //                mouseUpTest is executed over each gameboard Position
    protected boolean mouseUpScript() {
	boolean result = true;
	boolean tmp1, tmp2;

	try {
	    for ( int i = 0; i < ((GameBoard)OUT).position.length ; i++ ) {
		// alternate playerID = 0 and 1
		tmp1 = setPlayerIDTest( i % 2 );
		if ( !tmp1 )
		    logTestResult( "mouseUpScript: setPlayerIDTest("+i+")", 
				   tmp1 );	
		
		tmp2 = mouseUpTest (((GameBoard)OUT).position[i]);
		logTestResult( "mouseUpScript: position["+i+"]", 
			       tmp2 );

		result &= tmp1 && tmp2 && classInvariant();
	    }
	}
	catch (Exception e ) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}
	return result;
    }


    // -------------------------------------------------------------
    // The following are individual tests.  Most of these take 
    // a paramater and can be used in a test Script.
    // the individual tests attempt to follow a nameing scheme
    // which is the name of primary method they exercise followed
    // by the postfix - test.

 
    protected boolean showGameBoardTest(){
	boolean result;

	try {
	    ((GameBoard)OUT).setSize(160, 160);
	    ((GameBoard)OUT).setVisible(true); 
	    result = ((GameBoard)OUT).isVisible();
	}
	catch(Exception e) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}

	return result;
    }

    public boolean setGameStatusTest(int status){
 
	//legal status values are
	// -1=playing, 0=lost, 1=won, 2=draw
	boolean result;

	try {
	    ((GameBoard)OUT).setGameStatus(status);
	    int gameStatus 
		= ((Integer)(getPrivateField(OUT, "GameBoard","gameStatus"))).intValue();
	    result = (gameStatus == status) &&  classInvariant() ;
	} catch (Exception e) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}

	return result;
	
    }

    // Postcondition: calls java.awt.component.setSize
    public boolean setSizeTest(int width, int height) {
	boolean result;

	try {
	    boolean result1 =  ((GameBoard)OUT).isResizable();
	    logTestResult( " Game set to resizable ",
			   result1 );
	    
	    ((GameBoard)OUT).setSize(width, height );
	    // prompt user for confirmation - jlr
	    
	    result = result1 && classInvariant();
	}
	catch (Exception e ) { 
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}

	return result;
    }
    
    public boolean mouseDispatchTest(int x, int y) {
	boolean result;
	try {
	    MouseEvent mouseEvent = new MouseEvent( (GameBoard)OUT, // source
						    MouseEvent.MOUSE_CLICKED, // type
						    0, // when
						    InputEvent.BUTTON1_MASK, // modifier
						    x, // location
						    y, // location
						    1, // click count during time period
						    false // popupMenuTrigger
						    );

	    // NOTE: Events delivered using dispathEvent 
	    // bypass the system's event queue
	    ((GameBoard)OUT).dispatchEvent(mouseEvent);  

	    // could put a confirmation dialog box here - jlr
	    
	    result = true;
	}
	catch ( Exception e ) {  
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}

	return result;

    }

    // Precondition: The GameBoard object, OUT, is instantiated
    // Postcondition: returns true if the mouse event is sent and
    //                if a propertyChangeEvent is received.  
    //                Warning: will return false if x,y is not
    //                withing a gameboard position.
    protected boolean mouseUpTest(int x, int y) {
	boolean results;
	
	try {
	    PropertyChangeTestListener propertyChangeTest 
		= new PropertyChangeTestListener();
	    
	    ((GameBoard)OUT).addPropertyChangeListener( propertyChangeTest );
	    
	    boolean result1 = mouseDispatchTest(x,y);
	    logTestResult( "mouseUpScript: mouseDispatchTest( " + 
			   x + ", " + y + ")", 
			   result1 );
	    boolean result2 =  propertyChangeTest.isPropertyChangeReceived();
	    logTestResult( "mouseUpScript: isPropertyChangeReceived()", 
			   result2 );
	    if ( result2 ) {
  		PropertyChangeEvent pce = propertyChangeTest.getLastPropertyChangeEvent();
  		Move newMove = (Move)pce.getNewValue();
  		System.out.println(newMove.newPosition);
  	    }
	    results = result1 && result2;
	
	}
	catch ( Exception e ) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    results = false;
	}
		
	return results;

    }

    // Precondition: The GameBoard object, OUT, is instantiated  
    // Postcondition: returns true if the mouse event is sent and
    //                if a propertyChangeEvent is received.  
    protected boolean mouseUpTest ( GameBoardPosition position ) {

	return mouseUpTest(position.x, position.y);
	
    }

    protected boolean setPlayerIDTest( int newPlayerID ) {

	boolean result;

	try {
	    ((GameBoard)OUT).setPlayerID( newPlayerID );
	    int playerID 
		//  = ((Integer)(getPrivateField(OUT, "GameBoard", "playerID"))).intValue();
		= ((GameBoard)OUT).playerID;

	    result = (newPlayerID == playerID) ;
	}
	catch (Exception e) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    result = false;
	}

	return result;

    }

    protected boolean setMoveTest( int pos ) {
	boolean results;
	
	try {
	    PropertyChangeTestListener propertyChangeTest 
		= new PropertyChangeTestListener();
	    
	    ((GameBoard)OUT).addPropertyChangeListener( propertyChangeTest );
	    
	    Class parameterTypes[] =   { Integer.TYPE };
		
	    Object parameters[] = { new Integer(pos) };

	    invokePrivateMethod( OUT,   // object to invoke method on
				 "GameBoard", // object type
				 "setMove", // method name
				 parameterTypes,
				 parameters
				 );

	    logTestResult( "setMove: invokePrivateMethod( setMove )", 
			   true );
	    boolean result1 =  propertyChangeTest.isPropertyChangeReceived();
	    logTestResult( "setMove: isPropertyChangeReceived()", 
			   result1 );
	    if ( result1 ) {
  		PropertyChangeEvent pce = propertyChangeTest.getLastPropertyChangeEvent();
  		Move newMove = (Move)pce.getNewValue();
  		System.out.println(newMove.newPosition);
  	    }
	    results = result1;
	
	}
	catch ( Exception e ) {
	    showFieldValues(OUT, "GameBoard");
	    e.printStackTrace();
	    results = false;
	}
		
	return results;
    }
	
    

}





