1 /*
2 File timetable_defs.cpp
3 */
4 
5 /***************************************************************************
6                           timetable_defs.cpp  -  description
7                              -------------------
8     begin                : Sat Mar 15 2003
9     copyright            : (C) 2003 by Lalescu Liviu
10     email                : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
11  ***************************************************************************/
12 
13 /***************************************************************************
14  *                                                                         *
15  *   This program is free software: you can redistribute it and/or modify  *
16  *   it under the terms of the GNU Affero General Public License as        *
17  *   published by the Free Software Foundation, either version 3 of the    *
18  *   License, or (at your option) any later version.                       *
19  *                                                                         *
20  ***************************************************************************/
21 
22 #include "timetable_defs.h"
23 
24 //#include <ctime>
25 #include <chrono>
26 
27 #include <QHash>
28 
29 #include <QLocale>
30 
31 bool checkForUpdates;
32 
33 QString internetVersion;
34 
35 int STUDENTS_COMBO_BOXES_STYLE=STUDENTS_COMBO_BOXES_STYLE_SIMPLE;
36 
37 /**
38 FET version
39 */
40 const QString FET_VERSION="6.2.0";
41 
42 /**
43 FET language
44 */
45 QString FET_LANGUAGE="en_US";
46 
47 /**
48 The output directory. Please be careful when editing it,
49 because the functions add a FILE_SEP sign at the end of it
50 and then the name of a file. If you make OUTPUT_DIR="",
51 there will be problems.
52 */
53 QString OUTPUT_DIR;
54 
55 bool LANGUAGE_STYLE_RIGHT_TO_LEFT;
56 
57 QString LANGUAGE_FOR_HTML;
58 
59 /**
60 Timetable html css javaScript Level, by Volker Dirr
61 */
62 int TIMETABLE_HTML_LEVEL;
63 
64 bool TIMETABLE_HTML_PRINT_ACTIVITY_TAGS;
65 
66 bool PRINT_DETAILED_HTML_TIMETABLES;
67 
68 bool PRINT_DETAILED_HTML_TEACHERS_FREE_PERIODS;
69 
70 bool PRINT_NOT_AVAILABLE_TIME_SLOTS;
71 
72 bool PRINT_BREAK_TIME_SLOTS;
73 
74 bool PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME;
75 
76 bool DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS;
77 
78 bool TIMETABLE_HTML_REPEAT_NAMES;
79 
80 bool VERBOSE;
81 
82 //these hashes are needed to get the IDs for html and css in timetableexport and statistics
83 /*QHash<QString, QString> hashSubjectIDs;
84 QHash<QString, QString> hashActivityTagIDs;
85 QHash<QString, QString> hashStudentIDs;
86 QHash<QString, QString> hashTeacherIDs;
87 QHash<QString, QString> hashRoomIDs;
88 QHash<QString, QString> hashDayIDs;*/
89 
90 /**
91 A log file explaining how the xml input file was parsed
92 */
93 const QString XML_PARSING_LOG_FILENAME="file_open.log";
94 
95 /**
96 The predefined names of the days of the week
97 */
98 /*
99 const QString PREDEFINED_DAYS_OF_THE_WEEK[]={"Monday", "Tuesday", "Wednesday",
100 	"Thursday", "Friday", "Saturday", "Sunday", "Monday2",
101 	"Tuesday2", "Wednesday2", "Thursday2", "Friday2", "Saturday2", "Sunday2",
102 	"Monday3", "Tuesday3", "Wednesday3",
103 	"Thursday3", "Friday3", "Saturday3", "Sunday3", "Monday4",
104 	"Tuesday4", "Wednesday4", "Thursday4", "Friday4", "Saturday4", "Sunday4"};
105 */
106 
107 /**
108 File and directory separator
109 */
110 const QString FILE_SEP="/";
111 
protect(const QString & str)112 QString protect(const QString& str) //used for XML
113 {
114 	QString p=str;
115 	p.replace("&", "&amp;");
116 	p.replace("\"", "&quot;");
117 	p.replace(">", "&gt;");
118 	p.replace("<", "&lt;");
119 	p.replace("'", "&apos;");
120 	return p;
121 }
122 
protect2(const QString & str)123 QString protect2(const QString& str) //used for HTML
124 {
125 	QString p=str;
126 	p.replace("&", "&amp;");
127 	p.replace("\"", "&quot;");
128 	p.replace(">", "&gt;");
129 	p.replace("<", "&lt;");
130 	//p.replace("'", "&apos;");
131 	return p;
132 }
133 
protect2vert(const QString & str)134 QString protect2vert(const QString& str) //used for HTML
135 {
136 	QString p=str;
137 	p.replace("&", "&amp;");
138 	p.replace("\"", "&quot;");
139 	p.replace(">", "&gt;");
140 	p.replace("<", "&lt;");
141 	//p.replace("'", "&apos;");
142 
143 	QString returnstring;
144 	for(int i=0; i<p.size();i++){
145 		QString a=p.at(i);
146 		QString b="<br />";
147 		returnstring.append(a);
148 		returnstring.append(b);
149 	}
150 	return returnstring;
151 }
152 
153 ///////begin tricks
weight_sscanf(const QString & str,const char * fmt,double * result)154 void weight_sscanf(const QString& str, const char* fmt, double* result)
155 {
156 	assert(QString(fmt)==QString("%lf"));
157 
158 	bool ok;
159 	double myres=customFETStrToDouble(str, &ok);
160 	if(!ok)
161 		(*result)=-2.5; //any value that does not belong to {>=0.0 and <=100.0} or {-1.0}
162 						//not -1.0 because of modify multiple constraints min days between activities,
163 						//-1 there represents any weight
164 						//potential bug found by Volker Dirr
165 	else
166 		(*result)=myres;
167 }
168 
number(int n)169 QString CustomFETString::number(int n)
170 {
171 	return QString::number(n);
172 }
173 
number(double x)174 QString CustomFETString::number(double x)
175 {
176 	QString tmp=QString::number(x, 'f', CUSTOM_DOUBLE_PRECISION);
177 
178 	//remove trailing zeroes AFTER the decimal points
179 	if(tmp.contains('.')){
180 		int n=tmp.length()-1;
181 		int del=0;
182 		while(tmp.at(n)=='0'){
183 			n--;
184 			del++;
185 		}
186 		if(tmp.at(n)=='.'){
187 			n--;
188 			del++;
189 		}
190 		tmp.chop(del);
191 	}
192 
193 	return tmp;
194 }
195 
numberPlusTwoDigitsPrecision(double x)196 QString CustomFETString::numberPlusTwoDigitsPrecision(double x)
197 {
198 	QString tmp=QString::number(x, 'f', CUSTOM_DOUBLE_PRECISION+2);
199 
200 	//remove trailing zeroes AFTER the decimal points
201 	if(tmp.contains('.')){
202 		int n=tmp.length()-1;
203 		int del=0;
204 		while(tmp.at(n)=='0'){
205 			n--;
206 			del++;
207 		}
208 		if(tmp.at(n)=='.'){
209 			n--;
210 			del++;
211 		}
212 		tmp.chop(del);
213 	}
214 
215 	return tmp;
216 }
217 
customFETStrToDouble(const QString & str,bool * ok)218 double customFETStrToDouble(const QString& str, bool* ok)
219 {
220 	QLocale c(QLocale::C);
221 
222 	//tricks to convert numbers like 97.123456789 to 97.123457, to CUSTOM_DOUBLE_PRECISION (6) decimal digits after the decimal point
223 	double tmpd=c.toDouble(str, ok);
224 	if(ok!=0)
225 		if((*ok)==false)
226 			return tmpd;
227 	QString tmps=CustomFETString::number(tmpd);
228 	return c.toDouble(tmps, ok);
229 }
230 ///////end tricks
231 
232 bool BEEP_AT_END_OF_GENERATION=true;
233 bool ENABLE_COMMAND_AT_END_OF_GENERATION=true;
234 QString commandAtEndOfGeneration=QString("");
235 //bool DETACHED_NOTIFICATION=false;
236 //int terminateCommandAfterSeconds=0;
237 //int killCommandAfterSeconds=0;
238 
239 /*
240 int XX;
241 int YY;
242 int ZZ;
243 
244 //random routines
245 void initRandomKnuth()
246 {
247 	assert(MM==2147483647);
248 	assert(AA==48271);
249 	assert(QQ==44488);
250 	assert(RR==3399);
251 
252 	assert(MMM==2147483399);
253 	assert(MMM==MM-248);
254 	assert(AAA==40692);
255 	assert(QQQ==52774);
256 	assert(RRR==3791);
257 
258 	//a few tests
259 	XX=123; YY=123;
260 	int tttt=randomKnuth1MM1();
261 	assert(XX==5937333);
262 	assert(YY==5005116);
263 	assert(tttt==932217);
264 
265 	XX=4321; YY=54321;
266 	tttt=randomKnuth1MM1();
267 	assert(XX==208578991);
268 	assert(YY==62946733);
269 	assert(tttt==145632258);
270 
271 	XX=87654321; YY=987654321;
272 	tttt=randomKnuth1MM1();
273 	assert(XX==618944401);
274 	assert(YY==1625301246);
275 	assert(tttt==1141126801);
276 
277 	XX=1; YY=1;
278 	tttt=randomKnuth1MM1();
279 	assert(XX==48271);
280 	assert(YY==40692);
281 	assert(tttt==7579);
282 
283 	XX=MM-1; YY=MMM-1;
284 	tttt=randomKnuth1MM1();
285 	assert(XX==2147435376);
286 	assert(YY==2147442707);
287 	assert(tttt==2147476315);
288 
289 	XX=100; YY=1000;
290 	tttt=randomKnuth1MM1();
291 	assert(XX==4827100);
292 	assert(YY==40692000);
293 	assert(tttt==2111618746);
294 	//////////
295 
296 	//unsigned tt=unsigned(time(nullptr));
297 	qint64 tt=qint64(time(nullptr));
298 
299 	//XX is the current time
300 	//XX = 1 + ( (unsigned(tt)) % (unsigned(MM-1)) );
301 	XX = 1 + int( tt%(qint64(MM-1)) );
302 	assert(XX>0);
303 	assert(XX<MM);
304 
305 	//YY is the next random, after initializing YY with the current time
306 	//YY = 1 + ( (unsigned(tt)) % (unsigned(MMM-1)) );
307 	YY = 1 + int( tt%(qint64(MMM-1)) );
308 	assert(YY>0);
309 	assert(YY<MMM);
310 	YY=AAA*(YY%QQQ)-RRR*(YY/QQQ);
311 	if(YY<0)
312 		YY+=MMM;
313 	assert(YY>0);
314 	assert(YY<MMM);
315 
316 	ZZ=XX-YY;
317 	if(ZZ<=0)
318 		ZZ+=MM-1; //-1 is not written in Knuth TAOCP vol. 2 third edition; I think it would be an improvement. (Later edit: yes, the author confirmed that).
319 	assert(ZZ>0);
320 	assert(ZZ<MM); //again, modified from Knuth TAOCP vol. 2 third edition, ZZ is strictly lower than MM (the author confirmed that, too).
321 }
322 
323 int randomKnuth1MM1()
324 {
325 	assert(XX>0);
326 	assert(XX<MM);
327 
328 	XX=AA*(XX%QQ)-RR*(XX/QQ);
329 	if(XX<0)
330 		XX+=MM;
331 
332 	assert(XX>0);
333 	assert(XX<MM);
334 
335 	assert(YY>0);
336 	assert(YY<MMM);
337 
338 	YY=AAA*(YY%QQQ)-RRR*(YY/QQQ);
339 	if(YY<0)
340 		YY+=MMM;
341 
342 	assert(YY>0);
343 	assert(YY<MMM);
344 
345 	ZZ=XX-YY;
346 	if(ZZ<=0)
347 		ZZ+=MM-1; //-1 is not written in Knuth TAOCP vol. 2 third edition; I think it would be an improvement. (Later edit: yes, the author confirmed that).
348 	assert(ZZ>0);
349 	assert(ZZ<MM); //again, modified from Knuth TAOCP vol. 2 third edition, ZZ is strictly lower than MM (the author confirmed that, too).
350 
351 	return ZZ;
352 }
353 
354 int randomKnuth(int k)
355 {
356 	//like in Knuth TAOCP vol.2, reject some numbers (very few), so that the distribution is perfectly uniform
357 	for(;;){
358 		int U=randomKnuth1MM1();
359 		if( U <= k * ((MM-1)/k) )
360 			return U%k;
361 	}
362 }
363 */
364 
365 //MRG32k3a rng;
366 
367 const qint64 MRG32k3a::m1 = Q_INT64_C(4294967087);
368 const qint64 MRG32k3a::m2 = Q_INT64_C(4294944443);
369 const qint64 MRG32k3a::a12 = Q_INT64_C(1403580);
370 const qint64 MRG32k3a::a13n = Q_INT64_C(810728);
371 const qint64 MRG32k3a::a21 = Q_INT64_C(527612);
372 const qint64 MRG32k3a::a23n = Q_INT64_C(1370589);
373 
MRG32k3a()374 MRG32k3a::MRG32k3a()
375 {
376 	//not permitted values, so we check that we don't forget to init this RNG in another place.
377 	s10=s11=s12=0;
378 	s20=s21=s22=0;
379 }
380 
~MRG32k3a()381 MRG32k3a::~MRG32k3a()
382 {
383 }
384 
initializeMRG32k3a(qint64 _s10,qint64 _s11,qint64 _s12,qint64 _s20,qint64 _s21,qint64 _s22)385 void MRG32k3a::initializeMRG32k3a(qint64 _s10, qint64 _s11, qint64 _s12,
386 	qint64 _s20, qint64 _s21, qint64 _s22)
387 {
388 	assert(m1==Q_INT64_C(4294967296)-Q_INT64_C(209));
389 	assert(m1==Q_INT64_C(4294967087));
390 
391 	assert(m2==Q_INT64_C(4294967296)-Q_INT64_C(22853));
392 	assert(m2==Q_INT64_C(4294944443));
393 
394 	assert(a12==Q_INT64_C(1403580));
395 	assert(a13n==Q_INT64_C(810728));
396 
397 	assert(a21==Q_INT64_C(527612));
398 	assert(a23n==Q_INT64_C(1370589));
399 
400 	assert(_s10>=0);
401 	assert(_s11>=0);
402 	assert(_s12>=0);
403 
404 	assert(_s20>=0);
405 	assert(_s21>=0);
406 	assert(_s22>=0);
407 
408 	assert(_s10 < m1);
409 	assert(_s11 < m1);
410 	assert(_s12 < m1);
411 
412 	assert(_s20 < m2);
413 	assert(_s21 < m2);
414 	assert(_s22 < m2);
415 
416 	assert(_s10>0 || _s11>0 || _s12>0);
417 	assert(_s20>0 || _s21>0 || _s22>0);
418 
419 	s10=_s10;
420 	s11=_s11;
421 	s12=_s12;
422 
423 	s20=_s20;
424 	s21=_s21;
425 	s22=_s22;
426 }
427 
initializeMRG32k3a()428 void MRG32k3a::initializeMRG32k3a()
429 {
430 	qint64 _s10, _s11, _s12, _s20, _s21, _s22;
431 
432 	//qint64 tt=qint64(time(nullptr));
433 
434 	std::chrono::seconds s=std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
435 	qint64 si=static_cast<qint64>(s.count());
436 	//cout<<"si=="<<si<<endl;
437 	assert(si>=0);
438 	_s10=si%m1;
439 	if(_s10==0) //just in case :-)  . It could even be allowed to be 0, but then we wouldn't have a certain guarantee that not all seeds in component 1 are 0.
440 		_s10=1;
441 
442 	_s20=si%m2;
443 	if(_s20==0) //just in case :-)  . It could even be allowed to be 0, but then we wouldn't have a certain guarantee that not all seeds in component 2 are 0.
444 		_s20=1;
445 
446 	/*_s10 = 1 + tt%(m1-1);
447 	assert(_s10>=1);
448 	assert(_s10<m1);
449 
450 	_s20 = 1 + tt%(m2-1);
451 	assert(_s20>=1);
452 	assert(_s20<m2);*/
453 
454 	//Using ideas and code from https://stackoverflow.com/questions/19555121/how-to-get-current-timestamp-in-milliseconds-since-1970-just-the-way-java-gets
455 	//and https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back
456 	//and https://stackoverflow.com/questions/18022927/convert-high-resolution-clock-time-into-an-integer-chrono/18023064
457 	std::chrono::nanoseconds ns=std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch());
458 	qint64 nsi=static_cast<qint64>(ns.count());
459 	//cout<<"nsi=="<<nsi<<endl;
460 	assert(nsi>=0);
461 
462 	_s11=nsi%1000000000;
463 
464 	std::chrono::nanoseconds ns2=std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch());
465 	qint64 nsi2=static_cast<qint64>(ns2.count());
466 	//cout<<"nsi2=="<<nsi2<<endl;
467 	assert(nsi2>=0);
468 
469 	_s21=nsi2%1000000000;
470 
471 	_s12=0; //We could try other better methods, but they need to be portable.
472 	_s22=0;
473 
474 	initializeMRG32k3a(_s10, _s11, _s12, _s20, _s21, _s22);
475 }
476 
uiMRG32k3a()477 unsigned int MRG32k3a::uiMRG32k3a()
478 {
479 	assert(s10>0 || s11>0 || s12>0);
480 	assert(s20>0 || s21>0 || s22>0);
481 
482 	qint64 p, p1, p2;
483 
484 	/* Component 1 */
485 	p1 = a12*s11 - a13n*s10;
486 	p1%=m1;
487 	if(p1<0)
488 		p1+=m1;
489 	assert(p1>=0 && p1<m1);
490 	s10 = s11;
491 	s11 = s12;
492 	s12 = p1;
493 
494 	/* Component 2 */
495 	p2 = a21*s22 - a23n*s20;
496 	p2%=m2;
497 	if(p2<0)
498 		p2+=m2;
499 	assert(p2>=0 && p2<m2);
500 	s20 = s21;
501 	s21 = s22;
502 	s22 = p2;
503 
504 	/* Combination */
505 	p=p1-p2;
506 	if(p<0)
507 		p+=m1;
508 	assert(p>=0 && p<m1);
509 
510 	return (unsigned int)(p);
511 }
512 
513 /*double MRG32k3a::dMRG32k3a()
514 {
515 	double p=double(uiMRG32k3a())/double(m1);
516 
517 	assert(p>=0.0);
518 	assert(p<1.0);
519 
520 	return p;
521 }*/
522 
intMRG32k3a(int k)523 int MRG32k3a::intMRG32k3a(int k)
524 {
525 	qint64 q=(qint64(uiMRG32k3a())*qint64(k))/m1;
526 	assert(q<qint64(k));
527 	int r=int(q);
528 
529 	return r;
530 }
531