1 module glued.adhesives.config;
2 
3 import std.algorithm;
4 
5 public import glued.pathtree;
6 import glued.logging;
7 
8 import glued.adhesives.bundles;
9 
10 import optional;
11 import properd;
12 
13 //todo no tests at all
14 
15 struct ConfigEntry {
16     string text;
17     Asset source;
18 }
19 
20 //todo Environment seems more natural
21 //todo would this gain anything from making previous value versions visible or reachable?
22 class Config {
23     //todo CreateLogger -> DefineLogger; CreateLogger(name) = DefineLogger + Logger <name>
24     mixin CreateLogger;
25     Logger log;
26     
27     this(LogSink sink){
28         log = Logger(sink);
29     }
30     
31     private PathTree!ConfigEntry backend = new ConcretePathTree!ConfigEntry();
32     
33     void feed(Asset asset){
34         log.debug_.emit("Feeding config from ", asset);
35         auto aa = parseProperties(asset.content);
36         foreach(k; aa.keys()){
37             backend.put(k, ConfigEntry(aa[k], asset));
38         }
39     }
40     
41     //todo introduce interface ViewClosure(Result), normalize all closures, e.g. ValuesClosure: ViewClosure!string?
42     
43     @property
44     PathTreeView!ConfigEntry view(){
45         return backend;
46     }
47     
48     struct ValuesClosure {
49         private Config config;
50          
51         string get(string path){
52             return find(path).front();
53         }
54         
55         Optional!string find(string path){
56             return config.backend.get(path).map!(x => x.text).toOptional;
57         }
58         
59         Optional!string resolve(string path){
60             return config.backend.resolve(path).map!(x => x.text).toOptional;
61         }
62     }
63     
64     @property
65     ValuesClosure values(){
66         return ValuesClosure();
67     }
68     
69     struct SourcesClosure {
70         private Config config;
71          
72         Asset get(string path){
73             return find(path).front();
74         }
75         
76         Optional!Asset find(string path){
77             return config.backend.get(path).map!(x => x.source).toOptional;
78         }
79         
80         Optional!Asset resolve(string path){
81             return config.backend.resolve(path).map!(x => x.source).toOptional;
82         }
83     }
84     
85     @property
86     SourcesClosure sources(){
87         return SourcesClosure();
88     }
89     
90     struct EntriesClosure {
91         private Config config;
92          
93         ConfigEntry get(string path){
94             return find(path).front();
95         }
96         
97         Optional!ConfigEntry find(string path){
98             return config.backend.get(path);
99         }
100         
101         Optional!ConfigEntry resolve(string path){
102             return config.backend.resolve(path);
103         }
104     }
105     
106     @property
107     EntriesClosure entries(){
108         return EntriesClosure();
109     }
110 }