package org.kohsuke.args4j.spi;

import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.IllegalAnnotationError;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Field;

/**
 * {@link Setter} that allows multiple values to be stored into one array field.
 *
 * <p>
 * Because of the {@link CmdLineParser} abstractions of allowing incremental parsing of options,
 * this implementation creates a whole new array each time a new value is found.
 *
 * This is also why we don't support a setter method that takes list/array as arguments.
 *
 * @author Kohsuke Kawaguchi
 */
final class ArrayFieldSetter implements Setter {
    private final Object bean;
    private final Field f;

    public ArrayFieldSetter(Object bean, Field f) {
        this.bean = bean;
        this.f = f;

        if(!f.getType().isArray())
            throw new IllegalAnnotationError(Messages.ILLEGAL_FIELD_SIGNATURE.format(f.getType()));
    }

    public FieldSetter asFieldSetter() {
        return new FieldSetter(bean,f);
    }

    public AnnotatedElement asAnnotatedElement() {
        return f;
    }

    public boolean isMultiValued() {
    	return true;
    }

    public Class getType() {
        return f.getType().getComponentType();
    }

    public void addValue(Object value) {
        try {
            doAddValue(bean, value);
        } catch (IllegalAccessException _) {
            // try again
            f.setAccessible(true);
            try {
                doAddValue(bean,value);
            } catch (IllegalAccessException e) {
                throw new IllegalAccessError(e.getMessage());
            }
        }
    }

    private void doAddValue(Object bean, Object value) throws IllegalAccessException {
        Object ary = f.get(bean);
        if (ary == null) {
                ary = Array.newInstance(getType(), 1);
                Array.set(ary, 0, value);
        } else {
            int len = Array.getLength(ary);
            Object newAry = Array.newInstance(ary.getClass().getComponentType(), len +1);
                System.arraycopy(ary, 0, newAry, 0, len);
                Array.set(newAry, len, value);
            ary = newAry;
        }

        f.set(bean, ary);
    }
}


@@ -224,16 +224,81 @@
 t.Field;
+%0Aimport java.util.logging.Level;%0Aimport java.util.logging.Logger;
 %0A%0A/**%0A *
@@ -798,16 +798,54 @@
 Field f;
+%0A    %0A    private Object defaultArray;
 %0A%0A    pu
@@ -1068,24 +1068,718 @@
 etType()));%0A
+        %0A        trySetDefault(bean);%0A    %7D%0A%0A    /** Remember default so we throw away the default when adding user values.%0A     */%0A    private void trySetDefault(Object bean1) throws IllegalAccessError %7B%0A        try %7B%0A            doSetDefault(bean1);%0A        %7D catch (IllegalAccessException ex) %7B%0A            try %7B%0A                // try again%0A                f.setAccessible(true);%0A                doSetDefault(bean1);%0A            %7Dcatch (IllegalAccessException ex1) %7B%0A                throw new IllegalAccessError(ex1.getMessage());%0A            %7D%0A        %7D%0A    %7D%0A    %0A    private void doSetDefault(Object bean) throws IllegalAccessException %7B%0A        this.defaultArray = f.get(bean);        %0A
     %7D%0A%0A    p
@@ -2596,24 +2596,24 @@
 .get(bean);%0A
-
         if (
@@ -2623,16 +2623,39 @@
  == null
+ %7C%7C ary == defaultArray
 ) %7B%0A    

Fix for ArrayFieldSetter that starts initialization of string arrays at length zero. Hm ... will this bring us compatibility problems to the former implementation?