/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.auraframework.test.mock;

import java.util.List;

import org.auraframework.throwable.AuraRuntimeException;

import com.google.common.collect.Lists;

/**
 * A stubbed method invocation that provides a sequence of Answers for a
 * sequence of matching method invocations.
 * 
 * @param <T> the type of the return value for the stubbed method
 */
public class Stub<T> {
	private final Invocation invocation;
	private final List<Answer<T>> answers;
	private int answerIndex;

	public Stub(Invocation invocation, List<Answer<T>> answers) {
		if (answers.isEmpty()) {
			throw new IllegalArgumentException(
					"Must provide at least one answer for a stub");
		}
		reset();
		this.invocation = invocation;
		this.answers = Lists.newLinkedList(answers);
	}

	public void reset() {
        this.answerIndex = 0;
	}
	
	/**
	 * Get the invocation that this stub applies to.
	 * @return
	 */
	public Invocation getInvocation() {
		return invocation;
	}

	/**
	 * Get the answer for the current method invocation. This Stub will provide
	 * each Answer in the initial list of Answers sequentially until the last
	 * answer is reached. Thereafter, the last answer will be provided for every
	 * subsequent call.
	 * 
	 * @return the Answer for the current method invocation
	 */
    public Answer<T> getNextAnswer() {
        if (answerIndex <= answers.size() - 1) {
        	Answer<T> ret = answers.get(answerIndex);
            answerIndex++;
            return ret;
        } else {
        	throw new AuraRuntimeException("You have "+answers.size()+" answers for mocking, but they are all exhausted");
        }
    }
}

@@ -1879,16 +1879,39 @@
 ocation%0A
+%09 * @throws Throwable %0A
 %09 */%0A   
@@ -1943,16 +1943,33 @@
 Answer()
+ throws Throwable
  %7B%0A     
@@ -2127,24 +2127,628 @@
    %7D else %7B%0A
+        %09Answer%3CT%3E lastAnswer = answers.get(answers.size() - 1);%0A        %09Object value = lastAnswer.answer();%0A        %09String extraMessage = %22%22;%0A        %09if(value instanceof MockModel) %7B%0A        %09%09value = (MockModel)value;%0A        %09%09extraMessage = ((MockModel) value).getDescriptor().getQualifiedName();%0A        %09%7D else if (value instanceof MockAction)%7B%0A        %09%09value = (MockAction)value;%0A        %09%09extraMessage = ((MockAction) value).getDescriptor().getQualifiedName();%0A        %09%7D else %7B%0A        %09%09extraMessage = %22**New mock type other than Action or Model, please update the type here**%22;%0A        %09%7D%0A
         %09thr
@@ -2823,16 +2823,45 @@
  mocking
+ %22+extraMessage%0A        %09%09%09+%22
 , but th

add more msg when mock exhaust its answers. @rev gtorres@ @bug W-2795086@