1+ using System ;
2+ using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System . Diagnostics ;
5+ using System . Linq ;
6+ using System . Reflection ;
7+ using Novus . Utilities ;
8+ using SimpleCore . Utilities ;
9+ using SmartImage . Engines ;
10+ using SmartImage . Utilities ;
11+
12+ namespace SmartImage . Core
13+ {
14+ /// <summary>
15+ /// Utilities for <see cref="SearchConfig" />, <see cref="ConfigComponentAttribute" />
16+ /// </summary>
17+ internal static class ConfigComponents
18+ {
19+ /*
20+ * Handles config components (properties or fields).
21+ *
22+ * A config component is a setting (i.e. field, parameter, etc) within the config.
23+ *
24+ * mname - Member name
25+ * id - Map name (Id)
26+ */
27+
28+
29+ /// <summary>
30+ /// Update all fields annotated with <see cref="ConfigComponentAttribute" /> using <paramref name="obj" />.
31+ /// </summary>
32+ /// <param name="obj">Object</param>
33+ /// <param name="cfg">Map of values</param>
34+ internal static void UpdateFields ( object obj , IDictionary < string , string > cfg )
35+ {
36+ var tuples = obj . GetType ( ) . GetAnnotated < ConfigComponentAttribute > ( ) ;
37+
38+ foreach ( var ( _, member ) in tuples ) {
39+ string memberName = member . Name ;
40+
41+ string ? valStr = ReadComponentMapValue < object > ( obj , cfg , memberName ) . ToString ( ) ;
42+
43+ var fi = member . GetBackingField ( ) ;
44+
45+ var val = ParseComponentValue ( valStr , fi . FieldType ) ;
46+
47+ fi . SetValue ( obj , val ) ;
48+ }
49+ }
50+
51+ /// <summary>
52+ /// Get all members annotated with <see cref="ConfigComponentAttribute" /> in <paramref name="obj" />.
53+ /// </summary>
54+ internal static ( ConfigComponentAttribute Attribute , MemberInfo Member ) [ ] GetMembers ( object obj )
55+ {
56+ var tuples = obj . GetType ( ) . GetAnnotated < ConfigComponentAttribute > ( ) ;
57+
58+ return tuples . Select ( y => ( y . Attribute , y . Member ) ) . ToArray ( ) ;
59+ }
60+
61+ /// <summary>
62+ /// Get all fields annotated with <see cref="ConfigComponentAttribute" /> in <paramref name="obj" />.
63+ /// </summary>
64+ internal static ( ConfigComponentAttribute Attribute , FieldInfo Field ) [ ] GetFields ( object obj )
65+ {
66+ var tuples = GetMembers ( obj ) ;
67+
68+ return tuples . Select ( y => ( y . Attribute , y . Member . GetBackingField ( ) ) ) . ToArray ( ) ;
69+ }
70+
71+
72+ /// <summary>
73+ /// Get field of name <paramref name="mname" /> annotated with <see cref="ConfigComponentAttribute" /> in
74+ /// <paramref name="obj" />.
75+ /// </summary>
76+ internal static ( ConfigComponentAttribute Attribute , FieldInfo Field ) GetField ( object obj , string mname )
77+ {
78+ var t = obj . GetType ( ) ;
79+ var field = t . GetFieldAuto ( mname ) ;
80+
81+ var attr = field . GetCustomAttribute < ConfigComponentAttribute > ( ) ;
82+
83+ return ( attr , field ) ;
84+ }
85+
86+ /// <summary>
87+ /// Converts all members annotated with <see cref="ConfigComponentAttribute" /> in <paramref name="obj" /> to a
88+ /// <see cref="Dictionary{TKey,TValue}" />.
89+ /// </summary>
90+ internal static IDictionary < string , string > ConvertComponentsToMap ( object obj )
91+ {
92+ var cfgFields = GetFields ( obj ) ;
93+
94+ var keyValuePairs = cfgFields . Select ( f =>
95+ new KeyValuePair < string , string > ( f . Attribute . Id , f . Field . GetValue ( obj ) . ToString ( ) ) ) ;
96+
97+ return new Dictionary < string , string > ( keyValuePairs ) ;
98+ }
99+
100+
101+ internal static void WriteComponentsToFile ( object obj , string dest ) => Collections . WriteDictionary ( ConvertComponentsToMap ( obj ) , dest ) ;
102+
103+
104+ internal static T ReadComponentMapValue < T > ( object obj , IDictionary < string , string > cfg , string mname )
105+ {
106+ var ( attr , field ) = GetField ( obj , mname ) ;
107+
108+ var defaultValue = ( T ) attr . DefaultValue ;
109+ bool setDefaultIfNull = attr . SetDefaultIfNull ;
110+ string name = attr . Id ;
111+
112+
113+ var v = ReadComponentMapValue ( cfg , name , setDefaultIfNull , defaultValue ) ;
114+ Debug . WriteLine ( $ "{ v } -> { name } { field . Name } ") ;
115+ return v ;
116+ }
117+
118+ internal static object ParseComponentValue ( string rawValue , Type t )
119+ {
120+ if ( t . IsEnum ) {
121+ Enum . TryParse ( t , rawValue , out var e ) ;
122+ return e ;
123+ }
124+
125+ if ( t == typeof ( bool ) ) {
126+ Boolean . TryParse ( rawValue , out bool b ) ;
127+ return b ;
128+ }
129+
130+ return rawValue ;
131+ }
132+
133+ internal static T ParseComponentValue < T > ( string rawValue ) =>
134+ ( T ) ParseComponentValue ( rawValue , typeof ( T ) ) ;
135+
136+
137+ private static void AddToComponentMap < T > ( IDictionary < string , string > cfg , string id , T value )
138+ {
139+ string ? valStr = value . ToString ( ) ;
140+
141+ if ( ! cfg . ContainsKey ( id ) ) {
142+ cfg . Add ( id , valStr ) ;
143+ }
144+ else {
145+ cfg [ id ] = valStr ;
146+ }
147+ }
148+
149+ /// <summary>
150+ /// Reset all members annotated with <see cref="ConfigComponentAttribute" /> within <paramref name="obj" /> to their
151+ /// respective <see cref="ConfigComponentAttribute.DefaultValue" />.
152+ /// </summary>
153+ internal static void ResetComponents ( object obj )
154+ {
155+ var tuples = GetFields ( obj ) ;
156+
157+ foreach ( var ( attr , field ) in tuples ) {
158+ var dv = attr . DefaultValue ;
159+ field . SetValue ( obj , dv ) ;
160+
161+ Debug . WriteLine ( $ "Reset { dv } -> { field . Name } ") ;
162+ }
163+ }
164+
165+ /// <summary>
166+ /// Reset config component with member name <paramref name="mname" /> to its
167+ /// <seealso cref="ConfigComponentAttribute.DefaultValue" />.
168+ /// </summary>
169+ internal static void ResetComponent ( object obj , string mname )
170+ {
171+ var ( attr , field ) = GetField ( obj , mname ) ;
172+
173+ var dv = attr . DefaultValue ;
174+
175+ field . SetValue ( obj , dv ) ;
176+ }
177+
178+
179+ internal static T ReadComponentMapValue < T > ( IDictionary < string , string > cfg , string id ,
180+ bool setDefaultIfNull = false , T defaultValue = default )
181+ {
182+
183+ if ( ! cfg . ContainsKey ( id ) ) {
184+ cfg . Add ( id , String . Empty ) ;
185+ }
186+
187+ string rawValue = cfg [ id ] ;
188+
189+ if ( setDefaultIfNull && String . IsNullOrWhiteSpace ( rawValue ) ) {
190+ AddToComponentMap ( cfg , id , defaultValue . ToString ( ) ) ;
191+ rawValue = ReadComponentMapValue < string > ( cfg , id ) ;
192+ }
193+
194+ var parse = ParseComponentValue < T > ( rawValue ) ;
195+ return parse ;
196+ }
197+
198+
199+ internal static void ReadComponentFromArgument ( object obj , IEnumerator < string > argEnumerator )
200+ {
201+ var argName = argEnumerator . Current ;
202+
203+ var x = GetMembers ( obj ) ;
204+
205+ var correspondingComponent = x . FirstOrDefault ( y => y . Attribute . ArgumentName == argName ) ;
206+
207+ if ( correspondingComponent == default ) {
208+ return ;
209+ }
210+
211+ argEnumerator . MoveNext ( ) ;
212+
213+ string argValue2 = argEnumerator . Current ;
214+ var bf = correspondingComponent . Member . GetBackingField ( ) ;
215+
216+ var value = ConfigComponents . ParseComponentValue ( argValue2 , bf . FieldType ) ;
217+
218+ bf . SetValue ( obj , value ) ;
219+ }
220+ }
221+ }
0 commit comments