/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.sling.performance;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.naming.directory.InvalidAttributesException;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.apache.sling.performance.annotation.AfterMethodInvocation;
import org.apache.sling.performance.annotation.BeforeMethodInvocation;
import org.apache.sling.performance.annotation.PerformanceTest;
import org.junit.After;
import org.junit.Before;
import org.junit.runners.model.FrameworkMethod;

class FrameworkPerformanceMethod extends FrameworkMethod {

	private Object target;
	private PerformanceSuiteState performanceSuiteState;
	private PerformanceRunner.ReportLevel reportLevel = PerformanceRunner.ReportLevel.ClassLevel;

	public FrameworkPerformanceMethod(Method method, Object target,
			PerformanceSuiteState performanceSuiteState, PerformanceRunner.ReportLevel reportLevel) {
		super(method);
		this.target = target;
		this.performanceSuiteState = performanceSuiteState;
		this.reportLevel = reportLevel;
	}

	@Override
	public Object invokeExplosively(Object target, Object... params)
			throws Throwable {
		// Executes the test method on the supplied target

		// Check if this is the first test running from this specific
		// PerformanceSuite
		// and run the BeforeSuite methods
		if ((performanceSuiteState != null)
				&& (performanceSuiteState.getBeforeSuiteMethod() != null)
				&& (performanceSuiteState.getTargetObjectSuite() != null)
				&& (performanceSuiteState.getNumberOfExecutedMethods() == 0)
				&& !performanceSuiteState.testSuiteName
						.equals(ParameterizedTestList.TEST_CASE_ONLY)) {
			performanceSuiteState.getBeforeSuiteMethod().invoke(
					performanceSuiteState.getTargetObjectSuite());
		}

		// In case of a PerformanceSuite we need to run the methods annotated
		// with Before and After
		// ourselves as JUnit can't find them (JUnit is looking for them in the
		// test suite class);
		// in case we don't have to deal with a PerformanceSuite just skip this
		// as JUnit will run the methods itself
		if ((performanceSuiteState != null)
				&& !performanceSuiteState.testSuiteName
						.equals(ParameterizedTestList.TEST_CASE_ONLY)) {

			recursiveCallSpecificMethod(this.target.getClass(), this.target,
					Before.class);
		}

		// Need to count the number of tests run from the PerformanceSuite
		// so that we can call the AfterSuite method after the last test from
		// the suite
		// has run and the AfterSuite needs to run
		performanceSuiteState.incrementNumberOfExecutedTestMethods();

		Object response = null;

		Method testMethodToInvoke = this.getMethod();

		PerformanceTest performanceAnnotation = testMethodToInvoke
				.getAnnotation(PerformanceTest.class);

		// retrieve the test configuration options
		int warmuptime = performanceAnnotation.warmuptime();
		int runtime = performanceAnnotation.runtime();
		int warmupinvocations = performanceAnnotation.warmupinvocations();
		int runinvocations = performanceAnnotation.runinvocations();

		DescriptiveStatistics statistics = new DescriptiveStatistics();

		// System.out.println("Warmup started - test :" +
		// testMethodToInvoke.getName());

		if (warmupinvocations != 0) {
			// Run the number of invocation specified in the annotation
			// for warming up the system
			for (int invocationIndex = 0; invocationIndex < warmupinvocations; invocationIndex++) {

				recursiveCallSpecificMethod(this.target.getClass(),
						this.target, BeforeMethodInvocation.class);

				// TODO: implement the method to run a before a specific test
				// method
				// recursiveCallSpecificMethod(this.target.getClass(),
				// this.target, BeforeSpecificTest.class);

				response = super.invokeExplosively(this.target, params);

				// TODO: implement the method to run a after a specific test
				// method
				// recursiveCallSpecificMethod(this.target.getClass(),
				// this.target, AfterSpecificTest.class);

				recursiveCallSpecificMethod(this.target.getClass(),
						this.target, AfterMethodInvocation.class);
			}
		} else {
			// Run a few iterations to warm up the system
			long warmupEnd = System.currentTimeMillis() + warmuptime * 1000;
			while (System.currentTimeMillis() < warmupEnd) {
				recursiveCallSpecificMethod(this.target.getClass(),
						this.target, BeforeMethodInvocation.class);

				// TODO: implement the method to run a before a specific test
				// method
				// recursiveCallSpecificMethod(this.target.getClass(),
				// this.target, BeforeSpecificTest.class);

				response = super.invokeExplosively(this.target, params);

				// recursiveCallSpecificMethod(this.target.getClass(),
				// this.target, AfterSpecificTest.class);
				// TODO: implement the method to run a after a specific test
				// method

				recursiveCallSpecificMethod(this.target.getClass(),
						this.target, AfterMethodInvocation.class);
			}
		}

		// System.out.println("Warmup ended - test :" +
		// testMethodToInvoke.getName());
		if (runinvocations != 0) {
			// Run the specified number of iterations and capture the execution
			// times
			for (int invocationIndex = 0; invocationIndex < runinvocations; invocationIndex++) {

				response = this.invokeTimedTestMethod(testMethodToInvoke,
						statistics, params);
			}
		} else {
			// Run test iterations and capture the execution times
			long runtimeEnd = System.currentTimeMillis() + runtime * 1000;

			while (System.currentTimeMillis() < runtimeEnd) {

				response = this.invokeTimedTestMethod(testMethodToInvoke,
						statistics, params);

			}
		}

		if (statistics.getN() > 0) {
			ReportLogger
					.writeReport(this.target.getClass().getName(),
							this.performanceSuiteState.testSuiteName,
							getMethod().getName(), statistics,
							ReportLogger.ReportType.TXT, reportLevel);
		}

		// In case of a PerformanceSuite we need to run the methods annotated
		// with Before and After
		// ourselves as JUnit can't find them; in case we don't have to deal
		// with a PerformanceSuite
		// just skip this as JUnit will run the methods itself
		if ((performanceSuiteState != null)
				&& !performanceSuiteState.testSuiteName
						.equals(ParameterizedTestList.TEST_CASE_ONLY)) {

			recursiveCallSpecificMethod(this.target.getClass(), this.target,
					After.class);
		}

		// Check if this is the last test running from a PerformanceSuite
		// and run the AfterSuite method
		if ((performanceSuiteState != null)
				&& (performanceSuiteState.getAfterSuiteMethod() != null)
				&& (performanceSuiteState.getTargetObjectSuite() != null)
				&& (performanceSuiteState.getNumberOfExecutedMethods() == performanceSuiteState
						.getNumberOfMethodsInSuite())
				&& !performanceSuiteState.testSuiteName
						.equals(ParameterizedTestList.TEST_CASE_ONLY)) {
			performanceSuiteState.getAfterSuiteMethod().invoke(
					performanceSuiteState.getTargetObjectSuite());

		}

		return response;
	}

