package uk.co.flamingpenguin.jewel.cli;

import static uk.co.flamingpenguin.jewel.cli.ConvertTypeOfObject.converterTo;

import java.util.LinkedHashMap;
import java.util.Map;

class ArgumentPresenterImpl<O> implements ArgumentPresenter<O> {
    private final OptionsSpecification<O> specification;
    private final ArgumentPresentingStrategy<O> argumentPresentingStrategy;

    public ArgumentPresenterImpl(
            final OptionsSpecification<O> specification,
            final ArgumentPresentingStrategy<O> argumentPresentingStrategy) {
        this.specification = specification;
        this.argumentPresentingStrategy = argumentPresentingStrategy;
    }

    @Option public O presentArguments(final ArgumentCollection validatedArguments) throws ArgumentValidationException {
        final Map<String, Object> argumentMap = new LinkedHashMap<String, Object>();

        final ValidationErrorBuilder validationErrorBuilder = new ValidationErrorBuilderImpl();

        for (final ParsedOptionSpecification optionSpecification : specification) {
            final ConvertTypeOfObject<?> convertTypeOfObject =
                    converterTo(validationErrorBuilder, optionSpecification, optionSpecification.getMethod());
            putDefaultInMap(argumentMap, optionSpecification, convertTypeOfObject);

            final Argument argument = validatedArguments.getArgument(optionSpecification.getNames());
            if (argument != null) {
                if (optionSpecification.isMultiValued()) {
                    argumentMap.put(
                            optionSpecification.getCanonicalIdentifier(),
                            convertTypeOfObject.convert(argument.getValues()));
                } else if (!argument.getValues().isEmpty()) {
                    argumentMap.put(
                            optionSpecification.getCanonicalIdentifier(),
                            convertTypeOfObject.convert(argument.getValues().get(0)));
                } else if (argument.getValues().isEmpty()) {
                    argumentMap.put(optionSpecification.getCanonicalIdentifier(), null);
                }
            }
        }

        if (specification.hasUnparsedSpecification()) {
            final UnparsedOptionSpecification unparsedSpecification = specification.getUnparsedSpecification();

            final ConvertTypeOfObject<?> convertTypeOfObject =
                    converterTo(
                            validationErrorBuilder,
                            unparsedSpecification,
                            unparsedSpecification.getMethod());

            putDefaultInMap(argumentMap, unparsedSpecification, convertTypeOfObject);

            if (!validatedArguments.getUnparsed().isEmpty())
            {
                if (unparsedSpecification.isMultiValued())
                {
                    argumentMap.put(
                            unparsedSpecification.getCanonicalIdentifier(),
                            convertTypeOfObject.convert(validatedArguments.getUnparsed()));
                }
                else if (!validatedArguments.getUnparsed().isEmpty())
                {
                    argumentMap.put(
                            unparsedSpecification.getCanonicalIdentifier(),
                            convertTypeOfObject.convert(validatedArguments.getUnparsed().get(0)));
                }
            }
        }
        validationErrorBuilder.validate();
        return argumentPresentingStrategy.presentArguments(argumentMap);
    }

    private void putDefaultInMap(
            final Map<String, Object> argumentMap,
            final OptionSpecification optionSpecification,
            final ConvertTypeOfObject<?> convertTypeOfObject) {
        if (optionSpecification.isMultiValued() && optionSpecification.hasDefaultValue())
        {
            argumentMap.put(
                    optionSpecification.getCanonicalIdentifier(),
                    convertTypeOfObject.convert(optionSpecification.getDefaultValue()));
        }
        else if (optionSpecification.hasDefaultValue() && optionSpecification.getDefaultValue().size() > 0)
        {
            argumentMap.put(
                    optionSpecification.getCanonicalIdentifier(),
                    convertTypeOfObject.convert(optionSpecification.getDefaultValue().get(0)));
        }
    }
}

@@ -150,16 +150,40 @@
 shMap;%0D%0A
+import java.util.List;%0D%0A
 import j
