package org.jenkinsci.plugins.ghprb;

import hudson.model.AbstractBuild;
import hudson.model.Cause;
import hudson.model.Result;
import hudson.model.queue.QueueTaskFuture;
import hudson.plugins.git.util.BuildData;

import org.apache.commons.io.FileUtils;

import org.kohsuke.github.GHCommitState;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHUser;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author janinko
 */
public class GhprbBuilds {
    private static final Logger logger = Logger.getLogger(GhprbBuilds.class.getName());
    private final GhprbTrigger trigger;
    private final GhprbRepository repo;

    public GhprbBuilds(GhprbTrigger trigger, GhprbRepository repo) {
        this.trigger = trigger;
        this.repo = repo;
    }

    public String build(GhprbPullRequest pr, GHUser triggerSender, String commentBody) {
        StringBuilder sb = new StringBuilder();
        if (cancelBuild(pr.getId())) {
            sb.append("Previous build stopped.");
        }

        if (pr.isMergeable()) {
            sb.append(" Merged build triggered.");
        } else {
            sb.append(" Build triggered.");
        }

        GhprbCause cause = new GhprbCause(pr.getHead(), pr.getId(), 
        		pr.isMergeable(), pr.getTarget(), pr.getSource(), 
        		pr.getAuthorEmail(), pr.getTitle(), pr.getUrl(),
        		triggerSender, commentBody, pr.getCommitAuthor());

        QueueTaskFuture<?> build = trigger.startJob(cause, repo);
        if (build == null) {
            logger.log(Level.SEVERE, "Job did not start");
        }
        return sb.toString();
    }

    private boolean cancelBuild(int id) {
        return false;
    }

    private GhprbCause getCause(AbstractBuild<?,?> build) {
        Cause cause = build.getCause(GhprbCause.class);
        if (cause == null || (!(cause instanceof GhprbCause))) return null;
        return (GhprbCause) cause;
    }

    public void onStarted(AbstractBuild<?,?> build, PrintStream logger) {
        GhprbCause c = getCause(build);
        if (c == null) {
            return;
        }

        repo.createCommitStatus(build, GHCommitState.PENDING, (c.isMerged() ? "Merged build started." : "Build started."), c.getPullID());
        try {
            build.setDescription("<a title=\"" + c.getTitle() + "\" href=\"" + c.getUrl() + "\">PR #" + c.getPullID() + "</a>: " + c.getAbbreviatedTitle());
        } catch (IOException ex) {
            logger.println("Can't update build description");
            ex.printStackTrace(logger);
        }
    }

    public void onCompleted(AbstractBuild<?,?> build, PrintStream logger) {
        GhprbCause c = getCause(build);
        if (c == null) {
            return;
        }

        // remove the BuildData action that we may have added earlier to avoid
        // having two of them, and because the one we added isn't correct
        // @see GhprbTrigger
        BuildData fakeOne = null;
        for (BuildData data : build.getActions(BuildData.class)) {
            if (data.getLastBuiltRevision() != null && !data.getLastBuiltRevision().getSha1String().equals(c.getCommit())) {
                fakeOne = data;
                break;
            }
        }
        if (fakeOne != null) {
            build.getActions().remove(fakeOne);
        }

        GHCommitState state;
        if (build.getResult() == Result.SUCCESS) {
            state = GHCommitState.SUCCESS;
        } else if (build.getResult() == Result.UNSTABLE) {
            state = GHCommitState.valueOf(GhprbTrigger.getDscp().getUnstableAs());
        } else {
            state = GHCommitState.FAILURE;
        }
        repo.createCommitStatus(build, state, (c.isMerged() ? "Merged build finished." : "Build finished."), c.getPullID());

        String publishedURL = GhprbTrigger.getDscp().getPublishedURL();
        if (publishedURL != null && !publishedURL.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            
            String commentFilePath = trigger.getCommentFilePath();
            
            if (commentFilePath != null && !commentFilePath.isEmpty()) {
                try {
                    String scriptFilePathResolved = Ghprb.replaceMacros(build, commentFilePath);
                    
                    String content = FileUtils.readFileToString(new File(scriptFilePathResolved));
                	msg.append("Build comment file: \n--------------\n");
                    msg.append(content);
                    msg.append("\n--------------\n");
                } catch (IOException e) {
					msg.append("\n!!! Couldn't read comment file !!!\n");
                    logger.println("Couldn't read comment file");
                    e.printStackTrace(logger);
                }
            }
            
            
            if (state == GHCommitState.SUCCESS) {
                msg.append(GhprbTrigger.getDscp().getMsgSuccess(build));
            } else {
                msg.append(GhprbTrigger.getDscp().getMsgFailure(build));
            }

            msg.append("\nRefer to this link for build results (access rights to CI server needed): \n");

            msg.append(calculateBuildUrl(build));

            int numLines = GhprbTrigger.getDscp().getlogExcerptLines();
            if (state != GHCommitState.SUCCESS && numLines > 0) {
                // on failure, append an excerpt of the build log
                try {
                    // wrap log in "code" markdown
                    msg.append("\n\n**Build Log**\n*last ").append(numLines).append(" lines*\n");
                    msg.append("\n ```\n");
                    List<String> log = build.getLog(numLines);
                    for (String line : log) {
                        msg.append(line).append('\n');
                    }
                    msg.append("```\n");
                } catch (IOException ex) {
                    logger.println("Can't add log excerpt to commit comments");
                    ex.printStackTrace(logger);
                }
            }
            logger.println(msg);
            repo.addComment(c.getPullID(), msg.toString());
        }

        // close failed pull request automatically
        if (state == GHCommitState.FAILURE && trigger.isAutoCloseFailedPullRequests()) {

            try {
                GHPullRequest pr = repo.getPullRequest(c.getPullID());

                if (pr.getState().equals(GHIssueState.OPEN)) {
                    repo.closePullRequest(c.getPullID());
                }
            } catch (IOException ex) {
            	logger.println("Can't close pull request");
                ex.printStackTrace(logger);
            }
        }
    }

    private String calculateBuildUrl(AbstractBuild build) {
        GhprbBuildUrlManager buildManager =
            GhprbBuildUrlManagerFactoryUtil.getBuildManager(build);

        return buildManager.calculateBuildUrl();
    }
}

@@ -5362,33 +5362,41 @@
 .append(
-calculateBuildUrl
+generateCustomizedMessage
 (build))
@@ -6911,33 +6911,41 @@
  String 
-calculateBuildUrl
+generateCustomizedMessage
 (Abstrac

Rename method to be more generic