package org.jenkinsci.plugins.ghprb.manager.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import jenkins.model.Jenkins;

import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Result;
import hudson.tasks.junit.TestResult;
import hudson.tasks.junit.TestResultAction;
import hudson.tasks.junit.CaseResult;
import hudson.tasks.test.AggregatedTestResultAction;
import hudson.tasks.test.AggregatedTestResultAction.ChildReport;

import org.jenkinsci.plugins.ghprb.GhprbTrigger;
import org.jenkinsci.plugins.ghprb.manager.configuration.JobConfiguration;
import org.jenkinsci.plugins.ghprb.manager.GhprbBuildManager;

/**
 * @author mdelapenya (Manuel de la Peña)
 */
public abstract class GhprbBaseBuildManager implements GhprbBuildManager {

    public GhprbBaseBuildManager(AbstractBuild<?, ?> build) {
        this.build = build;
        this.jobConfiguration = buildDefaultConfiguration();
    }

    public GhprbBaseBuildManager(AbstractBuild<?, ?> build, JobConfiguration jobConfiguration) {
        this.build = build;
        this.jobConfiguration = jobConfiguration;
    }

    private JobConfiguration buildDefaultConfiguration() {
        return JobConfiguration.builder().printStackTrace(false).build();
    }

    /**
     * Calculate the build URL of a build of default type. This will be overriden by specific build types.
     * 
     * @return the build URL of a build of default type
     */
    public String calculateBuildUrl(String publishedURL) {
        return publishedURL + "/" + build.getUrl();
    }

    /**
     * Return a downstream iterator of a build of default type. This will be overriden by specific build types.
     *
     * If the receiver of the call has no child projects, it will return an iterator over itself
     *
     * @return the downstream builds as an iterator
     */
    public Iterator<?> downstreamProjects() {
        List<AbstractBuild<?, ?>> downstreamList = new ArrayList<AbstractBuild<?, ?>>();

        downstreamList.add(build);

        return downstreamList.iterator();
    }

    public JobConfiguration getJobConfiguration() {
        return this.jobConfiguration;
    }

    /**
     * Return the tests results of a build of default type. This will be overriden by specific build types.
     *
     * @return the tests result of a build of default type
     */
    public String getTestResults() {
        return getAggregatedTestResults(build);
    }

    protected String getAggregatedTestResults(AbstractBuild<?, ?> build) {
        AggregatedTestResultAction testResultAction = build.getAction(AggregatedTestResultAction.class);

        if (testResultAction == null) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        if (build.getResult() != Result.UNSTABLE) {
            sb.append("<h2>Build result: ");
            sb.append(build.getResult().toString());
            sb.append("</span></h2>");

            try {
                List<String> buildLog = build.getLog(_MAX_LINES_COUNT);

                for (String buildLogLine : buildLog) {
                    sb.append(buildLogLine);
                }
            } catch (IOException ioe) {
                LOGGER.log(Level.WARNING, ioe.getMessage());
            }

            return sb.toString();
        }

        sb.append("<h2>Failed Tests: ");
        sb.append("<span class='status-failure'>");
        sb.append(testResultAction.getFailCount());
        sb.append("</span></h2>");

        List<ChildReport> childReports = testResultAction.getChildReports();

        for (ChildReport report : childReports) {
            TestResult result = (TestResult) report.result;

            if (result.getFailCount() < 1) {
                continue;
            }

            AbstractProject<?, ?> project = (AbstractProject<?, ?>) report.child.getProject();

            String baseUrl = Jenkins.getInstance().getRootUrl() + build.getUrl() + project.getShortUrl() + "testReport";

            sb.append("<h3>");
            sb.append("<a name='");
            sb.append(project.getFullName());
            sb.append("' />");
            sb.append("<a href='");
            sb.append(baseUrl);
            sb.append("'>");
            sb.append(project.getFullName());
            sb.append("</a>");
            sb.append(": ");
            sb.append("<span class='status-failure'>");
            sb.append(result.getFailCount());
            sb.append("</span></h3>");

            sb.append("<ul>");

            List<CaseResult> failedTests = result.getFailedTests();

            for (CaseResult failedTest : failedTests) {
                sb.append("<li>");
                sb.append("<a href='");
                sb.append(baseUrl);
                sb.append("/");
                sb.append(failedTest.getRelativePathFrom(result));
                sb.append("'>");
                sb.append("<strong>");
                sb.append(failedTest.getFullDisplayName());
                sb.append("</strong>");
                sb.append("</a>");

                if (getJobConfiguration().printStackTrace()) {
                    sb.append("\n```\n");
                    sb.append(failedTest.getErrorStackTrace());
                    sb.append("\n```\n");
                }

                sb.append("</li>");
            }

            sb.append("</ul>");
        }

        return sb.toString();
    }

    protected static final Logger LOGGER = Logger.getLogger(GhprbBaseBuildManager.class.getName());

    public String getOneLineTestResults() {

        TestResultAction testResultAction = build.getAction(TestResultAction.class);

        if (testResultAction == null) {
            return "No test results found.";
        }
        return String.format("%d tests run, %d skipped, %d failed.", testResultAction.getTotalCount(), testResultAction.getSkipCount(), testResultAction.getFailCount());
    }

    protected AbstractBuild<?, ?> build;

    private static final int _MAX_LINES_COUNT = 25;

    private JobConfiguration jobConfiguration;

}

@@ -359,38 +359,45 @@
 rt hudson.tasks.
-junit.
+test.Abstract
 TestResult;%0Aimpo
@@ -386,24 +386,30 @@
 ctTestResult
+Action
 ;%0Aimport hud
@@ -426,38 +426,32 @@
 junit.TestResult
-Action
 ;%0Aimport hudson.
@@ -5691,32 +5691,40 @@
 ts() %7B%0A%0A        
+Abstract
 TestResultAction
@@ -5759,16 +5759,24 @@
 tAction(
+Abstract
 TestResu

Fix "No test results found" in Github build status