1 package com.lexicalscope.jewel.cli;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.LinkedHashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.Set;
10
11 import com.lexicalscope.jewel.cli.parser.ParsedArguments;
12 import com.lexicalscope.jewel.cli.validation.ArgumentValidator;
13 import com.lexicalscope.jewel.cli.validation.OptionCollection;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 public class ArgumentCollectionBuilder implements ParsedArguments {
32 private interface IParsingState {
33 IParsingState addValue(String value);
34
35 IParsingState addOption(String option) throws ArgumentValidationException;
36 }
37
38 private class Initial implements IParsingState {
39 @Override public IParsingState addValue(final String value) {
40 return new NoOptions(value);
41 }
42
43 @Override public IParsingState addOption(final String option) {
44 return new OptionOrValue(option);
45 }
46 }
47
48 private class NoOptions implements IParsingState {
49 public NoOptions(final String value) {
50 addUnparsedValue(value);
51 }
52
53 @Override public IParsingState addValue(final String value) {
54 addUnparsedValue(value);
55 return this;
56 }
57
58 @Override public IParsingState addOption(final String option) throws ArgumentValidationException {
59 throw misplacedOption(option);
60 }
61 }
62
63 private class UnparsedState implements IParsingState {
64 public UnparsedState() {
65 valuesForCurrentArgument = null;
66 }
67
68 @Override public IParsingState addValue(final String value) {
69 addUnparsedValue(value);
70 return this;
71 }
72
73 @Override public IParsingState addOption(final String option) throws ArgumentValidationException {
74 throw misplacedOption(option);
75 }
76 }
77
78 private class OptionOrValue implements IParsingState {
79 public OptionOrValue(final String option) {
80 addFirstValueForOption(option);
81 }
82
83 @Override public IParsingState addValue(final String value) {
84 valuesForCurrentArgument.add(value);
85 return this;
86 }
87
88 @Override public IParsingState addOption(final String option) {
89 return new OptionOrValue(option);
90 }
91 }
92
93 private final Map<String, List<String>> arguments = new LinkedHashMap<String, List<String>>();
94 private final List<String> unparsed = new ArrayList<String>();
95
96 private IParsingState state = new Initial();
97 private List<String> valuesForCurrentArgument;
98
99 @Override
100 public void unparsedOptionsFollow() {
101 state = new UnparsedState();
102 }
103
104 @Override
105 public void addValue(final String value)
106 {
107 state = state.addValue(value);
108 }
109
110 @Override
111 public void addOption(final String option)
112 {
113 state = state.addOption(option);
114 }
115
116 @Override public OptionCollection processArguments(final ArgumentValidator argumentProcessor) {
117 final Set<Entry<String, List<String>>> entrySet = arguments.entrySet();
118 final Iterator<Entry<String, List<String>>> iterator = entrySet.iterator();
119 while (iterator.hasNext()) {
120 final Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = iterator.next();
121
122 if(iterator.hasNext()) {
123 argumentProcessor.processOption(entry.getKey(), entry.getValue());
124 } else {
125 argumentProcessor.processLastOption(entry.getKey(), entry.getValue());
126 }
127 }
128 argumentProcessor.processUnparsed(unparsed);
129 return argumentProcessor.finishedProcessing();
130 }
131
132 private ArgumentValidationException misplacedOption(final String option) {
133 return new ArgumentValidationException(new ValidationFailureMisplacedOption(option));
134 }
135
136 private void addUnparsedValue(final String value) {
137 unparsed.add(value);
138 }
139
140 private void addFirstValueForOption(final String option) {
141 if(!arguments.containsKey(option))
142 {
143 valuesForCurrentArgument = new ArrayList<String>();
144 arguments.put(option, valuesForCurrentArgument);
145 }
146 valuesForCurrentArgument = arguments.get(option);
147 }
148 }