package org.jenkinsci.plugins.snsnotify;

import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
import hudson.Launcher;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

public class AmazonSNSNotifier extends Notifier {

    private final String projectTopicArn;

    @DataBoundConstructor
    public AmazonSNSNotifier(String projectTopicArn) {
        this.projectTopicArn = projectTopicArn;
    }

    public String getProjectTopicArn() {
        return projectTopicArn;
    }

    @Override
    public BuildStepMonitor getRequiredMonitorService() {
        return BuildStepMonitor.NONE;
    }

    @Override
    public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) {

        if (build.getResult() == Result.FAILURE || build.getResult() == Result.UNSTABLE) {

            String awsAccessKey = getDescriptor().getAwsAccessKey();
            String awsSecretKey = getDescriptor().getAwsSecretKey();
            String publishTopic = isEmpty(projectTopicArn) ? 
                getDescriptor().getDefaultTopicArn() : projectTopicArn;

            if (isEmpty(publishTopic)) {
                listener.error(
                        "No global or project topic ARN sent; cannot send SNS notification");
                return true;
            }

            if (isEmpty(awsAccessKey) || isEmpty(awsSecretKey)) {
                listener.error(
                        "AWS credentials not configured; cannot send SNS notification");
                return true;
            }

            String subject = truncate(
                    String.format("Build %s: %s", 
                        build.getResult().toString(), build.getFullDisplayName()), 100);

            String message = Hudson.getInstance().getRootUrl() == null ?
                Util.encode("(Global build server url not set)/" + build.getUrl()) :
                Util.encode(Hudson.getInstance().getRootUrl() + build.getUrl());

            AmazonSNSClient snsClient = new AmazonSNSClient(
                    new BasicAWSCredentials(awsAccessKey, awsSecretKey));
            try {
                PublishRequest pubReq = new PublishRequest(publishTopic, message, subject);
                snsClient.publish(pubReq);
            } catch (Exception e) {
                listener.error(
                        "Failed to send SNS notification: " + e.getMessage());
            } finally {
                snsClient.shutdown();
            }
        }

        return true;
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl)super.getDescriptor();
    }

    private String truncate(String s, int toLength) {
        if (s.length() > toLength) {
            return s.substring(0, toLength);
        }
        return s;
    }

    private boolean isEmpty(String s) {
        return s == null || s.trim().length() == 0;
    }

    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
        private String awsAccessKey;
        private String awsSecretKey;
        private String defaultTopicArn;

        public DescriptorImpl() {
            super(AmazonSNSNotifier.class);
            load();
        }

        @Override
        public String getDisplayName() {
            return "Amazon SNS Notifier";
        }

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            return true;
        }

        @Override
        public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
            awsAccessKey = formData.getString("awsAccessKey");
            awsSecretKey = formData.getString("awsSecretKey");
            defaultTopicArn = formData.getString("defaultTopicArn");

            save();
            return super.configure(req,formData);
        }

        public String getAwsAccessKey() {
            return awsAccessKey;
        }

        public String getAwsSecretKey() {
            return awsSecretKey;
        }

        public String getDefaultTopicArn() {
            return defaultTopicArn;
        }

        public void setAwsAccessKey(String awsAccessKey) {
            this.awsAccessKey = awsAccessKey;
        }

        public void setAwsSecretKey(String awsSecretKey) {
            this.awsSecretKey = awsSecretKey;
        }

        public void setDefaultTopicArn(String defaultTopicArn) {
            this.defaultTopicArn = defaultTopicArn;
        }
    }
}

@@ -2019,32 +2019,317 @@
 %0A            %7D%0A%0A
+            String snsApiEndpoint = getSNSApiEndpoint(publishTopic);%0A            if (isEmpty(snsApiEndpoint)) %7B%0A                listener.error(%0A                        %22Could not determine SNS API Endpoint from topic ARN: %22 + publishTopic);%0A                return true;%0A            %7D%0A%0A
             Stri
@@ -2351,16 +2351,16 @@
 uncate(%0A
-
         
@@ -2863,24 +2863,76 @@
 ecretKey));%0A
+            snsClient.setEndpoint(snsApiEndpoint);%0A%0A
             
@@ -3660,24 +3660,24 @@
 String s) %7B%0A
-
         retu
@@ -3719,24 +3719,706 @@
 = 0;%0A    %7D%0A%0A
+    /**%0A     * Determine the SNS API endpoint to make API calls to, based on the region%0A     * included in the topic ARN. %0A     */%0A    private String getSNSApiEndpoint(String topicArn) %7B%0A%0A        // This is probably not a recommended way to pick the API endpoint, but%0A        // it seems to be a reasonably safe assumption, and avoids extra %0A        // configuration variables.%0A%0A        if (!topicArn.startsWith(%22arn:aws:sns:%22)) %7B%0A            return null;%0A        %7D%0A%0A        String%5B%5D arnParts = topicArn.split(%22:%22);%0A        if (arnParts.length %3C 5) %7B%0A            return null;%0A        %7D%0A%0A        String region = arnParts%5B3%5D;%0A        return %22sns.%22 + region + %22.amazonaws.com%22;%0A    %7D%0A%0A
     @Extensi

determine the sns api endpoint from the topic arn