1 /*
2  * Copyright (C) 2020 Georg Zotti
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
17  */
18 
19 #include "StelTranslator.hpp"
20 #include "RomanCalendar.hpp"
21 #include "StelUtils.hpp"
22 #include "StelApp.hpp"
23 #include "StelCore.hpp"
24 
RomanCalendar(double jd)25 RomanCalendar::RomanCalendar(double jd): JulianCalendar(jd)
26 {
27 	RomanCalendar::retranslate();
28 }
29 
30 QMap<int, QString> RomanCalendar::monthGen;
31 
retranslate()32 void RomanCalendar::retranslate()
33 {
34 	// fill the name lists with translated month names
35 	monthGen={
36 		{ 1, qc_("Ianuarii"   , "Roman month name (genitive)")},
37 		{ 2, qc_("Februarii"  , "Roman month name (genitive)")},
38 		{ 3, qc_("Martii"     , "Roman month name (genitive)")},
39 		{ 4, qc_("Aprilis"    , "Roman month name (genitive)")},
40 		{ 5, qc_("Maii"       , "Roman month name (genitive)")},
41 		{ 6, qc_("Iunii"      , "Roman month name (genitive)")},
42 		{ 7, qc_("Iulii"      , "Roman month name (genitive)")},
43 		{ 8, qc_("Augusti"    , "Roman month name (genitive)")},
44 		{ 9, qc_("Septembris" , "Roman month name (genitive)")},
45 		{10, qc_("Octobris"   , "Roman month name (genitive)")},
46 		{11, qc_("Novembris"  , "Roman month name (genitive)")},
47 		{12, qc_("Decembris"  , "Roman month name (genitive)")}};
48 }
49 
50 // Set a calendar date from the Julian day number
setJD(double JD)51 void RomanCalendar::setJD(double JD)
52 {
53 	this->JD=JD;
54 
55 	int rd=fixedFromJD(JD, true);
56 	parts=romanFromFixed(rd);
57 
58 	emit partsChanged(parts);
59 }
60 
61 // get a stringlist of calendar date elements sorted from the largest to the smallest.
62 // AUCYear, Month, MonthName(genitive), event, DayName
getDateStrings() const63 QStringList RomanCalendar::getDateStrings() const
64 {
65 	QStringList events={qc_("Kalendae", "Roman calendar term"),
66 			    qc_("Nones",    "Roman calendar term"),
67 			    qc_("Ides",     "Roman calendar term")};
68 	QStringList eventsShort={qc_("Kal.", "Roman calendar term"),
69 				 qc_("Non.", "Roman calendar term"),
70 				 qc_("Id." , "Roman calendar term")};
71 
72 	QStringList list;
73 	list << QString::number(aucYearFromJulian(parts.at(0))); // 0:AUC year
74 	list << QString::number(parts.at(1)); // 1:Month (numeric)
75 	list << monthGen.value(parts.at(1));  // 2:Month (genitive form)
76 	// 3:event:
77 	if (parts.at(3)==1)
78 		list << events.at(parts.at(2)-1);
79 	else
80 		list << eventsShort.at(parts.at(2)-1);
81 
82 	// 4:day
83 	if (parts.at(3)==1)
84 		list << "";
85 	else if (parts.at(3)==2)
86 		list << qc_("pridie", "Roman calendar term");
87 	else {
88 		const QString bisTerm=QString(" %1").arg(parts.at(4)? qc_("bis", "Roman calendar term") : "");
89 		list << QString("%1%2 %3").arg(qc_("ante diem", "Roman calendar term"), bisTerm, romanNumber(parts.at(3)));
90 	}
91 
92 	return list;
93 }
94 
95 // get a formatted complete string for a date
getFormattedDateString() const96 QString RomanCalendar::getFormattedDateString() const
97 {
98 	QStringList str=getDateStrings();
99 
100 	QString day;
101 	return QString("%1 %2 %3 %4 %5")
102 			.arg(str.at(4))
103 			.arg(str.at(3))
104 			.arg(str.at(2))
105 			.arg(str.at(0))
106 			.arg(qc_("A.U.C.", "ab urbe condita"));// year AUC
107 }
108 
109 // set date from a vector of calendar date elements sorted from the largest to the smallest.
110 // JulianYear-Month[1...12]-event-count-leap
111 // Time is not changed!
setDate(QVector<int> parts)112 void RomanCalendar::setDate(QVector<int> parts)
113 {
114 	this->parts=parts;
115 
116 	double rd=fixedFromRoman(parts);
117 	// restore time from JD!
118 	double frac=StelUtils::fmodpos(JD+0.5+StelApp::getInstance().getCore()->getUTCOffset(JD)/24., 1.);
119 	JD=jdFromFixed(rd+frac, true);
120 
121 	emit jdChanged(JD);
122 }
123 
124 // returns 13 or 15, the day of "idae"
idesOfMonth(int month)125 int RomanCalendar::idesOfMonth(int month)
126 {
127 	static const QVector<int> cand={JulianCalendar::march, JulianCalendar::may, JulianCalendar::july, JulianCalendar::october};
128 	if (cand.contains(month))
129 		return 15;
130 	else
131 		return 13;
132 }
133 
134 // returns the day of "nones"
nonesOfMonth(int month)135 int RomanCalendar::nonesOfMonth(int month)
136 {
137 	return idesOfMonth(month)-8;
138 }
139 
140 // Convert between AUC and Julian year numbers
julianYearFromAUC(int aucYear)141 int RomanCalendar::julianYearFromAUC(int aucYear)
142 {
143 	if ((1<=aucYear) && (aucYear<=-yearRomeFounded))
144 		return aucYear + yearRomeFounded - 1;
145 	else
146 		return aucYear + yearRomeFounded;
147 }
148 
fixedFromRoman(QVector<int> roman)149 int RomanCalendar::fixedFromRoman(QVector<int> roman)
150 {
151 	const int year=roman.at(0);
152 	const int month=roman.at(1);
153 	const events event=static_cast<events>(roman.at(2));
154 	const int count=roman.at(3);
155 	const int leap=roman.at(4);
156 
157 	int rd = 0; // Suppress warning
158 	switch (event)
159 	{
160 	case kalends:
161 		rd=fixedFromJulian({year, month, 1});
162 		break;
163 	case nones:
164 		rd=fixedFromJulian({year, month, nonesOfMonth(month)});
165 		break;
166 	case ides:
167 		rd=fixedFromJulian({year, month, idesOfMonth(month)});
168 		break;
169 	}
170 	rd-=count;
171 	if (!(JulianCalendar::isLeap(year) && (month==JulianCalendar::march) && (event==kalends) && (16>=count) && (count>=6)))
172 		rd+=1;
173 	rd+=leap;
174 	return rd;
175 }
176 
romanFromFixed(int rd)177 QVector<int> RomanCalendar::romanFromFixed(int rd)
178 {
179 	const QVector<int>jdate=julianFromFixed(rd);
180 	const int year=jdate.at(0);
181 	const int month=jdate.at(1);
182 	const int day=jdate.at(2);
183 	const int monthP=StelUtils::amod(month+1, 12);
184 	const int yearP=(monthP!=1 ? year : (year!=-1 ? year+1 : 1 ));
185 	const int kalends1=fixedFromRoman({yearP, monthP, kalends, 1, false});
186 
187 	if (day==1)
188 		return {year, month, kalends, 1, false};
189 	else if (day<=nonesOfMonth(month))
190 		return {year, month, nones, nonesOfMonth(month)-day+1, false};
191 	else if (day<=idesOfMonth(month))
192 		return {year, month, ides, idesOfMonth(month)-day+1, false};
193 	else if (month!=february || !isLeap(year))
194 		return {yearP, monthP, kalends, kalends1-rd+1, false};
195 	else if (day<25)
196 		return {year, march, kalends, 30-day, false};
197 	else return {year, march, kalends, 31-day, day==25};
198 }
199 
200 // Convert between AUC and Julian year numbers
aucYearFromJulian(int julianYear)201 int RomanCalendar::aucYearFromJulian(int julianYear)
202 {
203 	if ((yearRomeFounded<=julianYear) && (julianYear<=-1))
204 		return julianYear - yearRomeFounded + 1;
205 	else
206 		return julianYear - yearRomeFounded;
207 }
208 
209 // return a Roman number (1...19)
romanNumber(const int num)210 QString RomanCalendar::romanNumber(const int num)
211 {
212 	QStringList roman={"",   "I",  "II",  "III",  "IV",  "V",  "VI",  "VII",  "VIII",  "IX",
213 			   "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX"};
214 	if (num>19) return QString::number(num); // "bogus";
215 	if (num<1) return QString::number(num);  // "bogus";
216 	return roman.at(num);
217 }
218