1 #Region "Microsoft.VisualBasic::8b04ddfc7f6c130f5da839ab2fd9786d, Microsoft.VisualBasic.Core\CommandLine\InteropService\CLIBuilder.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 CLIBuildMethod
35     
36     '         FunctionGetCLI, SimpleBuilder
37     '         Delegate Function
38     
39     '             Function: __booleanRule, __pathRule, __stringEnumRule, __stringRule, ClearParameters
40     
41     
42     
43     ' /********************************************************************************/
44
45 #End Region
46
47 Imports System.ComponentModel
48 Imports System.Reflection
49 Imports System.Runtime.CompilerServices
50 Imports System.Text
51 Imports Microsoft.VisualBasic.ApplicationServices
52 Imports Microsoft.VisualBasic.CommandLine.Reflection
53 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel.SchemaMaps
54 Imports Microsoft.VisualBasic.Language
55
56 Namespace CommandLine.InteropService
57
58     Public Module CLIBuildMethod
59
60         ReadOnly _typeInfo As Type = GetType([Optional])
61
62         ''' <summary>
63         ''' Generates the command line string value for the invoked target cli program using this interop services object instance.
64         ''' (生成命令行参数)
65         ''' </summary>
66         ''' <typeparam name="TInteropService">
67         ''' A class type object for interaction with a commandline program.
68         ''' (与命令行程序进行交互的模块对象类型)
69         ''' </typeparam>
70         ''' <param name="app">目标交互对象的实例</param>
71         ''' <returns></returns>
72         ''' <remarks>
73         ''' 依照类型<see cref="CLITypes"/>来生成参数字符串
74         ''' 
75         ''' <see cref="CLITypes.Boolean"/>, True => 参数名;
76         ''' <see cref="CLITypes.Double"/>, <see cref="CLITypes.Integer"/>, <see cref="CLITypes.String"/>, => 参数名 + 参数值,假若字符串为空则不添加;
77         ''' (假若是枚举值类型,可能还需要再枚举值之中添加<see cref="DescriptionAttribute"/>属性)
78         ''' <see cref="CLITypes.File"/>, 假若字符串为空则不添加,有空格自动添加双引号,相对路径会自动转换为全路径。
79         ''' </remarks>
80         <Extension>
81         Public Function GetCLI(Of TInteropService As Class)(app As TInteropService) As String
82             Dim args As BindProperty(Of [Optional])() =
83                 LinqAPI.Exec(Of BindProperty(Of [Optional])) <=
84  _
85                 From [property] As PropertyInfo
86                 In GetType(TInteropService).GetProperties
87                 Let attrs As Object() =
88                     [property].GetCustomAttributes(attributeType:=_typeInfo, inherit:=True)
89                 Where Not attrs.IsNullOrEmpty
90                 Let attr As [Optional] = DirectCast(attrs.First, [Optional])
91                 Select New BindProperty(Of [Optional]) With {
92                     .field = attr,
93                     .member = [property]
94                 }
95             Dim sb As New StringBuilder(1024)
96
97             For Each argum As BindProperty(Of [Optional]) In args
98                 Dim getCLIToken As __getCLIToken = __getMethods(argum.field.Type)
99                 Dim value As Object = argum.GetValue(app)
100                 Dim cliToken As String = getCLIToken(value, argum.field, DirectCast(argum.member, PropertyInfo))
101
102                 If Not String.IsNullOrEmpty(cliToken) Then
103                     Call sb.Append(cliToken & " ")
104                 End If
105             Next
106
107             Return sb.ToString.TrimEnd
108         End Function
109
110         ''' <summary>
111         ''' Creates a command line string by using simply fills the name and parameter values
112         ''' </summary>
113         ''' <param name="name"></param>
114         ''' <param name="args"></param>
115         ''' <returns></returns>
116         Public Function SimpleBuilder(name$, args As IEnumerable(Of KeyValuePair(Of StringString))) As String
117             Dim sbr As New StringBuilder(name)
118
119             For Each x In args
120                 If String.IsNullOrEmpty(x.Value) Then
121                     Continue For
122                 End If
123
124                 Call sbr.Append(" ")
125                 Call sbr.Append(x.Key & " ")
126                 Call sbr.Append(x.Value.CLIToken)
127             Next
128
129             Return sbr.ToString
130         End Function
131
132 #Region ""
133
134         ''' <summary>
135         ''' Converts the property value to a CLI token
136         ''' </summary>
137         Private ReadOnly __getMethods As IReadOnlyDictionary(Of CLITypes, __getCLIToken) =
138             New Dictionary(Of CLITypes, __getCLIToken) From {
139  _
140             {CLITypes.Boolean, AddressOf CLIBuildMethod.__booleanRule},
141             {CLITypes.Double, AddressOf CLIBuildMethod.__stringRule},
142             {CLITypes.File, AddressOf CLIBuildMethod.__pathRule},
143             {CLITypes.Integer, AddressOf CLIBuildMethod.__stringRule},
144             {CLITypes.String, AddressOf CLIBuildMethod.__stringRule}
145         }
146
147         Private Delegate Function __getCLIToken(value As Object, attr As [Optional], prop As PropertyInfo) As String
148
149         ''' <summary>
150         ''' The different between the String and Path is that applying <see cref="CLIToken"/> or <see cref="CLIPath"/>.
151         ''' </summary>
152         ''' <param name="value">只能是<see cref="System.String"/>类型的</param>
153         ''' <param name="attr"></param>
154         ''' <param name="prop"></param>
155         ''' <returns></returns>
156         Private Function __pathRule(value As Object, attr As [Optional], prop As PropertyInfo) As String
157             Dim path As String = DirectCast(value, String)
158             If Not String.IsNullOrEmpty(path) Then
159                 path = $"{attr.Name} {path.CLIPath}"
160             End If
161             Return path
162         End Function
163
164         ''' <summary>
165         ''' 可能包含有枚举值
166         ''' </summary>
167         ''' <param name="value"></param>
168         ''' <param name="attr"></param>
169         ''' <param name="prop"></param>
170         ''' <returns></returns>
171         Private Function __stringRule(value As Object, attr As [Optional], prop As PropertyInfo) As String
172             If prop.PropertyType.Equals(GetType(String)) Then
173                 Dim str As String = Scripting.ToString(value)
174                 If String.IsNullOrEmpty(str) Then
175                     Return ""
176                 Else
177                     Return $"{attr.Name} {str.CLIToken}"
178                 End If
179             ElseIf prop.PropertyType.IsInheritsFrom(GetType([Enum])) Then
180                 Return __stringEnumRule(value, attr, prop)
181             Else
182                 Dim str As String = Scripting.ToString(value)
183                 Return $"{attr.Name} {str}"
184             End If
185         End Function
186
187         Private Function __stringEnumRule(value As Object, attr As [Optional], prop As PropertyInfo) As String
188             Dim enumValue As [Enum] = DirectCast(value, System.Enum)
189             Dim type As Type = prop.PropertyType
190             Dim enumFields As FieldInfo() = type.GetFields
191             Dim nullGet = (From x As FieldInfo In enumFields
192                            Let flag As NullOrDefault = x.GetAttribute(Of NullOrDefault)
193                            Where Not flag Is Nothing
194                            Select flag, x).FirstOrDefault
195             If nullGet Is Nothing Then  '没有默认值
196 rtvl:           Dim strValue As String = enumValue.Description
197                 Return $"{attr.Name} {strValue.CLIToken}"
198             Else
199                 If nullGet.x.GetValue(Nothing).Equals(value) Then
200                     Dim str As String = nullGet.flag.value      ' 是默认值,则返回默认值
201                     If String.IsNullOrEmpty(str) Then
202                         Return ""
203                     Else
204                         Return $"{attr.Name} {str}"
205                     End If
206                 Else
207                     GoTo rtvl
208                 End If
209             End If
210         End Function
211
212         ''' <summary>
213         ''' Property value to boolean flag in the CLI
214         ''' </summary>
215         ''' <param name="value"></param>
216         ''' <param name="attr"></param>
217         ''' <param name="prop"></param>
218         ''' <returns></returns>
219         Private Function __booleanRule(value As Object, attr As [Optional], prop As PropertyInfo) As String
220             Dim name As String = attr.Name
221             Dim b As Boolean
222
223             If prop.PropertyType.Equals(GetType(Boolean)) Then
224                 b = DirectCast(value, Boolean)
225             Else
226                 Dim str As String = Scripting.ToString(value)
227                 b = str.ParseBoolean
228             End If
229
230             If b Then
231                 Return name
232             Else
233                 Return ""
234             End If
235         End Function
236 #End Region
237
238         ''' <summary>
239         ''' Reset the CLI parameters property in the target class object.
240         ''' </summary>
241         ''' <typeparam name="TInteropService"></typeparam>
242         ''' <param name="inst"></param>
243         ''' <returns>返回所重置的参数的个数</returns>
244         ''' <remarks></remarks>
245         Public Function ClearParameters(Of TInteropService As Class)(inst As TInteropService) As Integer
246             Dim n As Integer
247             Dim lstProperty As PropertyInfo() = inst.GetType().GetProperties()
248
249             Try
250                 For Each [Property] As PropertyInfo In lstProperty
251                     Dim attrs As Object() = [Property].GetCustomAttributes(_typeInfo, inherit:=False)
252                     If Not (attrs Is Nothing OrElse attrs.Length = 0) Then
253                         Call [Property].SetValue(inst, ""Nothing)
254                         n += 1
255                     End If
256                 Next
257             Catch ex As Exception
258                 Throw New InvalidOperationException(InvalidOperation)
259             End Try
260
261             Return n
262         End Function
263
264         Const InvalidOperation$ = "The target type information is not the 'System.String'!"
265     End Module
266 End Namespace