import java.beans.*;  
import java.lang.reflect.*;

public abstract class AbstractBeanTest 
    extends AbstractTest{

    protected boolean vetoableChangeReceived = false;
    protected PropertyChangeEvent lastVetoChangeEvent = null;
    protected boolean validVetoableChange = false;

    protected boolean propertyChangeReceived = false;
    protected PropertyChangeEvent lastPropertyChangeEvent = null;

    public AbstractBeanTest( String reportFile ) {
	super(reportFile);
    }

    // Precondition: OUT declares the standard Bean method
    //               addVetoableChangeListener.
    // Postcondition: a VetoableChangeListener is created and
    //                will call vetoChange when a vetoableChangeEvent 
    //                is fired
    public void addVetoableChangeTest(Object OUT, 
					  String OutClassName ) 
	throws NoSuchMethodException, ClassNotFoundException,
	       InvocationTargetException {

	    Class OUTClass = Class.forName(OutClassName);
	    
	    try {
		
		Class parameterTypes[] = {Class.forName("VetoableChangeListener")} ;
		
		Method addVetoMethod 
		    = OUTClass.getDeclaredMethod( "addVetoableChangeListener",
						  parameterTypes );

		Object args[] = new Object[1];
		// set up vetoChange to be called whenever a 
		// VetoableChangeEvent occurs.
		args[1] = new VetoableChangeListener() {
		    public void vetoableChange(PropertyChangeEvent evt) 
		    throws PropertyVetoException {
			vetoChange( evt );
		    }		
		};
		
		addVetoMethod.invoke( OUT, args);
		
	    }
	    catch ( SecurityException se ){
		System.err.println("Use the JDK policyTool to " + 
				   "check your .java.policy file" );
		System.err.println(se);
		se.printStackTrace();
	    }
	    catch ( IllegalAccessException ie ){
		System.err.println("Use the JDK policyTool to " + 
				   "check your .java.policy file" );
		System.err.println(ie);
		ie.printStackTrace();
	    }
      
    }

   
    // Precondition: OUT declares the standard Bean method
    //               removeVetoableChangeListener and BeanTest::
    //               addVetoableChangeListener has been called.
    // Postcondition: A call to OUT.removeVetoableChangeTest is made
    public void removeVetoableChangeTest(Object OUT, 
					 String OutClassName ) {
					  // Left as an Exercise
    }


    // Precondition: vetoChange is called when a vetoableChange 
    //               event occurs.
    // Postcondition: records the event and throws an exception if
    //                isValidVetoableChange() == false
    public void vetoChange(PropertyChangeEvent evt) 
	throws PropertyVetoException {
	
	lastVetoChangeEvent = evt;
	vetoableChangeReceived = true;

	if ( !isValidVetoableChange() ) {
	    throw new PropertyVetoException("Invalid Change", evt);
	}
	
    }

    // feel free to override.
    protected boolean isValidVetoableChange() {
	return validVetoableChange;
    }

    protected void setValidVetoableChange( boolean newChange) {
	validVetoableChange = newChange;
    }

    protected PropertyChangeEvent getLastVetoChangeEvent() {
	return lastVetoChangeEvent;
    }
    
    protected void resetVetoChangeEvent() {
	lastVetoChangeEvent = null;
	vetoableChangeReceived = false;
    }

    // Precondition:  should ussually call resetVetoChangeEvent 
    //                before receiving/dispatching event and calling this.
    // Postcondition: checks for vetoableChangeEvent for at least
    //                5 secs.  Returns true if vetoableChangeEvent
    //                was received.
    public boolean isVetoableChangeReceived() {
	java.lang.Object sync = new java.lang.Object();

	for (int i = 0; ( vetoableChangeReceived || 
			  i < 10 ); i++ ) {
	    try {
		synchronized( sync) { sync.wait(500); }
	    }
	    catch (InterruptedException e ) {}
	}	    

	return vetoableChangeReceived;
    }
  
    // Precondition: OUT declares the standard Bean method
    //               addPropertyChangeListener.
    // Postcondition: a PropertyChangeListener is created and
    //                will call propertyChange when a vetoableChangeEvent 
    //                is fired
    public void addPropertyChangeTest( Object OUT, 
				       String OutClassName ) 
	throws NoSuchMethodException, ClassNotFoundException,
	       InvocationTargetException {

	Class OUTClass = Class.forName(OutClassName);
	    
	try {
	    Class parameterTypes[] = new Class[1];
	    parameterTypes[0] = Class.forName("java.beans.PropertyChangeListener");
	    
	    Method addPropertyMethod 
		= OUTClass.getDeclaredMethod( "addPropertyChangeListener",
					      parameterTypes );
	    
	    Object args[] = new Object[1];
	    // set up propertyChange to be called whenever a 
	    // PropertyChangeEvent occurs.
	    args[0] = new PropertyChangeListener() {
		public void propertyChange(PropertyChangeEvent evt) {
		    propertyChange( evt );
		}		
	    };
		
	    addPropertyMethod.invoke( OUT, args);
		
	    }
	    catch ( SecurityException se ) {
		System.err.println("Use the JDK policyTool to " + 
				   "check your .java.policy file" );
		System.err.println(se);
		se.printStackTrace();
	    }
	    catch ( IllegalAccessException ie ){
		System.err.println("Use the JDK policyTool to " + 
				   "check your .java.policy file" );
		System.err.println(ie);
		ie.printStackTrace();
	    }
	    
    }

   
    // Precondition: OUT declares the standard Bean method
    //               removePropertyChangeListener and BeanTest::
    //               addPropertyChangeListener has been called.
    // Postcondition: A call to OUT.removePropertyChangeTest is made
    public void removePropertyChangeTest(Object OUT, 
					 String OutClassName ) {
					  // Left as an Exercise
    }


    // Precondition: propertyChange is called when a 
    //               PropertyChangeEvent occurs.
    // Postcondition: records the event and sets 
    //                sets propertyChangeReceived = true
    protected void propertyChange(PropertyChangeEvent evt) {
	
	propertyChangeReceived = true;
	lastPropertyChangeEvent = evt;
    }

    protected PropertyChangeEvent getLastPropertyChangeEvent() {
	return lastPropertyChangeEvent;
    }
      
    protected void resetPropertyChangeEvent() {
	lastPropertyChangeEvent = null;
	propertyChangeReceived = false;
    }

    // Precondition:  should ussually call resetPropertyChangeEvent 
    //                before receiving/dispatching event and calling this.
    // Postcondition: checks for propertyChangeEvent received for at least
    //                5 secs.  Returns true if vetoableChangeEvent
    //                was received.
    public boolean isPropertyChangeReceived() {
	java.lang.Object sync = new java.lang.Object();

	for (int i = 0; ( propertyChangeReceived || 
			  i < 10 ); i++ ) {
	    try {
		synchronized( sync ) { sync.wait(500); }
	    }
	    catch (Exception e ) {
		e.printStackTrace();
		return false;
	    }
	}	    

	return propertyChangeReceived;
    }
   
    public abstract void functionalSuite();
    public abstract void structuralSuite();
    public abstract void interactionSuite();
    public abstract void baselineSuite();
    public abstract void regressionSuite();
    public abstract boolean classInvariant();

}

