package joptsimple;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import joptsimple.internal.Objects;

public class OptionSet {
   private final List<OptionSpec<?>> detectedSpecs = new ArrayList();
   private final Map<String, AbstractOptionSpec<?>> detectedOptions = new HashMap();
   private final Map<AbstractOptionSpec<?>, List<String>> optionsToArguments = new IdentityHashMap();
   private final Map<String, List<?>> defaultValues;

   OptionSet(Map<String, List<?>> defaults) {
      this.defaultValues = new HashMap(defaults);
   }

   public boolean hasOptions() {
      return !this.detectedOptions.isEmpty();
   }

   public boolean has(String option) {
      return this.detectedOptions.containsKey(option);
   }

   public boolean has(OptionSpec<?> option) {
      return this.optionsToArguments.containsKey(option);
   }

   public boolean hasArgument(String option) {
      AbstractOptionSpec<?> spec = (AbstractOptionSpec)this.detectedOptions.get(option);
      return spec != null && this.hasArgument((OptionSpec)spec);
   }

   public boolean hasArgument(OptionSpec<?> option) {
      Objects.ensureNotNull(option);
      List<String> values = (List)this.optionsToArguments.get(option);
      return values != null && !values.isEmpty();
   }

   public Object valueOf(String option) {
      Objects.ensureNotNull(option);
      AbstractOptionSpec<?> spec = (AbstractOptionSpec)this.detectedOptions.get(option);
      if (spec == null) {
         List<?> defaults = this.defaultValuesFor(option);
         return defaults.isEmpty() ? null : defaults.get(0);
      } else {
         return this.valueOf((OptionSpec)spec);
      }
   }

   public <V> V valueOf(OptionSpec<V> option) {
      Objects.ensureNotNull(option);
      List<V> values = this.valuesOf(option);
      switch(values.size()) {
      case 0:
         return null;
      case 1:
         return values.get(0);
      default:
         throw new MultipleArgumentsForOptionException(option.options());
      }
   }

   public List<?> valuesOf(String option) {
      Objects.ensureNotNull(option);
      AbstractOptionSpec<?> spec = (AbstractOptionSpec)this.detectedOptions.get(option);
      return spec == null ? this.defaultValuesFor(option) : this.valuesOf((OptionSpec)spec);
   }

   public <V> List<V> valuesOf(OptionSpec<V> option) {
      Objects.ensureNotNull(option);
      List<String> values = (List)this.optionsToArguments.get(option);
      if (values != null && !values.isEmpty()) {
         AbstractOptionSpec<V> spec = (AbstractOptionSpec)option;
         List<V> convertedValues = new ArrayList();
         Iterator i$ = values.iterator();

         while(i$.hasNext()) {
            String each = (String)i$.next();
            convertedValues.add(spec.convert(each));
         }

         return Collections.unmodifiableList(convertedValues);
      } else {
         return this.defaultValueFor(option);
      }
   }

   public List<OptionSpec<?>> specs() {
      List<OptionSpec<?>> specs = this.detectedSpecs;
      specs.remove(this.detectedOptions.get("[arguments]"));
      return Collections.unmodifiableList(specs);
   }

   public List<?> nonOptionArguments() {
      return Collections.unmodifiableList(this.valuesOf((OptionSpec)this.detectedOptions.get("[arguments]")));
   }

   void add(AbstractOptionSpec<?> spec) {
      this.addWithArgument(spec, (String)null);
   }

   void addWithArgument(AbstractOptionSpec<?> spec, String argument) {
      this.detectedSpecs.add(spec);
      Iterator i$ = spec.options().iterator();

      while(i$.hasNext()) {
         String each = (String)i$.next();
         this.detectedOptions.put(each, spec);
      }

      List<String> optionArguments = (List)this.optionsToArguments.get(spec);
      if (optionArguments == null) {
         optionArguments = new ArrayList();
         this.optionsToArguments.put(spec, optionArguments);
      }

      if (argument != null) {
         ((List)optionArguments).add(argument);
      }

   }

   public boolean equals(Object that) {
      if (this == that) {
         return true;
      } else if (that != null && this.getClass().equals(that.getClass())) {
         OptionSet other = (OptionSet)that;
         Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap(this.optionsToArguments);
         Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments = new HashMap(other.optionsToArguments);
         return this.detectedOptions.equals(other.detectedOptions) && thisOptionsToArguments.equals(otherOptionsToArguments);
      } else {
         return false;
      }
   }

   public int hashCode() {
      Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap(this.optionsToArguments);
      return this.detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode();
   }

   private <V> List<V> defaultValuesFor(String option) {
      return this.defaultValues.containsKey(option) ? (List)this.defaultValues.get(option) : Collections.emptyList();
   }

   private <V> List<V> defaultValueFor(OptionSpec<V> option) {
      return this.defaultValuesFor((String)option.options().iterator().next());
   }
}
