1 module dunitconversion.aliasdictionary;
2 
3 import std.container;
4 import std.json;
5 
6 /**
7  * The AliasDictionary class provides an alias dictionary to allow quick on-the-fly
8  * conversion of unit name aliases such as km/h -> kmph, kmh etc.
9  */
10 class AliasDictionary {
11 
12     /**
13       * Default constructor as it is
14       */  
15     this() {
16         m_names = new RedBlackTree!string;
17     }
18 
19     /**
20      * Gets name by alias
21      * Params: aliasName = alias to get name
22      * Returns: string containing name corresponding to the given alias
23      */
24     string name(string aliasName) const {
25         if (aliasName in m_names)
26             return aliasName;
27         if (aliasName !in m_aliases)
28             throw new Exception("Alias not found");
29         return m_aliases[aliasName];
30     }
31 
32     /**
33      * Gets a list of aliases for a given name
34      * Params: name = name to get aliases
35      * Returns: QList<string> containing aliases for a given name
36      */
37     string[] aliases(string name) const {
38         string [] result;
39         foreach(item; m_aliases.byKeyValue()) {
40             if (item.value == name) {
41                 result ~= item.key;
42             }
43         }
44         return result;
45     }
46 
47     /**
48      * Checks if this dictionary is empty
49      * Returns: true if empty, false otherwise
50      */
51     bool isEmpty() const {
52         return m_aliases is null;
53     }
54 
55     /**
56      * Adds an alias to the dictionary
57      * Params:
58      *      name = name which will be returned if an alias requested
59      *      alias = alias for the given name
60      */
61     void addAlias(string name, string aliasName) {
62         m_aliases[aliasName] = name;
63         m_names.insert(name);
64     }
65 
66     /**
67      * Checks if a dictionary contains name for the given alias
68      * Params: alias =  alias to check existence
69      * Returns: true if a dictionary contains name for the given alias, false otherwise
70      */
71     bool opBinaryRight(string op)(string aliasName) const 
72     if (op == "in") {
73         if (aliasName in m_aliases || aliasName in m_names)
74             return true;
75         return false;
76     }
77 
78     /**
79      * Loads alias rules from JSON
80      * Params: json = containing serialized dictionary
81      */
82     void loadFromJson(JSONValue json) {
83         auto rules = json["aliases"].array;
84         foreach (r; rules)
85         {
86             auto rule = r.object;
87             auto name = rule["name"].str;
88             if (name is null)
89                 continue;
90             auto aliases = rule["aliases"].array;
91             foreach (a; aliases)
92                 addAlias(name, a.str);
93         }
94     }
95 
96     /**
97      * Removes all alias-name from dictionary
98      */
99     void clear() {
100         m_aliases = null;
101         m_names.clear();
102     }
103 
104 protected:
105     string [string] m_aliases;  /// AA containing names associated with each alias
106     RedBlackTree!string m_names;    /// Full list of names
107 }