package test.mockobjects.dynamic;

import junit.framework.*;

import com.mockobjects.*;
import com.mockobjects.dynamic.Callable;
import com.mockobjects.dynamic.Mock;
import com.mockobjects.util.*;

public class MockCallable implements Callable {
	
	private ExpectationCounter callCount = new ExpectationCounter("call.count");
	private ExpectationValue callMock = new ExpectationValue("call.mock");
	private ExpectationValue callMethodName = new ExpectationValue("call.methodName");
	private ExpectationList callArgs = new ExpectationList("call.args");
	private ReturnValue callResult = new ReturnValue("call.return");
	private Throwable callThrow = null;
	
	private ExpectationValue matchesMethodName = new ExpectationValue("matches.methodName");
	private ExpectationList matchesArgs = new ExpectationList("matches.args");
	private ReturnValue matchesResult = new ReturnValue("matches.return");
	private ExpectationCounter matchesCount = new ExpectationCounter("matches.count");
	
	private ExpectationCounter verifyCount = new ExpectationCounter("verify.count");
	private AssertionFailedError verifyError = null;
	
	private ReturnValue toStringResult = new ReturnValue("toString.return");
	
	
	public void setExpectedCallCount( int count ) {
		callCount.setExpected(count);	
	}
	
	public void setExpectedCall( Mock mock, String methodName, Object[] args ) {
		callMock.setExpected(mock);
		callMethodName.setExpected(methodName);
		callArgs.addExpectedMany(args);
	}
	
	public void setupCallReturn( Object result ) {
		callResult.setValue(result);
	}
	
	public void setupCallThrow( Throwable thrown ) {
		callThrow = thrown;
	}
	
	public Object call(Mock mock, String methodName, Object[] args) throws Throwable {
		callMock.setActual(mock);
		callMethodName.setActual(methodName);
		callArgs.addActualMany(args);
		callCount.inc();
		
		if( callThrow != null ) {
			throw callThrow;
		} else {
			return callResult.getValue();
		}
	}
	
	public void setExpectedMatches( String methodName, Object[] args ) {
		matchesMethodName.setExpected(methodName);
		matchesArgs.addExpectedMany(args);
	}
	
	public void setExpectedMatchesCount(int count) {
		matchesCount.setExpected(count);
	}
	
	public void setupMatchesReturn( boolean result ) {
		matchesResult.setValue(result);
	}
	
	public boolean matches(String methodName, Object[] args) {
		matchesMethodName.setActual(methodName);
		matchesArgs.addActualMany(args);
		matchesCount.inc();
		return matchesResult.getBooleanValue();
	}

	public void setExpectedVerifyCalls( int count ) {
		verifyCount.setExpected(count);
	}

	public void setupVerifyThrow( AssertionFailedError err ) {
		verifyError = err;
	}
	
	/** @deprecated to avoid calling verify instead of verifyExpectations
	 */
	public void verify() {
		verifyCount.inc();
		if( verifyError != null ) throw verifyError;
	}
	
	/** We have to rename 'verify' because we want to mock the behaviour of the
	 *  verify method itself.
	 */
	public void verifyExpectations() {
		Verifier.verifyObject(this);
	}
	
	public void setupGetDescription( String result ) {
		toStringResult.setValue(result);
	}
	
	public String getDescription() {
		return (String)toStringResult.getValue();
	}
}
