import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.ho.yaml.Yaml;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.MultiObjectDeleteException;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.Upload;

public class UploadFilesToS3 {

	@SuppressWarnings("deprecation")
	public static void main(String[] args) {
		
		Map<String,Object> conf = new HashMap<String,Object>();
		String bucketName     = "prod-fact_sales";
		String configFilePath = "/mnt/data/ETL/java/accounting/config/config.yml";
		String localPath = "/mnt/data/tmp/processed_dig_sales";
		String key = "staging_fact_sales/";
		Boolean replaceFiles = true;
		
		Options options = new Options();
		options.addOption("bucket",true,"Bucket name on Amazon S3");
		options.addOption("configFilePath",true,"(Optional) Config.yml file for this cli tool (Default: /mnt/data/ETL/java/accounting/config/config.yml)");
		options.addOption("localPath",true,"Local path from which files are being uploaded from.");
		options.addOption("key",true,"remote key on S3");
		options.addOption("replaceFiles",true,"(Optional) Flag indicating whether you want to replace the files. (Default: true)");
		
		if(args.length==0){
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("ant run -Dargs='paramA=xxx paramB=yyy .....'", options);
			System.exit(1);
		}
		
		try {
			CommandLineParser parser = new GnuParser();
			CommandLine cmd = parser.parse( options, args);
			if(cmd.hasOption("configFilePath")){
				configFilePath = cmd.getOptionValue("configFilePath");
			}
			if(cmd.hasOption("localPath")){
				localPath = cmd.getOptionValue("localPath");
			}
			if(cmd.hasOption("key")){
				key = cmd.getOptionValue("key");
			}
			if(cmd.hasOption("replaceFiles")){
				replaceFiles = cmd.getOptionValue("replaceFiles")=="true" ? true : false;
			}
			
			System.out.println(configFilePath);
	    	try {
				conf = (Map)Yaml.load(new File(configFilePath));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
	  	    String accessKey = (String)conf.get("accessKey");
	  	    String accessSecret = (String)conf.get("accessSecret");
	  	    
	  	    if(replaceFiles){
	  	    	deleteAllS3ObjectsInBucket(bucketName, "staging", new BasicAWSCredentials(accessKey,accessSecret));
	  	    }
	
			System.out.println("Uploading a new object to S3 from a file\n");
			File[] files = new File(cmd.getOptionValue("localPath")).listFiles();
			int fileCount = 0;
			for (File file : files) {
			    if (file.isFile()) {
			    	TransferManager tx = new TransferManager(new BasicAWSCredentials(accessKey,accessSecret));
					Upload upload = tx.upload(bucketName, key+file.getName(), file);
					try{
						while (upload.isDone() == false) {
						    System.out.println(upload.getProgress().getPercentTransfered() + "%");
							Thread.sleep(100);
						}
					}catch(InterruptedException e){
						System.out.println(e.getMessage());
					}
					fileCount++;
			    }
			}
			System.out.println(fileCount+" files were uploaded to S3 location: "+bucketName+"/"+key);
			System.exit(1);
			
		} catch (ParseException e2) {
			e2.printStackTrace();
		}
	}
	
	public static void deleteAllS3ObjectsInBucket(String bucketName, String prefix, BasicAWSCredentials awsCredentials){
		AmazonS3 s3 = new AmazonS3Client(awsCredentials);
	  	DeleteObjectsRequest multiObjectDeleteRequest = new DeleteObjectsRequest(bucketName);
        List<KeyVersion> keys = new ArrayList<KeyVersion>();
        ObjectListing objectListing = s3.listObjects(new ListObjectsRequest()
                  .withBucketName(bucketName)
                  .withPrefix(prefix));
        for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
              String k = objectSummary.getKey();
              System.out.println("Deleting objects: "+k);
              keys.add(new KeyVersion(k));
        }
         
        if(keys.size() > 0){
	        multiObjectDeleteRequest.setKeys(keys);
	        try {
	            DeleteObjectsResult delObjRes = s3.deleteObjects(multiObjectDeleteRequest);
	            System.out.format("Successfully deleted all the %s items.\n", delObjRes.getDeletedObjects().size());
	            			
	        } catch (MultiObjectDeleteException e) {
	            // Process exception.
	        }
        }
	}

}
