00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "holidayparserdriverplan_p.h"
00034 #include "holidayscannerplan_p.h"
00035 #include "holidayparserplan.hpp"
00036
00037 #include <sstream>
00038
00039 #include <QFileInfo>
00040
00041 #include <kdebug.h>
00042
00043 #include "holiday_p.h"
00044
00045 #define LAST 99999
00046 #define ANY -99999
00047 #define BEFORE -1
00048 #define AFTER 1
00049
00050 using namespace KHolidays;
00051
00052 HolidayParserDriverPlan::HolidayParserDriverPlan( const QString &planFilePath )
00053 :HolidayParserDriver( planFilePath ),
00054 m_traceParsing( false ),
00055 m_traceScanning( false ),
00056 m_parseMetadataOnly( false )
00057 {
00058 QFile holidayFile( filePath() );
00059 if ( holidayFile.open( QIODevice::ReadOnly ) ) {
00060 m_scanData = holidayFile.readAll();
00061 holidayFile.close();
00062 }
00063 m_scanner = new HolidayScannerPlan();
00064 m_scanner->set_debug( m_traceScanning );
00065 m_parser = new HolidayParserPlan( *this );
00066 m_parser->set_debug_level( m_traceParsing );
00067 parseMetadata();
00068 }
00069
00070 HolidayParserDriverPlan::~HolidayParserDriverPlan()
00071 {
00072 delete m_parser;
00073 delete m_scanner;
00074 }
00075
00076
00077 void HolidayParserDriverPlan::error( const KHolidays::location &errorLocation, const QString &errorMessage )
00078 {
00079 Q_UNUSED( errorLocation );
00080
00081
00082 kDebug() << errorMessage;
00083 }
00084
00085 void HolidayParserDriverPlan::error( const QString &errorMessage )
00086 {
00087 kDebug() << errorMessage;
00088 }
00089
00090
00091 void HolidayParserDriverPlan::parse()
00092 {
00093
00094 foreach( QString calendar, m_fileCalendarTypes ) {
00095
00096
00097
00098 setParseCalendar( calendar );
00099 setParseStartEnd();
00100
00101
00102 for ( m_parseYear = m_parseStartYear; m_parseYear <= m_parseEndYear; ++m_parseYear ) {
00103
00104 m_parseCalendar->setDate( m_parseYearStart, m_parseYear, 1, 1 );
00105 m_parseYearEaster = easter( m_parseYear );
00106 m_parseYearPascha = pascha( m_parseYear );
00107
00108 std::istringstream iss2( std::string( m_scanData.data() ) );
00109 m_scanner->yyrestart( &iss2 );
00110
00111 m_parser->parse();
00112 }
00113
00114 }
00115 }
00116
00117 void HolidayParserDriverPlan::parseMetadata()
00118 {
00119 m_parseMetadataOnly = true;
00120 m_fileCountryCode.clear();
00121 m_fileLanguageCode.clear();
00122 m_fileName.clear();
00123 m_fileDescription.clear();
00124 m_fileCalendarTypes.clear();
00125 m_fileCalendarTypes.append( "gregorian" );
00126
00127
00128 setParseCalendar( "gregorian" );
00129 m_parseYear = QDate::currentDate().year();
00130 std::istringstream iss2( std::string( m_scanData.data() ) );
00131 m_scanner->yyrestart( &iss2 );
00132 m_parser->parse();
00133 m_resultList.clear();
00134
00135
00136
00137
00138 QFileInfo file( m_filePath );
00139 if ( file.exists() ) {
00140 QStringList metadata = file.fileName().split('_');
00141 if ( metadata[0] == "holiday" && metadata.count() > 2 ) {
00142 if ( m_fileCountryCode.isEmpty() ) {
00143 setFileCountryCode( metadata[1].toUpper() );
00144 }
00145 if ( m_fileLanguageCode.isEmpty() ) {
00146 QStringList language = metadata[2].split('-');
00147 m_fileLanguageCode = language[0];
00148 if ( language.count() > 1 ) {
00149 setFileLanguageCode( language[0].append( '_' ).append( language[1].toUpper() ) );
00150 } else {
00151 setFileLanguageCode( language[0] );
00152 }
00153 }
00154 if ( m_fileLanguageCode.isEmpty() && metadata.count() > 3 ) {
00155 m_fileName = metadata[3];
00156 }
00157 }
00158 }
00159
00160 m_parseMetadataOnly = false;
00161 }
00162
00163 QString HolidayParserDriverPlan::filePath()
00164 {
00165 return m_filePath;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 int HolidayParserDriverPlan::adjustedMonthNumber( int month )
00175 {
00176 if ( m_eventCalendarType != "hebrew" ||
00177 m_parseCalendar->calendarType() != "hebrew" ||
00178 !m_parseCalendar->isLeapYear( m_parseYear ) ||
00179 month < 6 ) {
00180 return month;
00181 }
00182
00183 if ( month == 13 ) {
00184 return 6;
00185 }
00186
00187 if ( month == 14 ) {
00188 return 7;
00189 }
00190
00191 return month + 1;
00192 }
00193
00194 bool HolidayParserDriverPlan::isLeapYear( int year )
00195 {
00196 return m_parseCalendar->isLeapYear( year );
00197 }
00198
00199 int HolidayParserDriverPlan::parseYear()
00200 {
00201 return m_parseYear;
00202 }
00203
00204 int HolidayParserDriverPlan::monthsInYear( int year )
00205 {
00206 QDate tempDate;
00207 m_parseCalendar->setDate( tempDate, year, 1, 1 );
00208 return m_parseCalendar->monthsInYear( tempDate );
00209 }
00210
00211 int HolidayParserDriverPlan::daysInMonth( int year, int month )
00212 {
00213 QDate tempDate;
00214 m_parseCalendar->setDate( tempDate, year, month, 1 );
00215 return m_parseCalendar->daysInMonth( tempDate );
00216 }
00217
00218 int HolidayParserDriverPlan::julianDay( int year, int month, int day )
00219 {
00220 QDate tempDate;
00221 m_parseCalendar->setDate( tempDate, year, month, day );
00222 return tempDate.toJulianDay();
00223 }
00224
00225 void HolidayParserDriverPlan::julianDayToDate( int jd, int *year, int *month, int *day )
00226 {
00227 QDate tempDate = QDate::fromJulianDay( jd );
00228
00229 if ( year ) {
00230 *year = m_parseCalendar->year( tempDate );
00231 }
00232 if ( month ) {
00233 *month = m_parseCalendar->month( tempDate );
00234 }
00235 if ( day ) {
00236 *day = m_parseCalendar->day( tempDate );
00237 }
00238 }
00239
00240 QDate HolidayParserDriverPlan::easter( int year )
00241 {
00242 if ( m_parseCalendar->calendarType() != "gregorian" ) {
00243 return QDate();
00244 }
00245
00246
00247
00248 int g = year % 19;
00249 int c = year / 100;
00250 int h = ( c - ( c / 4 ) - ( ( ( 8 * c ) + 13 ) / 25 ) + ( 19 * g ) + 15 ) % 30;
00251 int i = h - ( ( h / 28 ) * ( 1 - ( ( 29 / ( h + 1 ) ) * ( ( 21 - g ) / 11 ) ) ) );
00252 int j = ( year + ( year / 4 ) + i + 2 - c + ( c / 4 ) ) % 7;
00253 int l = i - j;
00254 int month = 3 + ( ( l + 40 ) / 44 );
00255 int day = l + 28 - ( 31 * ( month / 4 ) );
00256
00257 return QDate::fromJulianDay( julianDay( year, month, day ) );
00258 }
00259
00260
00261 QDate HolidayParserDriverPlan::pascha( int year )
00262 {
00263 if ( m_parseCalendar->calendarType() == "gregorian" ||
00264 m_parseCalendar->calendarType() == "julian" ) {
00265
00266
00267
00268 int g = year % 19;
00269 int i = ( ( 19 * g ) + 15 ) % 30;
00270 int j = ( year + ( year / 4 ) + i ) % 7;
00271 int l = i - j;
00272 int month = 3 + ( ( l + 40 ) / 44 );
00273 int day = l + 28 - ( 31 * ( month / 4 ) );
00274
00275 if ( m_parseCalendar->calendarType() == "julian" ) {
00276 return QDate::fromJulianDay( julianDay( year, month, day ) );
00277 }
00278
00279 if ( m_parseCalendar->calendarType() == "gregorian" ) {
00280 setParseCalendar( "julian" );
00281 int paschaJd = julianDay( year, month, day );
00282 setParseCalendar( "gregorian" );
00283 return QDate::fromJulianDay( paschaJd );
00284 }
00285 }
00286
00287 return QDate();
00288 }
00289
00290
00291
00292
00293
00294
00295
00296 int HolidayParserDriverPlan::julianDayFromEventName( const QString &eventName )
00297 {
00298 foreach ( const KHolidays::Holiday &thisHoliday, m_resultList ) {
00299 if ( thisHoliday.text() == eventName ) {
00300 return thisHoliday.date().toJulianDay();
00301 }
00302 }
00303 return -1;
00304 }
00305
00306
00307 int HolidayParserDriverPlan::julianDayFromEaster( void )
00308 {
00309 if ( m_eventCalendarType == "gregorian" ) {
00310 return m_parseYearEaster.toJulianDay();
00311 } else {
00312 error( "Can only use Easter in Gregorian event rule" );
00313 return -1;
00314 }
00315 }
00316
00317
00318 int HolidayParserDriverPlan::julianDayFromPascha( void )
00319 {
00320 if ( m_eventCalendarType == "gregorian" || m_eventCalendarType == "julian" ) {
00321 return m_parseYearPascha.toJulianDay();
00322 } else {
00323 error( "Can only use Easter in Gregorian or Julian event rule" );
00324 return -1;
00325 }
00326 }
00327
00328
00329 int HolidayParserDriverPlan::julianDayFromMonthDay( int month, int day ) {
00330 return julianDay( m_parseYear, month, day );
00331 }
00332
00333
00334 int HolidayParserDriverPlan::julianDayFromRelativeWeekday( int occurrence, int weekday, int jd )
00335 {
00336 if ( occurrence == ANY ) {
00337 occurrence = AFTER;
00338 }
00339
00340 int thisWeekday = m_parseCalendar->dayOfWeek( QDate::fromJulianDay( jd ) );
00341
00342
00343
00344 if ( occurrence > 0 ) {
00345 occurrence = occurrence - 1;
00346 } else if ( occurrence < 0 && weekday == thisWeekday ) {
00347 occurrence = occurrence + 1;
00348 }
00349
00350 if ( weekday < thisWeekday ) {
00351 occurrence = occurrence + 1;
00352 }
00353
00354 return jd + weekday - thisWeekday + ( occurrence * 7 );
00355 }
00356
00357
00358 int HolidayParserDriverPlan::julianDayFromWeekdayInMonth( int occurrence, int weekday, int month )
00359 {
00360 if ( occurrence == LAST ) {
00361 return julianDayFromRelativeWeekday( BEFORE, weekday, julianDay( m_parseYear, month, daysInMonth( m_parseYear, month ) ) );
00362 } else {
00363 return julianDayFromRelativeWeekday( occurrence, weekday, julianDay( m_parseYear, month, 1 ) );
00364 }
00365 }
00366
00367
00368
00369
00370
00371
00372 void HolidayParserDriverPlan::setFileCountryCode( const QString &countryCode )
00373 {
00374 m_fileCountryCode = countryCode;
00375 }
00376
00377 void HolidayParserDriverPlan::setFileLanguageCode( const QString &languageCode )
00378 {
00379 m_fileLanguageCode = languageCode;
00380 }
00381
00382 void HolidayParserDriverPlan::setFileName( const QString &name )
00383 {
00384 m_fileName = name;
00385 }
00386
00387 void HolidayParserDriverPlan::setFileDescription( const QString &description )
00388 {
00389 m_fileDescription = description;
00390 }
00391
00392 void HolidayParserDriverPlan::setEventName( const QString &eventName )
00393 {
00394 m_eventName = eventName;
00395 }
00396
00397 void HolidayParserDriverPlan::setEventColorName( int nameColor )
00398 {
00399 m_eventColorName = nameColor;
00400 }
00401
00402 void HolidayParserDriverPlan::setEventColorDay( int dayColor )
00403 {
00404 m_eventColorDay = dayColor;
00405 }
00406
00407 void HolidayParserDriverPlan::setEventCalendarType( const QString &calendarType )
00408 {
00409 m_eventCalendarType = calendarType;
00410 if ( m_parseMetadataOnly && !m_fileCalendarTypes.contains( calendarType ) ) {
00411 m_fileCalendarTypes.append( calendarType );
00412 }
00413 }
00414
00415 void HolidayParserDriverPlan::setEventDate( int eventYear, int eventMonth, int eventDay )
00416 {
00417 m_eventYear = eventYear;
00418 m_eventMonth = eventMonth;
00419 m_eventDay = eventDay;
00420 }
00421
00422 void HolidayParserDriverPlan::setEventDate( int jd )
00423 {
00424 julianDayToDate( jd, &m_eventYear, &m_eventMonth, &m_eventDay );
00425 }
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 void HolidayParserDriverPlan::setFromWeekdayInMonth( int occurrence, int weekday, int month, int offset, int duration )
00438 {
00439
00440 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00441 return;
00442 }
00443
00444 int startMonth, endMonth;
00445 if ( month == LAST ) {
00446 startMonth = monthsInYear( m_parseYear );
00447 endMonth = startMonth;
00448 } else if ( month == ANY ) {
00449 startMonth = 1;
00450 endMonth = monthsInYear( m_parseYear );
00451 } else {
00452 startMonth = month;
00453 endMonth = month;
00454 }
00455
00456
00457 for ( int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
00458
00459 if ( m_parseCalendar->isValid( m_parseYear, thisMonth, 1 ) ) {
00460 int startOccurrence, endOccurrence;
00461 if ( occurrence == ANY ) {
00462 startOccurrence = 1;
00463 endOccurrence = 5;
00464 } else {
00465 startOccurrence = occurrence;
00466 endOccurrence = occurrence;
00467 }
00468
00469 int jdMonthStart = julianDay( m_parseYear, thisMonth, 1 );
00470 int jdMonthEnd = julianDay( m_parseYear, thisMonth, daysInMonth( m_parseYear, thisMonth ) );
00471
00472
00473 for ( int thisOccurrence = startOccurrence; thisOccurrence <= endOccurrence; ++thisOccurrence ) {
00474 int thisJd = julianDayFromWeekdayInMonth( thisOccurrence, weekday, thisMonth );
00475 if ( thisJd >= jdMonthStart && thisJd <= jdMonthEnd ) {
00476 setEvent( thisJd + offset, 0, duration );
00477 }
00478 }
00479 }
00480
00481 }
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 void HolidayParserDriverPlan::setFromRelativeWeekday( int occurrence, int weekday, int offset, int duration )
00491 {
00492
00493 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00494 return;
00495 }
00496
00497 int thisYear;
00498 if ( m_eventYear == ANY ) {
00499 thisYear = m_parseYear;
00500 } else {
00501 thisYear = m_eventYear;
00502 }
00503
00504 int startMonth, endMonth;
00505 if ( m_eventMonth == LAST ) {
00506 startMonth = monthsInYear( thisYear );
00507 endMonth = startMonth;
00508 } else if ( m_eventMonth == ANY ) {
00509 startMonth = 1;
00510 endMonth = monthsInYear( thisYear );
00511 } else {
00512 startMonth = m_eventMonth;
00513 endMonth = m_eventMonth;
00514 }
00515
00516
00517 int thisMonth;
00518 for ( thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
00519
00520 int startDay, endDay;
00521 if ( m_eventDay == LAST ) {
00522 startDay = daysInMonth( thisYear, thisMonth );
00523 endDay = startDay;
00524 } else if ( m_eventDay == ANY ) {
00525 startDay = 1;
00526 endDay = daysInMonth( thisYear, thisMonth );
00527 } else {
00528 startDay = m_eventDay;
00529 endDay = m_eventDay;
00530 }
00531
00532
00533 for ( int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
00534 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
00535 int relativeJd = julianDayFromRelativeWeekday( occurrence, weekday, julianDay( thisYear, thisMonth, thisDay ) );
00536 setEvent( relativeJd + offset, 0, duration );
00537 }
00538 }
00539
00540 }
00541 }
00542
00543
00544 int HolidayParserDriverPlan::conditionalOffset( int year, int month, int day, int condition )
00545 {
00551 int offset = 0;
00552
00553 QDate tempDate;
00554 m_parseCalendar->setDate( tempDate, year, month, day );
00555 int weekday = m_parseCalendar->dayOfWeek( tempDate );
00556
00557 if ( condition & ( 1 << weekday ) ) {
00558
00559 int to = ( condition >> 8 );
00560 while ( !( to & ( 1 << ( ( weekday + offset ) % 7 ) ) ) && ( offset < 8 ) ) {
00561 ++offset;
00562 }
00563 }
00564
00565 if ( offset >= 8 ) {
00566 offset = 0;
00567 }
00568
00569 return offset;
00570 }
00571
00572
00573
00574
00575
00576
00577
00578 void HolidayParserDriverPlan::setFromDate( int offset, int condition, int duration )
00579 {
00580
00581 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00582 return;
00583 }
00584
00585 int thisYear;
00586 if ( m_eventYear == ANY ) {
00587 thisYear = m_parseYear;
00588 } else {
00589 thisYear = m_eventYear;
00590 }
00591
00592 int startMonth, endMonth;
00593 if ( m_eventMonth == LAST ) {
00594 startMonth = monthsInYear( thisYear );
00595 endMonth = startMonth;
00596 } else if ( m_eventMonth == ANY ) {
00597 startMonth = 1;
00598 endMonth = monthsInYear( thisYear );
00599 } else {
00600 startMonth = m_eventMonth;
00601 endMonth = m_eventMonth;
00602 }
00603
00604
00605 for ( int thisMonth = startMonth; thisMonth <= endMonth; ++thisMonth ) {
00606
00607 int startDay, endDay;
00608 if ( m_eventDay == LAST ) {
00609 startDay = daysInMonth( thisYear, thisMonth );
00610 endDay = startDay;
00611 } else if ( m_eventDay == ANY ) {
00612 startDay = 1;
00613 endDay = daysInMonth( thisYear, thisMonth );
00614 } else {
00615 startDay = m_eventDay;
00616 endDay = m_eventDay;
00617 }
00618
00619
00620 for ( int thisDay = startDay; thisDay <= endDay; ++thisDay ) {
00621
00622 if ( m_parseCalendar->isValid( thisYear, thisMonth, thisDay ) ) {
00623 setEvent( julianDay( thisYear, thisMonth, thisDay ) + offset,
00624 conditionalOffset( thisYear, thisMonth, thisDay, condition ), duration );
00625 }
00626
00627 }
00628
00629 }
00630 }
00631
00632
00633
00634
00635
00636
00637
00638 void HolidayParserDriverPlan::setFromEaster( int offset, int duration )
00639 {
00640
00641 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00642 return;
00643 }
00644
00645 if ( m_eventCalendarType == "gregorian" ) {
00646 setEvent( m_parseYearEaster.toJulianDay() + offset, 0, duration );
00647 } else {
00648 error( "Can only use Easter in Gregorian event rule" );
00649 }
00650 }
00651
00652
00653
00654
00655
00656
00657
00658 void HolidayParserDriverPlan::setFromPascha( int offset, int duration )
00659 {
00660
00661 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00662 return;
00663 }
00664
00665 if ( m_eventCalendarType == "gregorian" || m_eventCalendarType == "julian" ) {
00666 setEvent( m_parseYearPascha.toJulianDay(), offset, duration );
00667 } else {
00668 error( "Can only use Pascha in Julian and Gregorian event rule" );
00669 }
00670 }
00671
00672
00673 void HolidayParserDriverPlan::setEvent( int jd, int observeOffset, int duration )
00674 {
00675
00676 if ( m_parseMetadataOnly || m_eventCalendarType != m_parseCalendar->calendarType() ) {
00677 return;
00678 }
00679
00680
00681 int observeJd = jd + observeOffset;
00682
00683
00684 for ( int dd = 0; dd < duration; ++dd ) {
00685
00686
00687 if ( m_parseCalendar->isValid( QDate::fromJulianDay( observeJd + dd ) ) &&
00688 observeJd + dd >= m_requestStart.toJulianDay() &&
00689 observeJd + dd <= m_requestEnd.toJulianDay() ) {
00690
00691 KHolidays::Holiday holiday;
00692 holiday.d->mDate = QDate::fromJulianDay( observeJd + dd );
00693 holiday.d->mText = m_eventName;
00694 holiday.d->mShortText = m_eventName;
00695 if ( m_eventColorName == 2 || m_eventColorName == 9 ||
00696 m_eventColorDay == 2 || m_eventColorDay == 9 ) {
00697 holiday.d->mDayType = KHolidays::Holiday::NonWorkday;
00698 } else {
00699 holiday.d->mDayType = KHolidays::Holiday::Workday;
00700 }
00701 m_resultList.append( holiday );
00702
00703 }
00704
00705 }
00706 }