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.InputOption;
13 
14 import hunt.console.error.InvalidArgumentException;
15 import hunt.console.error.LogicException;
16 import hunt.console.util.StringUtils;
17 import hunt.text.Common;
18 import std.string;
19 import hunt.Exceptions;
20 import std.conv;
21 
22 class InputOption
23 {
24     enum int VALUE_NONE = 1;
25     enum int VALUE_REQUIRED = 2;
26     enum int VALUE_OPTIONAL = 4;
27     enum int VALUE_IS_ARRAY = 8;
28 
29     private string name;
30     private string shortcut;
31     private int mode;
32     private string description;
33     private string defaultValue;
34 
35     this(string name)
36     {
37         this(name, null, VALUE_NONE, null, null);
38     }
39 
40     this(string name, string shortcut)
41     {
42         this(name, shortcut, VALUE_NONE, null, null);
43     }
44 
45     this(string name, string shortcut, int mode)
46     {
47         this(name, shortcut, mode, null, null);
48     }
49 
50     this(string name, string shortcut, int mode, string description)
51     {
52         this(name, shortcut, mode, description, null);
53     }
54 
55     this(string name, string shortcut, int mode, string description, string defaultValue)
56     {
57         if (name.startsWith("--")) {
58             name = name.substring(2);
59         }
60 
61         if (name.isEmpty()) {
62             throw new InvalidArgumentException("An option name cannot be empty.");
63         }
64 
65         if (shortcut !is null && shortcut.isEmpty()) {
66             shortcut = null;
67         }
68 
69         if (shortcut !is null) {
70             shortcut = StringUtils.ltrim(shortcut, '-');
71             if (shortcut.isEmpty()) {
72                 throw new IllegalArgumentException("An option shortcut cannot be empty.");
73             }
74         }
75 
76         if (mode > 15 || mode < 1) {
77             throw new InvalidArgumentException("Option mode " ~ mode.to!string ~ " is not valid");
78         }
79 
80         this.name = name;
81         this.shortcut = shortcut;
82         this.mode = mode;
83         this.description = description;
84 
85         setDefaultValue(defaultValue);
86     }
87 
88     string getShortcut()
89     {
90         return shortcut;
91     }
92 
93     string getName()
94     {
95         return name;
96     }
97 
98     bool acceptValue()
99     {
100         return isValueRequired() || isValueOptional();
101     }
102 
103     bool isValueRequired()
104     {
105         return (mode & VALUE_REQUIRED) == VALUE_REQUIRED;
106     }
107 
108     bool isValueOptional()
109     {
110         return (mode & VALUE_OPTIONAL) == VALUE_OPTIONAL;
111     }
112 
113     bool isArray()
114     {
115         return (mode & VALUE_IS_ARRAY) == VALUE_IS_ARRAY;
116     }
117 
118     void setDefaultValue(string defaultValue)
119     {
120         if ((mode & VALUE_NONE) == VALUE_NONE && defaultValue !is null) {
121             throw new LogicException("Cannot set a default value when using InputOption.VALUE_NONE mode.");
122         }
123 
124         if (isArray()) {
125             // todo implement
126         }
127 
128         this.defaultValue = acceptValue() ? defaultValue : null;
129     }
130 
131     string getDefaultValue()
132     {
133         return defaultValue;
134     }
135 
136     string getDescription()
137     {
138         return description;
139     }
140 
141     override bool opEquals(Object o)
142     {
143         if (this is o) return true;
144         if (!(cast(InputOption)o !is null)) return false;
145 
146         InputOption that =cast(InputOption) o;
147 
148         if (isArray() != that.isArray()) return false;
149         if (isValueRequired() != that.isValueRequired()) return false;
150         if (isValueOptional() != that.isValueOptional()) return false;
151         if (defaultValue !is null ? !(defaultValue == that.defaultValue) : that.defaultValue !is null) return false;
152         if (name !is null ? !(name == that.name) : that.name !is null) return false;
153         if (shortcut !is null ? !(shortcut == that.shortcut) : that.shortcut !is null) return false;
154 
155         return true;
156     }
157 
158     override size_t toHash() @trusted nothrow
159     {
160         int result = name !is null ? cast(int)(name.hashOf()) : 0;
161         result = 31 * result + (shortcut !is null ? cast(int)(shortcut.hashOf()) : 0);
162         result = 31 * result + mode;
163         result = 31 * result + (description !is null ? cast(int)(description.hashOf()) : 0);
164         result = 31 * result + (defaultValue !is null ? cast(int)(defaultValue.hashOf()) : 0);
165         return result;
166     }
167 }