1 /*
2  * hunt-console eases the creation of beautiful and testable command line interfaces.
3  *
4  * Copyright (C) 2018-2019, HuntLabs
5  *
6  * Website: https://www.huntlabs.net
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module hunt.console.input.AbstractInput;
13 
14 import hunt.console.error.InvalidArgumentException;
15 
16 import hunt.collection.HashMap;
17 import hunt.collection.Map;
18 import hunt.console.input.Input;
19 import hunt.console.input.InputDefinition;
20 import hunt.Exceptions;
21 
22 import std.string;
23 
24 public abstract class AbstractInput : Input
25 {
26     protected InputDefinition definition;
27     protected Map!(string, string) options;
28     protected Map!(string, string) arguments;
29     protected bool interactive = true;
30 
31     public this()
32     {
33         this.definition = new InputDefinition();
34     }
35 
36     public this(InputDefinition definition)
37     {
38         bind(definition);
39         validate();
40     }
41 
42     override public void bind(InputDefinition definition)
43     {
44         this.arguments = new HashMap!(string, string)();
45         this.options = new HashMap!(string, string)();
46         this.definition = definition;
47 
48         parse();
49     }
50 
51     protected abstract void parse();
52 
53     override public void validate()
54     {
55         if (arguments.size() < definition.getArgumentRequiredCount()) {
56             throw new RuntimeException("Not enough arguments");
57         }
58     }
59 
60     override public bool isInteractive()
61     {
62         return interactive;
63     }
64 
65     override public void setInteractive(bool interactive)
66     {
67         this.interactive = interactive;
68     }
69 
70     override public string[] getArguments()
71     {
72         Map!(string, string) argumentValues = definition.getArgumentDefaults();
73 
74         foreach (string k,string v ; arguments) {
75             argumentValues.put(k, v);
76         }
77 
78         return argumentValues.values();
79     }
80 
81     override public string getArgument(string name)
82     {
83         if (!definition.hasArgument(name)) {
84             throw new InvalidArgumentException(format("The '%s' argument does not exist.", name));
85         }
86 
87         if (arguments.containsKey(name)) {
88             return arguments.get(name);
89         }
90 
91         return definition.getArgument(name).getDefaultValue();
92     }
93 
94     override public void setArgument(string name, string value) /* throws InvalidArgumentException */
95     {
96         if (!definition.hasArgument(name)) {
97             throw new InvalidArgumentException(format("The '%s' argument does not exist.", name));
98         }
99 
100         arguments.put(name, value);
101     }
102 
103     override public bool hasArgument(string name)
104     {
105         return definition.hasArgument(name);
106     }
107 
108     override public string[] getOptions()
109     {
110         Map!(string, string) optionValues = definition.getOptionDefaults();
111 
112         foreach (string k ,string v ; options) {
113             optionValues.put(k, v);
114         }
115 
116         return optionValues.values();
117     }
118 
119     override public string getOption(string name)
120     {
121         if (!definition.hasOption(name)) {
122             throw new InvalidArgumentException(format("The '%s' option does not exist.", name));
123         }
124 
125         if (options.containsKey(name)) {
126             return options.get(name);
127         }
128 
129         return definition.getOption(name).getDefaultValue();
130     }
131 
132     override public void setOption(string name, string value) /* throws InvalidArgumentException */
133     {
134         if (!definition.hasOption(name)) {
135             throw new InvalidArgumentException(format("The '%s' option does not exist.", name));
136         }
137 
138         options.put(name, value);
139     }
140 
141     override public bool hasOption(string name)
142     {
143         return definition.hasOption(name);
144     }
145 }