	/**
	 * Method that runs 1 invocation of the timed test method
	 * 
	 * @param testMethodToInvoke
	 *            the test method to invoke
	 * @param statistics
	 *            the statistics object that collects the results
	 * @param params
	 *            the parameters for the invocation of the test method
	 * @return the response from the method invocation
	 * @throws Throwable
	 */
	private Object invokeTimedTestMethod(Method testMethodToInvoke,
			DescriptiveStatistics statistics, Object... params)
			throws Throwable {

		Object response = null;

		recursiveCallSpecificMethod(this.target.getClass(), this.target,
				BeforeMethodInvocation.class);

		// TODO: implement the method to run a before a specific test method
		// recursiveCallSpecificMethod(this.target.getClass(), this.target,
		// BeforeSpecificTest.class);

		// timing the test method execution
		// System.out.println("Start test: " + testMethodToInvoke.getName());
		long start = System.nanoTime();
		response = super.invokeExplosively(this.target, params);
		long timeMilliseconds = TimeUnit.MILLISECONDS.convert(System.nanoTime()
				- start, TimeUnit.NANOSECONDS);
		statistics.addValue(timeMilliseconds);

		// System.out.println("End test: " + testMethodToInvoke.getName());

		// System.out.println("Test execution time (ms): " + timeMilliseconds);

		// TODO: implement the method to run a after a specific test method
		// recursiveCallSpecificMethod(this.target.getClass(), this.target,
		// AfterSpecificTest.class);

		recursiveCallSpecificMethod(this.target.getClass(), this.target,
				AfterMethodInvocation.class);

		return response;
	}

	/**
	 * Recursively call a specific method annotated with a custom annotation
	 * 
	 * @param test
	 *            the test class that contains the method
	 * @param instance
	 *            the instance on which will run the method
	 * @param methodAnnotation
	 *            the method annotation to look for
	 * @throws InvocationTargetException
	 * @throws InvalidAttributesException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	@SuppressWarnings({ "rawtypes" })
	private void recursiveCallSpecificMethod(Class test, Object instance,
			Class<? extends Annotation> methodAnnotation)
			throws InvocationTargetException, InvalidAttributesException,
			IllegalAccessException, InstantiationException {
		if (test.getSuperclass() != null) {
			recursiveCallSpecificMethod(test.getSuperclass(), instance,
					methodAnnotation);
		}

		Method testMethod = getSpecificTestMethod(test, methodAnnotation);
		if (testMethod != null) {
			if (!testMethod.isAccessible()) {
				testMethod.setAccessible(true);
			}
			testMethod.invoke(instance);
		}
	}

	/**
	 * Get the method annotated with the custom annotation
	 * 
	 * @param testClass
	 *            the test class on which to look for the method
	 * @param methodAnnotation
	 *            the method annotation to look for
	 * @return
	 * @throws InvalidAttributesException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	@SuppressWarnings({ "rawtypes" })
	private Method getSpecificTestMethod(Class testClass,
			Class<? extends Annotation> methodAnnotation)
			throws InvalidAttributesException, IllegalAccessException,
			InstantiationException {

		Method[] methodsToReturn = getSpecificMethods(testClass,
				methodAnnotation);
		Method methodToReturn = null;
		if (methodsToReturn.length == 1) {
			methodToReturn = methodsToReturn[0];
		} else if (methodsToReturn.length > 1) {
			throw new InvalidAttributesException(
					"Only 1 non parameterized before method accepted");
		}

		return methodToReturn;
	}

	/**
	 * Retrieve all the specific methods from test class
	 * 
	 * @param testClass
	 *            the test class that we need to search in
	 * @param annotation
	 *            the annotation that we should look for
	 * @return the list with the methods that have the specified annotation
	 */
	@SuppressWarnings({ "rawtypes" })
	private Method[] getSpecificMethods(Class testClass,
			Class<? extends Annotation> annotation) {
		Method[] allMethods = testClass.getDeclaredMethods();

		List<Method> methodListResult = new ArrayList<Method>();

		for (Method testMethod : allMethods) {
			if (testMethod.isAnnotationPresent(annotation)) {
				methodListResult.add(testMethod);
			}
		}
		return methodListResult.toArray(new Method[] {});
	}

}
