package hudson.plugins.jira;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import hudson.plugins.jira.model.JiraIssue;
import org.apache.commons.lang.StringUtils;

import hudson.Extension;
import hudson.MarkupText;
import hudson.Util;
import hudson.model.Job;
import hudson.model.Run;
import hudson.scm.ChangeLogAnnotator;
import hudson.scm.ChangeLogSet.Entry;

/**
 * {@link ChangeLogAnnotator} that picks up JIRA issue IDs.
 *
 * @author Kohsuke Kawaguchi
 */
@Extension
public class JiraChangeLogAnnotator extends ChangeLogAnnotator {

    private static final Logger LOGGER = Logger.getLogger(JiraChangeLogAnnotator.class.getName());

    public JiraChangeLogAnnotator() {
        super();
        LOGGER.fine("JiraChangeLogAnnotator created");
    }

    @Override
    public void annotate(Run<?, ?> build, Entry change, MarkupText text) {
        JiraSite site = getSiteForProject(build.getParent());
        
        if (site == null) {
            LOGGER.fine("not configured with JIRA");
            return;    // not configured with JIRA
        }

        LOGGER.log(Level.FINE, "Using site: {0}", site.getUrl());

        // if there's any recorded detail information, try to use that, too.
        JiraBuildAction a = build.getAction(JiraBuildAction.class);

        Set<JiraIssue> issuesToBeSaved = new LinkedHashSet<>();

        Pattern pattern = site.getIssuePattern();

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Using issue pattern: " + pattern);
        }

        String plainText = text.getText();

        Matcher m = pattern.matcher(plainText);

        while (m.find()) {
            if (m.groupCount() >= 1) {

                String id = m.group(1);

                if (StringUtils.isNotBlank(site.userName) && !site.existsIssue(id)) {
                    LOGGER.log(Level.INFO, "No known JIRA project corresponding to id: ''{0}''", id);
                    continue;
                }

                LOGGER.log(Level.INFO, "Annotating JIRA id: ''{0}''", id);

                URL url, alternativeUrl;
                try {
                    url = site.getUrl(id);
                } catch (MalformedURLException e) {
                    throw new AssertionError(e); // impossible
                }

                try {
                    alternativeUrl = site.getAlternativeUrl(id);
                    if (alternativeUrl != null) {
                        url = alternativeUrl;
                    }
                } catch (MalformedURLException e) {
                    LOGGER.log(Level.WARNING, "Failed to construct alternative URL for Jira link. " + e.getMessage());
                    // This should not fail, since we already have an URL object. Exceptions would happen elsewhere.
                    throw new AssertionError(e);
                }

                JiraIssue issue = null;
                if (a != null) {
                    issue = a.getIssue(id);
                }

                if (issue == null) {
                    try {
                        issue = site.getIssue(id);
                        if (issue != null) {
                            issuesToBeSaved.add(issue);
                        }
                    } catch (Exception e) {
                        LOGGER.log(Level.WARNING, "Error getting remote issue " + id, e);
                    }
                }

                if (issue == null) {
                    text.addMarkup(m.start(1), m.end(1), "<a href='" + url + "'>", "</a>");
                } else {
                    text.addMarkup(m.start(1), m.end(1),
                            String.format("<a href='%s' tooltip='%s'>", url, Util.escape(issue.getSummary())), "</a>");
                }

            } else {
                LOGGER.log(Level.WARNING, "The JIRA pattern " + pattern + " doesn't define a capturing group!");
            }
        }

        if (!issuesToBeSaved.isEmpty()) {
            saveIssues(build, a, issuesToBeSaved);
        }
    }

    private void saveIssues(Run<?, ?> build, JiraBuildAction a,
                            Set<JiraIssue> issuesToBeSaved) {
        if (a != null) {
            a.addIssues(issuesToBeSaved);
        } else {
            JiraBuildAction action = new JiraBuildAction(build, issuesToBeSaved);
            build.addAction(action);
        }

        try {
            build.save();
        } catch (final IOException e) {
            LOGGER.log(Level.WARNING, "Error saving updated build", e);
        }
    }

    JiraSite getSiteForProject(Job<?, ?> project) {
        return JiraSite.get(project);
    }
}

@@ -3493,39 +3493,36 @@
 OGGER.log(Level.
-WARNING
+FINE
 , %22Error getting

Set log level to FINE.