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.descriptor.ConsoleDescription;
13 
14 import std.string;
15 
16 import hunt.console.Console;
17 import hunt.console.error.InvalidArgumentException;
18 import hunt.console.command.Command;
19 import hunt.console.descriptor.ConsoleDescription;
20 
21 import hunt.collection.ArrayList;
22 import hunt.collection.HashMap;
23 import hunt.collection.List;
24 import hunt.collection.Map;
25 import hunt.Integer;
26 
27 class ConsoleDescription
28 {
29     public static string GLOBAL_NAMESPACE = "_global";
30 
31     private  Console application;
32 
33     private  string namespace;
34 
35     private Map!(string, List!(string)) namespaces;
36 
37     private Map!(string, Command) commands;
38 
39     private Map!(string, Command) aliases;
40 
41     public this(Console application)
42     {
43         this(application, null);
44     }
45 
46     public this(Console application, string namespace)
47     {
48         this.application = application;
49         this.namespace = namespace;
50     }
51 
52     public Map!(string, List!(string)) getNamespaces()
53     {
54         if (namespaces is null) {
55             inspectConsole();
56         }
57 
58         return namespaces;
59     }
60 
61     public Map!(string, Command) getCommands()
62     {
63         if (commands is null) {
64             inspectConsole();
65         }
66 
67         return commands;
68     }
69 
70     public Command getCommand(string name)
71     {
72         if (!commands.containsKey(name) && !aliases.containsKey(name)) {
73             throw new InvalidArgumentException(format("Command %s does not exist.", name));
74         }
75 
76         if (commands.containsKey(name)) {
77             return commands.get(name);
78         }
79 
80         return aliases.get(name);
81     }
82 
83     private void inspectConsole()
84     {
85         commands = new HashMap!(string, Command)();
86         aliases = new HashMap!(string, Command)();
87         namespaces = new HashMap!(string, List!(string))();
88 
89         Map!(string, Command) all;
90         if (namespace is null) {
91             all = application.all();
92         } else {
93             all = application.all(namespace);
94         }
95 
96         foreach (string k ,Map!(string, Command) v ; sortCommands(all)) {
97 
98             string namespace = k;
99             List!(string) names = new ArrayList!(string)();
100 
101             foreach (string subK , Command subV ; v) {
102                 string name = subK;
103                 Command command = subV;
104                 if (command.getName() is null || command.getName().length == 0) {
105                     continue;
106                 }
107 
108                 if (command.getName() == name) {
109                     commands.put(name, command);
110                 } else {
111                     aliases.put(name, command);
112                 }
113 
114                 names.add(name);
115             }
116 
117             namespaces.put(namespace, names);
118         }
119     }
120 
121     private Map!(string, Map!(string, Command)) sortCommands(Map!(string, Command) commands)
122     {
123         Map!(string, Map!(string, Command)) namespacedCommands = new HashMap!(string, Map!(string, Command))();
124 
125         string key;
126         foreach (string k ,Command v ; commands) {
127             key = application.extractNamespace(k, new Integer(1));
128             if (key is null || key.length == 0) {
129                 key = GLOBAL_NAMESPACE;
130             }
131 
132             if (!namespacedCommands.containsKey(key)) {
133                 namespacedCommands.put(key, new HashMap!(string, Command)());
134             }
135             namespacedCommands.get(key).put(k, v);
136         }
137 
138         // todo sort
139 
140         return namespacedCommands;
141     }
142 }