Merge: introduce nit_env.sh to setup the shell environement
[nit.git] / contrib / benitlux / src / report.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import opts
16
17 import benitlux_model
18 import benitlux_db
19 import correct
20
21 # Sort beers by their availability
22 class BeerComparator
23 super Comparator
24
25 # 1st sorting priority
26 var map1: HashMap[COMPARED, Comparable]
27
28 # 2nd sorting priority
29 var map2: HashMap[COMPARED, Comparable]
30
31 # Key compare
32 redef fun compare(a, b) do return if map1[a] == map1[b] then
33 map2[a] <=> map2[b]
34 else map1[a] <=> map1[b]
35 end
36
37 redef class Text
38
39 # Get the background for the date `self` of format `yyyy-mm-dd`
40 private fun date_to_back: String
41 do
42 assert length == 10
43
44 var m = substring(5, 2)
45 var month = m.to_i
46 if [4..9].has(month) then return " "
47 return "-"
48 end
49 end
50
51 var opts = new OptionContext
52 var opt_columns = new OptionInt("Number of columns for the graph", 70, "-c")
53 opts.add_option(opt_columns)
54
55 opts.parse(args)
56 var rest = opts.rest
57
58 # Use the local DB
59 var db_path = "benitlux_sherbrooke.db"
60 if rest.not_empty then db_path = rest.first
61 var db = new DB.open(db_path)
62
63 # All known beers
64 var beers = db.beers
65 assert beers != null
66 print "{beers.length} known beers"
67
68 # All days
69 var all_days = db.days
70 assert all_days != null
71 print "{all_days.length} days, from {all_days.first} to {all_days.last}"
72
73 # Beers availability by days
74 var beer2days = new HashMap[Beer, Array[String]]
75 for beer in beers do
76 var days = db.days(beer)
77 assert days != null
78 default_comparator.sort days
79 beer2days[beer] = days
80 end
81
82 # Sort beers by their availability and first date of appearance
83 var availability = new HashMap[Beer, Int]
84 var appearances = new HashMap[Beer, String]
85 for beer in beers do
86 var days = beer2days[beer]
87 if days.not_empty then
88 appearances[beer] = days.first
89 availability[beer] = -days.length # Opposite for inverse sort
90 else
91 appearances[beer] = "err"
92 availability[beer] = 1
93 end
94 end
95
96 # Sort by availability then appearance
97 var sorter: Comparator = new BeerComparator(availability, appearances)
98 sorter.sort beers
99
100 # List all beers
101 print "\nBeers:"
102 for beer in beers do
103 var days = beer2days[beer]
104
105 # Skip never-available beers, usually name errors
106 if days.is_empty then continue
107
108 var from = days.first
109 if from == all_days.first then from = " ... "
110
111 var to = days.last
112 if to == all_days.last then to = " ... "
113
114 print "- {days.length}\t{from} {to}\t{beer.name}: {beer.desc}"
115 end
116
117 # Sort by appearance then availability
118 sorter = new BeerComparator(appearances, availability)
119 sorter.sort beers
120
121 # Display the batch graph
122 print "\nAvailability graph:"
123
124 # Compute `column_width` days from all the known days
125 var column_width = opt_columns.value
126 var days_sample = [for i in [1..column_width[ do all_days[i*all_days.length/column_width]]
127 var weeks_sample = new Array[Array[String]]
128
129 # Gather columns headers for each month
130 var headers = new Array[nullable String]
131 var iter = all_days.iterator
132 iter.start
133 var pre = ""
134 for day in days_sample do
135 # Prepare headers
136 var new_pre = day.substring(0, 7)
137
138 if not day.has_prefix(pre) then
139 headers.add new_pre
140 else headers.add null
141
142 pre = new_pre
143
144 # Fill weeks
145 var week = new Array[String]
146 weeks_sample.add week
147 while iter.is_ok do
148 var item = iter.item
149 if item == day then break
150 week.add item
151 iter.next
152 end
153 end
154
155 # Draw the headers from top to bottom so they look like:
156 #
157 # ~~~
158 # 2
159 # 0
160 # 1
161 # 5
162 # -
163 # 0
164 # 1
165 # ~~~
166 for l in 7.times do
167 for header in headers do
168 if header != null then
169 printn header[l]
170 else printn " "
171 end
172 print ""
173 end
174
175 for beer in beers do
176 var days = beer2days[beer]
177
178 # Skip never-available beers, usually name errors
179 if days.is_empty then continue
180
181 # Print a line looking like: " ############ ###### -----########- Beer"
182 var last = null
183 #var iter = days.iterator
184 for week in weeks_sample do
185 printn if days.has_all(week) then
186 "#"
187 else if days.has_any(week) then
188 ":"
189 else week.first.date_to_back
190 end
191 print " {beer.name}"
192 end
193
194 db.close