package com.reyun.util;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import com.google.common.collect.Lists;

import java.io.*;
import java.net.URL;
import java.util.List;

public class AwsS3Util {
    private static AwsS3Util awsS3Util = new AwsS3Util();

    private AmazonS3 s3;

    private AwsS3Util() {
        String accessKey = Constant.accessKey;
        String secretKey = Constant.secretKey;

        if ((accessKey != null) && (secretKey != null)) {
            AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);

            ClientConfiguration config = new ClientConfiguration();
            String proxyHost = System.getProperty("http.proxyHost");
            String proxyPort = System.getProperty("http.proxyPort");
            if (proxyHost != null && proxyPort != null) {
                config.setProxyHost(proxyHost);
                config.setProxyPort(Integer.valueOf(proxyPort));
            }

            if (s3 == null)
                s3 = new AmazonS3Client(credentials, config);

            s3.setRegion(com.amazonaws.regions.Region.getRegion(Regions.fromName(Constant.ddbregion)));
        }
    }

    public static AwsS3Util getInstance() {
        return awsS3Util;
    }

    public List<String> getS3Keys(String bucket, String prefix) {
        List<String> rtnList = Lists.newArrayList();
        ObjectListing objectListing = s3.listObjects(new ListObjectsRequest()
                .withBucketName(bucket)
                .withPrefix(prefix));
        for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
            rtnList.add(objectSummary.getKey());
        }
        return rtnList;
    }

    public long uploadStreamToS3(String bucket, String s3key, InputStream in, String contentType, long contentLength)
            throws IOException {
        ObjectMetadata md = new ObjectMetadata();
        if (contentType != null)
            md.setContentType(contentType);
        md.setContentLength(contentLength);
        s3.putObject(bucket, s3key, in, md);
        return contentLength;
    }

    public long uploadStringToS3(String s3bucket, String s3key, String str)
            throws IOException {
        final byte[] bytes = str.getBytes("UTF-8");
        BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(bytes));
        try {
            return uploadStreamToS3(s3bucket, s3key, bis, "text/plain; charset=UTF-8", bytes.length);
        } finally {
            IOUtil.close(bis);
        }
    }

    public byte[] downloadBytesFromS3(String bucket, String s3key) throws IOException {
        InputStream is = null;
        ByteArrayOutputStream bos = null;
        try {
            is = downloadStreamFromS3(bucket, s3key);
            bos = new ByteArrayOutputStream();
            IOUtil.copy(is, bos);
            return bos.toByteArray();
        } finally {
            if (bos != null)
                IOUtil.close(bos);
            if (is != null)
                IOUtil.close(is);
        }
    }

    public InputStream downloadStreamFromS3(String bucket, String s3key) {
        return s3.getObject(bucket, s3key).getObjectContent();
    }

    public void deleteS3Object(String bucket, String s3key) {
        s3.deleteObject(bucket, s3key);
    }

    public long length(String bucket, String s3key) {
        //FIXME: it seems we do not need to fire an extra getObject request?
        long len = 0;
        final S3Object s3Object = s3.getObject(bucket, s3key);
        try {
            if (s3Object != null) {
                len = s3Object.getObjectMetadata().getContentLength();
            }
        }
        finally {
            try {
                if (s3Object != null) {
                    s3Object.close();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
        return len;
    }

    public boolean doesObjectExist(String bucketName, String objectName) {
        return s3.doesObjectExist(bucketName, objectName);
    }

    public URL generatePresignedUrl(String bucketName, String objectName, long expireMsFromCurrent) {
        java.util.Date expiration = new java.util.Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += expireMsFromCurrent;
        expiration.setTime(expTimeMillis);
        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName,
                objectName).withMethod(HttpMethod.GET).withExpiration(expiration);
        return s3.generatePresignedUrl(generatePresignedUrlRequest);
    }
}