Makefile: talk about nit_env.sh after successful `make all`
[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 benitlux_model
16 import benitlux_db
17 import correct
18
19 # Sort beers by their availability
20 class BeerComparator
21 super Comparator
22
23 # 1st sorting priority
24 var map1: HashMap[COMPARED, Comparable]
25
26 # 2nd sorting priority
27 var map2: HashMap[COMPARED, Comparable]
28
29 # Key compare
30 redef fun compare(a, b) do return if map1[a] == map1[b] then
31 map2[a] <=> map2[b]
32 else map1[a] <=> map1[b]
33 end
34
35 redef class Text
36
37 # Get the background for the date `self` of format `yyyy-mm-dd`
38 private fun date_to_back: String
39 do
40 assert length == 10
41
42 var m = substring(5, 2)
43 var month = m.to_i
44 if [4..9].has(month) then return " "
45 return "-"
46 end
47 end
48
49 # Use the local DB
50 var db_path = "benitlux_sherbrooke.db"
51 var db = new DB.open(db_path)
52
53 # All known beers
54 var beers = db.beers
55 assert beers != null
56 print "{beers.length} known beers"
57
58 # All days
59 var all_days = db.days
60 assert all_days != null
61 print "{all_days.length} days, from {all_days.first} to {all_days.last}"
62
63 # Beers availability by days
64 var beer2days = new HashMap[Beer, Array[String]]
65 for beer in beers do
66 var days = db.days(beer)
67 assert days != null
68 default_comparator.sort days
69 beer2days[beer] = days
70 end
71
72 # Sort beers by their availability and first date of appearance
73 var availability = new HashMap[Beer, Int]
74 var appearances = new HashMap[Beer, String]
75 for beer in beers do
76 var days = beer2days[beer]
77 if days.not_empty then
78 appearances[beer] = days.first
79 availability[beer] = -days.length # Opposite for inverse sort
80 else
81 appearances[beer] = "err"
82 availability[beer] = 1
83 end
84 end
85
86 # Sort by availability then appearance
87 var sorter: Comparator = new BeerComparator(availability, appearances)
88 sorter.sort beers
89
90 # List all beers
91 print "\nBeers:"
92 for beer in beers do
93 var days = beer2days[beer]
94
95 # Skip never-available beers, usually name errors
96 if days.is_empty then continue
97
98 var from = days.first
99 if from == all_days.first then from = " ... "
100
101 var to = days.last
102 if to == all_days.last then to = " ... "
103
104 print "- {days.length}\t{from} {to}\t{beer.name}: {beer.desc}"
105 end
106
107 # Sort by appearance then availability
108 sorter = new BeerComparator(appearances, availability)
109 sorter.sort beers
110
111 # Display the batch graph
112 print "\nAvailability graph:"
113
114 # Compute `column_width` days from all the known days
115 var column_width = 70
116 var days_sample = [for i in column_width.times do all_days[i*all_days.length/column_width]]
117
118 # Gather columns headers for each month
119 var headers = new Array[nullable String]
120 var pre = ""
121 for day in days_sample do
122 var new_pre = day.substring(0, 7)
123
124 if not day.has_prefix(pre) then
125 headers.add new_pre
126 else headers.add null
127
128 pre = new_pre
129 end
130
131 # Draw the headers from top to bottom so they look like:
132 #
133 # ~~~
134 # 2
135 # 0
136 # 1
137 # 5
138 # -
139 # 0
140 # 1
141 # ~~~
142 for l in 7.times do
143 for header in headers do
144 if header != null then
145 printn header[l]
146 else printn " "
147 end
148 print ""
149 end
150
151 for beer in beers do
152 var days = beer2days[beer]
153
154 # Skip never-available beers, usually name errors
155 if days.is_empty then continue
156
157 # Print a line looking like: " ############ ###### -----########-: Beer"
158 for s in days_sample do printn if days.has(s) then "#" else s.date_to_back
159 print ": {beer.name}"
160 end
161
162 db.close