1 #Region "Microsoft.VisualBasic::c2476a3f0b6d1aa41c34fcfda30c2b17, Microsoft.VisualBasic.Core\ApplicationServices\Terminal\PrintAsTable.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 PrintAsTable
35     
36     '         Function: Print
37     
38     '         Sub: Print, PrintTable
39     '         Delegate Sub
40     
41     '             Sub: (+3 Overloads) Print, printInternal
42     
43     
44     
45     ' /********************************************************************************/
46
47 #End Region
48
49 Imports System.IO
50 Imports System.Runtime.CompilerServices
51 Imports System.Text
52 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
53 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel.SchemaMaps
54 Imports Microsoft.VisualBasic.Language
55 Imports Microsoft.VisualBasic.Linq
56
57 Namespace ApplicationServices.Terminal
58
59     Public Module PrintAsTable
60
61         ''' <summary>
62         ''' Returns a text string 
63         ''' </summary>
64         ''' <typeparam name="T"></typeparam>
65         ''' <param name="source"></param>
66         ''' <param name="addBorder"></param>
67         ''' <returns></returns>
68         <Extension>
69         Public Function Print(Of T)(source As IEnumerable(Of T), Optional addBorder As Boolean = TrueAs String
70             Dim out As New StringBuilder
71             Dim dev As New StringWriter(out)
72             Call source.Print(dev, addBorder)
73             Return out.ToString
74         End Function
75
76         ''' <summary>
77         ''' Print the object collection as table on the console 
78         ''' </summary>
79         ''' <typeparam name="T"></typeparam>
80         ''' <param name="source"></param>
81         ''' <param name="dev"></param>
82         ''' <param name="addBorder"></param>
83         <Extension>
84         Public Sub Print(Of T)(source As IEnumerable(Of T), dev As TextWriter, Optional addBorder As Boolean = True)
85             Dim schema = LinqAPI.Exec(Of BindProperty(Of DataFrameColumnAttribute)) _
86  _
87                 () <= From x As BindProperty(Of DataFrameColumnAttribute)
88                       In DataFrameColumnAttribute _
89                           .LoadMapping(Of T)(mapsAll:=True) _
90                           .Values
91                       Where x.IsPrimitive
92                       Select x
93
94             Dim titles As String() = schema.Select(Function(x) x.Identity).ToArray
95             Dim contents = LinqAPI.Exec(Of Dictionary(Of StringString)) _
96  _
97                 () <= From x As T
98                       In source
99                       Select (From p As BindProperty(Of DataFrameColumnAttribute)
100                               In schema
101                               Select p,
102                                   s = p.GetValue(x)) _
103                           .ToDictionary(Function(o) o.p.Identity,
104                                         Function(o) Scripting.ToString(o.s))
105
106             Dim table As List(Of String()) =
107                 contents _
108                 .Select(Function(line)
109                             Return titles.Select(Function(name) line(name)).ToArray
110                         End Function) _
111                 .AsList
112
113             If addBorder Then
114                 Call (titles + table).PrintTable(dev, sep:=" "c)
115             Else
116                 Call (titles + table).Print(dev, sep:=" "c)
117             End If
118         End Sub
119
120         ''' <summary>
121         ''' 与函数<see cref="Print"/>所不同的是,这个函数还会添加边框
122         ''' </summary>
123         ''' <param name="source"></param>
124         ''' <param name="dev"></param>
125         ''' <param name="sep"></param>
126         <Extension>
127         Public Sub PrintTable(source As IEnumerable(Of String()),
128                               Optional dev As TextWriter = Nothing,
129                               Optional sep As Char = " "c,
130                               Optional title$() = Nothing,
131                               Optional trilinearTable As Boolean = False,
132                               Optional leftMargin% = 0)
133
134             Dim printHead As Boolean = False
135             Dim table$()() = source.ToArray
136             Dim printOfHead As printOnDevice =
137                 Sub(row, width, maxLen, device)
138
139                     If leftMargin > 0 Then
140                         Call device.Write(New String(sep, leftMargin))
141                     End If
142
143                     Call device.Write("+")
144                     Call device.Write(maxLen.Select(Function(l) New String("-"c, l)).JoinBy("+"))
145                     Call device.Write("+")
146                     Call device.WriteLine()
147                 End Sub
148
149             If Not title Is Nothing Then
150                 table = title.Join(table).ToArray
151             End If
152
153             Call table.printInternal(
154                 dev, 2, Sub(row, width, maxLen, device)
155                             Dim offset% = 0
156
157                             If Not printHead Then
158                                 Call printOfHead(Nothing, width, maxLen, device)
159                             End If
160                             If leftMargin > 0 Then
161                                 Call device.Write(New String(sep, leftMargin))
162                             End If
163                             If Not trilinearTable Then
164                                 Call device.Write("|")
165                             End If
166
167                             For i As Integer = 0 To width - 1
168                                 If row(i) Is Nothing Then
169                                     row(i) = ""
170                                 End If
171
172                                 If trilinearTable Then
173                                     device.Write(" ")
174                                 End If
175
176                                 offset = maxLen(i) - row(i).Length - 1
177                                 device.Write(" " & row(i) & New String(sep, offset))
178
179                                 If Not trilinearTable Then
180                                     Call device.Write("|")
181                                 End If
182                             Next
183
184                             Call device.WriteLine()
185
186                             If Not printHead Then
187                                 Call printOfHead(Nothing, width, maxLen, device)
188                                 printHead = True
189                             End If
190                         End Sub, printOfHead)
191         End Sub
192
193         Private Delegate Sub printOnDevice(row$(), width%, maxLen%(), device As TextWriter)
194
195         <Extension>
196         Private Sub printInternal(table$()(), dev As TextWriter, distance%, printLayout As printOnDevice, Optional final As printOnDevice = Nothing)
197             With dev Or Console.Out.AsDefault
198                 Dim width% = table.Max(Function(row) row.Length)
199                 Dim index%
200                 Dim maxLen%() = New Integer(width - 1) {}
201
202                 ' 按照列计算出layout偏移量
203                 For i As Integer = 0 To width - 1
204                     index = i
205                     maxLen(index) = table _
206                         .Select(Function(row) row.ElementAtOrDefault(index)) _
207                         .Select(Function(s)
208                                     If String.IsNullOrEmpty(s) Then
209                                         Return 0
210                                     Else
211                                         Return s.Length
212                                     End If
213                                 End Function) _
214                         .Max + distance
215                 Next
216
217                 For Each row As String() In table
218                     Call printLayout(row, width, maxLen, .ByRef)
219                 Next
220
221                 If Not final Is Nothing Then
222                     Call final(Nothing, width, maxLen, .ByRef)
223                 End If
224
225                 Call .Flush()
226             End With
227         End Sub
228
229         ''' <summary>
230         ''' Print the string matrix collection <paramref name="source"/> in table layout.
231         ''' </summary>
232         ''' <param name="source">The string matrix collection.</param>
233         ''' <param name="dev">The output device</param>
234         ''' <param name="sep"></param>
235         <MethodImpl(MethodImplOptions.AggressiveInlining)>
236         <Extension>
237         Public Sub Print(source As IEnumerable(Of String()), Optional dev As TextWriter = NothingOptional sep As Char = " "c, Optional distance% = 2)
238             Call source _
239                 .ToArray _
240                 .printInternal(
241                     dev, distance, Sub(row, width, maxLen, device)
242                                        Dim offset% = 0
243
244                                        For i As Integer = 0 To width - 1
245                                            If row(i) Is Nothing Then
246                                                row(i) = ""
247                                            End If
248
249                                            device.Write(New String(sep, offset) & row(i))
250                                            offset = maxLen(i) - row(i).Length
251                                        Next
252
253                                        Call device.WriteLine()
254                                    End Sub)
255         End Sub
256
257         ''' <summary>
258         ''' Print the string dictionary as table
259         ''' </summary>
260         ''' <param name="table"></param>
261         ''' <param name="dev"></param>
262         ''' <param name="sep"></param>
263         <MethodImpl(MethodImplOptions.AggressiveInlining)>
264         <Extension>
265         Public Sub Print(table As Dictionary(Of StringString),
266                          Optional dev As TextWriter = Nothing,
267                          Optional sep As Char = " "c,
268                          Optional distance% = 2)
269             Call {
270                 New String() {"Item""Value"}
271             } _
272             .Join(table.Select(Function(map) {map.Key, map.Value})) _
273             .Print(dev, sep, distance)
274         End Sub
275
276         <MethodImpl(MethodImplOptions.AggressiveInlining)>
277         <Extension>
278         Public Sub Print(data As IEnumerable(Of NamedValue(Of String)),
279                          Optional dev As TextWriter = Nothing,
280                          Optional sep As Char = " "c,
281                          Optional trilinearTable As Boolean = False,
282                          Optional leftMargin% = 0)
283             Call {
284                 New String() {"Name""Value""Description"}
285             } _
286             .Join(data.Select(Function(item)
287                                   Return {item.Name, item.Value, item.Description}
288                               End Function)) _
289             .PrintTable(
290                 dev,
291                 sep,
292                 trilinearTable:=trilinearTable,
293                 leftMargin:=leftMargin)
294         End Sub
295     End Module
296 End Namespace