@@ -1515,679 +1515,100 @@
     
-if (optionSpecification.isMultiValued()) %7B%0D%0A                    argumentMap.put(%0D%0A                            optionSpecification.getCanonicalIdentifier(),%0D%0A                            convertTypeOfObject.convert(argument.getValues()));%0D%0A                %7D else if (!argument.getValues().isEmpty()) %7B%0D%0A                    argumentMap.put(%0D%0A                            optionSpecification.getCanonicalIdentifier(),%0D%0A                            convertTypeOfObject.convert(argument.getValues().get(0)));%0D%0A                %7D else if (argument.getValues().isEmpty()) %7B%0D%0A                    argumentMap.put(optionSpecification.getCanonicalIdentifier(), null);%0D%0A                %7D
+putValuesInMap(argumentMap, optionSpecification, convertTypeOfObject, argument.getValues());
 %0D%0A  
@@ -2154,34 +2154,32 @@
 TypeOfObject);%0D%0A
-%0D%0A
             if (
@@ -2222,29 +2222,16 @@
 Empty())
-%0D%0A           
  %7B%0D%0A    
@@ -2246,71 +2246,29 @@
     
-if (unparsedSpecification.isMultiValued())
+putValuesInMap(
 %0D%0A    
-            %7B%0D%0A
     
@@ -2290,35 +2290,27 @@
  argumentMap
-.put(%0D%0A    
+,%0D%0A
             
@@ -2346,40 +2346,11 @@
 tion
-.getCanonicalIdentifier(),%0D%0A    
+,%0D%0A
     
@@ -2384,33 +2384,51 @@
 TypeOfObject
-.convert(
+,%0D%0A                        
 validatedArg
@@ -2448,17 +2448,16 @@
 arsed())
-)
 ;%0D%0A     
@@ -2451,32 +2451,39 @@
 ed());%0D%0A        
+    %7D%0D%0A
         %7D%0D%0A     
@@ -2489,98 +2489,427 @@
     
-        else if (!validatedArguments.getUnparsed().isEmpty())%0D%0A                %7B%0D%0A        
+validationErrorBuilder.validate();%0D%0A        return argumentPresentingStrategy.presentArguments(argumentMap);%0D%0A    %7D%0D%0A%0D%0A    private void putValuesInMap(%0D%0A            final Map%3CString, Object%3E argumentMap,%0D%0A            final OptionSpecification specification,%0D%0A            final ConvertTypeOfObject%3C?%3E convertTypeOfObject,%0D%0A            final List%3CString%3E values) %7B%0D%0A        if (specification.isMultiValued())%0D%0A        %7B%0D%0A
     
@@ -2954,33 +2954,17 @@
         
-        unparsedS
+s
 pecifica
@@ -3011,32 +3011,24 @@
             
-        
 convertTypeO
@@ -3050,44 +3050,11 @@
 (val
-idatedArguments.getUnparsed().get(0)
+ues
 ));%0D
@@ -3058,32 +3058,35 @@
 );%0D%0A        
+%7D%0D%0A
         
 %7D%0D%0A         
@@ -3077,24 +3077,76 @@
     
-%7D%0D%0A            %7D
+else if (!values.isEmpty())%0D%0A        %7B%0D%0A            argumentMap.put(
 %0D%0A  
@@ -3147,35 +3147,36 @@
 t(%0D%0A        
-%7D%0D%0A
+    
         
 validationEr
@@ -3167,42 +3167,47 @@
     
-validationErrorBuilder.validate();
+specification.getCanonicalIdentifier(),
 %0D%0A  
@@ -3216,72 +3216,191 @@
     
-return argumentPresentingStrategy.presentArguments(argumentMap);
+            convertTypeOfObject.convert(values.get(0)));%0D%0A        %7D else if (values.isEmpty()) %7B%0D%0A            argumentMap.put(specification.getCanonicalIdentifier(), null);%0D%0A        %7D
 %0D%0A  

refactor different option types