package org.csanchez.aws.glacier;

import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.csanchez.aws.glacier.domain.Action;
import org.csanchez.aws.glacier.domain.Archive;
import org.csanchez.aws.glacier.domain.Vault;
import org.csanchez.aws.glacier.utils.Check;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;

public class Main {

    private static final Log LOG = LogFactory.getLog( Main.class );
    private static final Options COMMON_OPTIONS = commonOptions();

    public static void main( String[] args ) throws Exception {

        File props = new File( System.getProperty( "user.home" ) + "/AwsCredentials.properties" );
        if ( !props.exists() ) {
            LOG.error( "Missing " + props.getAbsolutePath() );
            return;
        }

        AWSCredentials credentials = new PropertiesCredentials( props );

        if ( args.length < 1 ) {
            printHelp( COMMON_OPTIONS );
            return;
        }

        CommandLine cmd = new PosixParser().parse( COMMON_OPTIONS, args );
        List<String> arguments = Arrays.asList( cmd.getArgs() );

        String region = cmd.getOptionValue( "region", "us-east-1" );
        Action action = Check.notNull( Action.fromName( arguments.get( 0 ) ), "No action provided" );

        Glacier glacier = new Glacier( credentials, region );

        try {
            switch ( action ) {
                case VAULTS:
                    Validate.isTrue( arguments.size() == 1 );

                    Collection<Vault> vaults = glacier.vaults().get();
                    for ( Vault vault : vaults ) {
                        System.out.println( vault );
                    }

                    if ( vaults.isEmpty() ) {
                        LOG.info( "There are no vaults in \"" + region + "\" region" );
                    }

                    return;

                case INVENTORY:
                    Validate.isTrue( arguments.size() == 2 );

                    Collection<Archive> inventory = glacier.inventory( arguments.get( 1 ) ).get();
                    for ( Archive archive : inventory ) {
                        System.out.println( archive );
                    }
                    
                    if ( inventory.isEmpty() ) {
                        LOG.info( "There are no archives in vault \"" + arguments.get( 1 ) + "\"" );
                    }
                    
                    return;

                case UPLOAD:
                    Validate.isTrue( arguments.size() >= 3 );

                    // TODO: output filename and archiveId to sysout
                    List<String> uploads = arguments.subList( 2, arguments.size() );

                    LOG.info( uploads.size() + " archive(s) requested for upload." );

                    for ( String archive : uploads ) {
                        glacier.upload( arguments.get( 1 ), archive );
                    }
                    return;

                case DELETE:
                    Validate.isTrue( arguments.size() >= 3 );

                    List<String> deletes = arguments.subList( 2, arguments.size() );

                    LOG.info( deletes.size() + " archive(s) requested for deletion." );

                    for ( String archive : deletes ) {
                        glacier.delete( arguments.get( 1 ), archive );
                    }
                    return;

                case DOWNLOAD:
                    Validate.isTrue( arguments.size() == 4 );

                    File archive = glacier.download( arguments.get( 1 ), arguments.get( 2 ) ).get();
                    archive.renameTo( new File( arguments.get( 3 ) ) );
                    return;
            }
        } catch ( IllegalArgumentException ignore ) {
            // Fall-through for validation
        } finally {
            IOUtils.closeQuietly( glacier );
        }

        printHelp( COMMON_OPTIONS );
    }

    private static void printHelp( Options options ) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp( "glacier " + "upload vault_name file1 file2 ... | " + "download vault_name archiveId output_file | " + "delete vault_name archiveId | " + "inventory vault_name | ", options );
    }

    @SuppressWarnings( "static-access" )
    private static Options commonOptions() {
        Options options = new Options();
        Option region = OptionBuilder.withArgName( "region" ).hasArg().withDescription( "Specify URL as the web service URL to use. Defaults to 'us-east-1'" ).create( "region" );
        options.addOption( region );

        Option topic = OptionBuilder.withArgName( "topic_name" ).hasArg().withDescription( "SNS topic to use for inventory retrieval. Defaults to 'glacier'" ).create( "topic" );
        options.addOption( topic );

        Option queue = OptionBuilder.withArgName( "queue_name" ).hasArg().withDescription( "SQS queue to use for inventory retrieval. Defaults to 'glacier'" ).create( "queue" );
        options.addOption( queue );

        Option output = OptionBuilder.withArgName( "file_name" ).hasArg().withDescription( "File to save the inventory to. Defaults to 'glacier.json'" ).create( "output" );
        options.addOption( output );

        return options;
    }
}

@@ -125,16 +125,52 @@
 il.List;
+%0Aimport java.util.concurrent.Future;
 %0A%0Aimport
@@ -631,102 +631,8 @@
 on;%0A
-import org.csanchez.aws.glacier.domain.Archive;%0Aimport org.csanchez.aws.glacier.domain.Vault;%0A
 impo
@@ -1901,25 +1901,24 @@
 e() == 1 );%0A
-%0A
             
@@ -1929,265 +1929,33 @@
     
-Collection%3CVault%3E vaults = glacier.vaults().get();%0A                    for ( Vault vault : vaults ) %7B%0A                        System.out.println( vault );%0A                    %7D%0A%0A                    if ( vaults.isEmpty() ) %7B%0A                        LOG.info(
+output( glacier.vaults(),
  %22Th
@@ -2009,31 +2009,8 @@
  );%0A
-                    %7D%0A%0A
     
@@ -2124,25 +2124,24 @@
 e() == 2 );%0A
-%0A
             
@@ -2152,39 +2152,15 @@
     
-Collection%3CArchive%3E inventory =
+output(
  gla
@@ -2199,254 +2199,9 @@
  ) )
-.get();%0A                    for ( Archive archive : inventory ) %7B%0A                        System.out.println( archive );%0A                    %7D%0A                    %0A                    if ( inventory.isEmpty() ) %7B%0A                        LOG.info(
+,
  %22Th
@@ -2268,51 +2268,8 @@
  );%0A
-                    %7D%0A                    %0A
     
@@ -5110,11 +5110,377 @@
 s;%0A    %7D
+%0A%0A    private static %3CT%3E void output( Future%3CCollection%3CT%3E%3E future, String empty ) throws Exception %7B%0A        Collection%3CT%3E collection = future.get();%0A        if ( collection == null %7C%7C collection.isEmpty() ) %7B%0A            LOG.info( empty );%0A            return;%0A        %7D%0A%0A        for ( T item : collection ) %7B%0A            System.out.println( item );%0A        %7D%0A    %7D
 %0A%7D%0A

Extract some common code to a method