1 #Region "Microsoft.VisualBasic::54118c312bdd77113acd60282993177c, Microsoft.VisualBasic.Core\ComponentModel\Settings\Inf\IOProvider.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module IOProvider
35     
36     '         Function: __getPath, __getSections, EmptySection, (+2 Overloads) LoadProfile, (+2 Overloads) WriteProfile
37     
38     
39     ' /********************************************************************************/
40
41 #End Region
42
43 Imports System.Reflection
44 Imports System.Runtime.CompilerServices
45 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
46 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel.SchemaMaps
47 Imports Microsoft.VisualBasic.Language
48
49 Namespace ComponentModel.Settings.Inf
50
51     ''' <summary>
52     ''' 在这个模块之中提供了.NET对象与``*.ini``配置文件之间的相互映射的序列化操作
53     ''' </summary>
54     Public Module IOProvider
55
56         <MethodImpl(MethodImplOptions.AggressiveInlining)>
57         <Extension>
58         Private Function EmptySection(x As Type, section As PropertyInfo) As String
59             Return $"Property [{x.Name}\({section.PropertyType.Name}){section.Name}] for ini section is null."
60         End Function
61
62         ''' <summary>
63         ''' 将目标对象写为``*.ini``文件
64         ''' (目标对象之中的所有的简单属性都会被保存在一个对象名称的section中,)
65         ''' </summary>
66         ''' <typeparam name="T"></typeparam>
67         ''' <param name="x"></param>
68         ''' <param name="path"></param>
69         ''' <returns></returns>
70         <Extension>
71         Public Function WriteProfile(Of T As Class)(x As T, path$) As Boolean
72             Dim ini As New IniFile(path)
73             Dim msg$
74
75             ' 首先写入global的配置数据
76             Call ClassMapper.ClassDumper(x:=x, type:=GetType(T), ini:=ini)
77
78             For Each section As PropertyInfo In __getSections(Of T)()
79                 Dim obj As Object = section.GetValue(x, Nothing)
80                 Dim schema As Type = section.PropertyType
81
82                 If obj Is Nothing Then
83                     msg = GetType(T).EmptySection(section)
84                     obj = Activator.CreateInstance(schema)
85
86                     Call msg.Warning
87                     Call App.LogException(msg)
88                 End If
89
90                 Call ClassMapper.ClassDumper(
91                     x:=obj,
92                     type:=schema,
93                     ini:=ini
94                 )
95             Next
96
97             Call $"Ini profile data was saved at location: {path.GetFullPath}".__INFO_ECHO
98
99             Return True
100         End Function
101
102         ''' <summary>
103         ''' 属性的类型需要定义<see cref="ClassName"/>,Section类型里面的属性还需要
104         ''' 定义<see cref="DataFrameColumnAttribute"/>,否则将不会将对应的属性的值
105         ''' 写入到ini文件之中。
106         ''' </summary>
107         ''' <typeparam name="T"></typeparam>
108         ''' <param name="x"></param>
109         ''' <returns></returns>
110         ''' 
111         <MethodImpl(MethodImplOptions.AggressiveInlining)>
112         <Extension>
113         Public Function WriteProfile(Of T As Class)(x As T) As Boolean
114             Return x.WriteProfile(__getPath(Of T))
115         End Function
116
117         ''' <summary>
118         ''' 查找出所有<see cref="ClassName"/>标记的属性
119         ''' </summary>
120         ''' <typeparam name="T"></typeparam>
121         ''' <returns></returns>
122         Private Function __getSections(Of T As Class)() As PropertyInfo()
123             Dim properties As PropertyInfo() = GetType(T).GetProperties(PublicProperty)
124
125             properties = LinqAPI.Exec(Of PropertyInfo) _
126  _
127                 () <= From p As PropertyInfo
128                       In properties
129                       Let type As Type = p.PropertyType
130                       Let attr As ClassName = type.GetAttribute(Of ClassName)
131                       Where Not attr Is Nothing
132                       Select p
133
134             Return properties
135         End Function
136
137         ''' <summary>
138         ''' 从指定的``*.ini``文件之中加载配置数据,如果配置文件不存在,则这个函数会返回空值
139         ''' </summary>
140         ''' <typeparam name="T"></typeparam>
141         ''' <param name="path"></param>
142         ''' <returns></returns>
143         <Extension>
144         Public Function LoadProfile(Of T As Class)(path As StringAs T
145             Dim ini As New IniFile(path)
146
147             If Not ini.FileExists Then
148                 Return Nothing
149             End If
150
151             Dim obj As Object = ClassMapper.ClassWriter(ini, GetType(T))
152             Dim x As Object
153
154             For Each prop As PropertyInfo In __getSections(Of T)()
155                 x = ClassMapper.ClassWriter(ini, prop.PropertyType)
156                 prop.SetValue(obj, x, Nothing)
157             Next
158
159             Return DirectCast(obj, T)
160         End Function
161
162         Private Function __getPath(Of T As Class)() As String
163             Dim path As IniMapIO = GetType(T).GetAttribute(Of IniMapIO)
164
165             If path Is Nothing Then
166                 Throw New Exception("Could not found path mapping! @" & GetType(T).FullName)
167             Else
168                 Return path.Path
169             End If
170         End Function
171
172         Public Function LoadProfile(Of T As Class)(Optional ByRef fileExists As Boolean = FalseOptional ByRef path$ = NothingAs T
173             path = __getPath(Of T)()
174             fileExists = path.FileExists
175
176             If Not fileExists Then
177                 ' 文件不存在,则直接写文件了
178                 Dim obj As T = Activator.CreateInstance(Of T)
179                 Call obj.WriteProfile
180                 Return obj
181             Else
182                 Return path.LoadProfile(Of T)
183             End If
184         End Function
185     End Module
186 End Namespace