1 /*
2 Very basic table<nested table> implementation.
3 
4 Categories and atoms are held seperately to stop me making mistakes
5 
6 Operates in terms of D strings 
7 */
8 module util.statman;
9 import std.json;
10 import std.exception : enforce;
11 
12 public
13 {
14     struct StatManager
15     {
16         HasCategory buf;
17 
18         this(string nameset)
19         {
20             buf = new HasCategory;
21             buf.setAtom("from", nameset);
22         }
23 
24         alias buf this;
25         StatManager* gcDup()
26         {
27             auto y = new StatManager;
28             y.buf = this.buf;
29             return y;
30         }
31     }
32 }
33 // Hidden implementation detailed
34 private:
35 
36 ///The base of all stats
37 interface HasJSON
38 {
39     JSONValue getJSON() const pure;
40     string prettyString(uint depth = 0);
41 }
42 
43 class Atom(T) : HasJSON
44 {
45     private T x;
46     this(T xx)
47     {
48         import std.traits : hasIndirections;
49 
50         static if (hasIndirections!T)
51         {
52             x = xx.idup;
53         }
54         else
55         {
56             x = xx;
57         }
58     }
59 
60     JSONValue getJSON() const pure
61     {
62         return JSONValue(x);
63     }
64 
65     string prettyString(uint depth = 0)
66     {
67         import std.conv;
68 
69         return to!string(x);
70     }
71 }
72 class Array : HasJSON {
73     string name;
74     this(string _name)
75     {
76         name = _name;
77     }
78     private HasCategory[] content;
79     HasCategory index(ulong i)
80     {
81         return content[i];
82     }
83     HasCategory bump()
84     {
85         auto y = new HasCategory;
86         content ~= y;
87         return y;
88     }
89     void debg() const
90     {
91         import std.stdio;
92         writeln("Stored: ", content.length);
93     }
94     JSONValue getJSON() const pure
95     {
96         
97         JSONValue g;
98         g.array = [];
99         foreach(i, v; content)
100         {
101             g.array ~= v.getJSON;
102         }
103         return g;
104     }
105     string prettyString(uint depth = 0)
106     {
107         import std.array : replicate;
108         import std.format;
109         alias tabrep = x => "\t".replicate(x);
110         const tabs = tabrep(depth);
111         string tmp = tabs;
112         foreach(i, j; content)
113         {
114             tmp ~= format!"Index: %d\n%s%s"(i, tabs, j.prettyString(depth + 1));
115         }
116         return tmp;
117     }
118 }
119 public class HasCategory : HasJSON
120 {
121     HasJSON[string] atomMap;
122 
123     void setAtom(T)(string name, T x)
124     {
125         atomMap[name] = new Atom!T(x);
126     }
127     Array initArray(string name)
128     {
129         if(name !in atomMap) {
130             auto y = new Array(name);
131             atomMap[name] = y;
132             return y;
133         } else {
134             return cast(Array) atomMap[name];
135         }
136         
137         
138     }
139     HasCategory[string] categoryMap;
140     HasCategory category(string name)
141     {
142         enforce(name !in atomMap, "Name collision: category is also an atom");
143         if (name in categoryMap)
144         {
145             return categoryMap[name];
146         }
147         else
148         {
149             categoryMap[name] = new HasCategory;
150             return categoryMap[name];
151         }
152     }
153     //Attempts to be slightly clever: Get the identifier from a symbol and use that to assign an atom
154     void setAtom(alias var)()
155     {
156         setAtom(__traits(identifier, var), var);
157     }
158 
159     JSONValue getJSON() const pure
160     {
161         JSONValue buf;
162         foreach (key, value; atomMap)
163         {
164             buf[key] = value.getJSON;
165         }
166         foreach (key, value; categoryMap)
167         {
168             buf[key] = value.getJSON;
169         }
170         return buf;
171     }
172 
173     private string[2][] getAtoms()
174     {
175         string[2][] tmp;
176         foreach (key, value; atomMap)
177         {
178             tmp ~= [key, value.prettyString];
179         }
180         return tmp;
181     }
182 
183     string prettyString(uint depth = 0)
184     {
185         //ugly
186         import std.stdio;
187         alias tabrep = x => "\t".replicate(x);
188 
189         import util.colour;
190         import std.format;
191         import std.algorithm;
192         import std.array : replicate;
193 
194         const tabs = "\t".replicate(depth);
195         string tmp;
196         
197             
198         
199         foreach (key, value; atomMap)
200         {
201 
202             tmp ~= format!"%s%s: %s\n"(tabs, colourString(key, ForegroundColour.Yellow),
203                         colourString(value.prettyString(0), ForegroundColour.Red));
204         }
205         
206         
207         foreach (key, value; categoryMap)
208         {
209             const colouredKey = key.colourString(ForegroundColour.Green);
210             tmp ~= format!"%s%s\n%s\n"(tabs, colouredKey, value.prettyString(depth + 1));
211             
212         }
213 
214         return tmp;
215     }
216 }