/*
 * Copyright 2015-2016 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution and is available at
 *
 * http://www.eclipse.org/legal/epl-v10.html
 */

package org.junit.gen5.surefire;

import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
import static org.junit.gen5.engine.TestExecutionResult.Status.*;

import java.util.Optional;

import org.apache.maven.surefire.report.PojoStackTraceWriter;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.junit.gen5.engine.TestExecutionResult;
import org.junit.gen5.engine.support.descriptor.JavaSource;
import org.junit.gen5.launcher.TestExecutionListener;
import org.junit.gen5.launcher.TestIdentifier;

final class RunListenerAdapter implements TestExecutionListener {

	private RunListener runListener;

	public RunListenerAdapter(RunListener reporter) {
		this.runListener = reporter;
	}

	@Override
	public void executionStarted(TestIdentifier testIdentifier) {
		runListener.testStarting(createReportEntry(testIdentifier));
	}

	@Override
	public void executionSkipped(TestIdentifier testIdentifier, String reason) {
		runListener.testSkipped(
			ignored(getClassNameOrUniqueId(testIdentifier), testIdentifier.getDisplayName(), reason));
	}

	@Override
	public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
		if (testExecutionResult.getStatus() == SUCCESSFUL) {
			runListener.testSucceeded(createReportEntry(testIdentifier));
		}
		else if (testExecutionResult.getStatus() == ABORTED) {
			runListener.testAssumptionFailure(createReportEntry(testIdentifier, testExecutionResult.getThrowable()));
		}
		else {
			runListener.testFailed(createReportEntry(testIdentifier, testExecutionResult.getThrowable()));
		}
	}

	private SimpleReportEntry createReportEntry(TestIdentifier testIdentifier) {
		return new SimpleReportEntry(getClassNameOrUniqueId(testIdentifier), testIdentifier.getDisplayName());
	}

	private SimpleReportEntry createReportEntry(TestIdentifier testIdentifier, Optional<Throwable> throwable) {
		Optional<JavaSource> javaSource = getJavaSource(testIdentifier);
		if (javaSource.isPresent() && javaSource.get().getJavaClass().isPresent()) {
			Class<?> sourceClass = javaSource.get().getJavaClass().get();
			Optional<String> sourceMethodName = javaSource.get().getJavaMethodName();
			StackTraceWriter stackTraceWriter = getStackTraceWriter(sourceClass, sourceMethodName, throwable);
			return new SimpleReportEntry(getClassNameOrUniqueId(testIdentifier), testIdentifier.getDisplayName(),
				stackTraceWriter, null);
		}
		return ignored(getClassNameOrUniqueId(testIdentifier), testIdentifier.getDisplayName(),
			throwable.map(Throwable::getMessage).orElse(null));
	}

	private StackTraceWriter getStackTraceWriter(Class<?> sourceClass, Optional<String> sourceMethodName,
			Optional<Throwable> throwable) {
		String className = sourceClass.getName();
		String methodName = sourceMethodName.orElse("");
		return new PojoStackTraceWriter(className, methodName, throwable.orElse(null));
	}

	private String getClassNameOrUniqueId(TestIdentifier testIdentifier) {
		return getClassName(testIdentifier).orElse(testIdentifier.getUniqueId().toString());
	}

	private Optional<String> getClassName(TestIdentifier testIdentifier) {
		Optional<JavaSource> javaSource = getJavaSource(testIdentifier);
		if (javaSource.isPresent()) {
			if (javaSource.get().getJavaClass().isPresent()) {
				return javaSource.get().getJavaClass().map(Class::getName);
			}
		}
		return Optional.empty();
	}

	private Optional<JavaSource> getJavaSource(TestIdentifier testIdentifier) {
		return testIdentifier.getSource().filter(JavaSource.class::isInstance).map(JavaSource.class::cast);
	}
}

@@ -478,17 +478,94 @@
 .Status.
-*
+ABORTED;%0Aimport static org.junit.gen5.engine.TestExecutionResult.Status.FAILED
 ;%0A%0Aimpor
@@ -1289,24 +1289,58 @@
 entifier) %7B%0A
+%09%09if (testIdentifier.isTest()) %7B%0A%09
 %09%09runListene
@@ -1386,24 +1386,28 @@
 entifier));%0A
+%09%09%7D%0A
 %09%7D%0A%0A%09@Overri
@@ -1773,18 +1773,15 @@
  == 
-SUCCESSFUL
+ABORTED
 ) %7B%0A
@@ -1803,17 +1803,25 @@
 test
-Succeeded
+AssumptionFailure
 (cre
@@ -1841,32 +1841,68 @@
 y(testIdentifier
+, testExecutionResult.getThrowable()
 ));%0A%09%09%7D%0A%09%09else i
@@ -1895,21 +1895,16 @@
 ;%0A%09%09%7D%0A%09%09
-else 
 if (test
@@ -1926,37 +1926,36 @@
 .getStatus() == 
-ABORT
+FAIL
 ED) %7B%0A%09%09%09runList
@@ -1963,33 +1963,22 @@
 ner.test
-Assumption
 Fail
-ur
 e
+d
 (createR
@@ -2052,12 +2052,36 @@
 %7D%0A%09%09
-else
+if (testIdentifier.isTest())
  %7B%0A%09
@@ -2090,36 +2090,39 @@
 runListener.test
-Fail
+Succeed
 ed(createReportE
@@ -2144,44 +2144,8 @@
 fier
-, testExecutionResult.getThrowable()
 ));%0A

Fix test counts in Surefire Provider