/*
 * Created on 04-Apr-2003
 */
package com.mockobjects.dynamic;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


public class CallBag extends CallCollection implements Callable, CallableAddable {
	private List expectedCalls = new ArrayList();
	private List expectedMatches = new ArrayList();

	public CallBag() {
	}

    public void reset() {
        this.expectedCalls.clear();
        this.expectedMatches.clear();
    }

	public Object call(Mock mock, String methodName, Object[] args)
		throws Throwable {
			
		Callable matchingCall = findMatchingCall(methodName, args, this.expectedCalls);
		if(matchingCall == null) {
			matchingCall = findMatchingCall(methodName, args, this.expectedMatches);
		}
		if(matchingCall == null) {
			throw createUnexpectedCallError(methodName, args);
		}
		
		return matchingCall.call(mock, methodName, args);
		
	}

	private Callable findMatchingCall(String methodName, Object[] args, List callList) {
		for (Iterator call = callList.iterator(); call.hasNext();) {
			Callable element = (Callable) call.next();

			if (element.matches(methodName, args)) {
				return element;
			}
		}

		return null;
	}

	public String getDescription() {
		if (this.expectedCalls.isEmpty()) {
			return "no methods";
		} else {
			StringBuffer buf = new StringBuffer();

			buf.append("one of:\n");

			for (Iterator i = this.expectedCalls.iterator(); i.hasNext();) {
				buf.append(((Callable) i.next()).getDescription());
				buf.append("\n");
			}

			return buf.toString();
		}
	}

	public boolean matches(String methodName, Object[] args) {
		throw new Error("not implemented");
	}

	public void verify() {
		for (Iterator call = this.expectedCalls.iterator(); call.hasNext();) {
			Callable element = (Callable) call.next();
			element.verify();
		}
	}

	public void addExpect(Callable call) {
		this.expectedCalls.add(call);
	}

	public void addMatch(Callable call) {
		this.expectedMatches.add(call);
	}
}
