00001
00005
00006 #include <cassert>
00007 #include <iostream>
00008 #include <sstream>
00009 #include <fstream>
00010 #include <string>
00011
00012 #include <boost/program_options.hpp>
00013 #include <boost/tokenizer.hpp>
00014 #include <boost/regex.hpp>
00015 #include <boost/swap.hpp>
00016 #include <boost/algorithm/string/case_conv.hpp>
00017
00018 #include <stdair/basic/BasLogParams.hpp>
00019 #include <stdair/basic/BasDBParams.hpp>
00020 #include <stdair/service/Logger.hpp>
00021
00022 #include <sevmgr/SEVMGR_Service.hpp>
00023 #include <sevmgr/config/sevmgr-paths.hpp>
00024
00025 #include <sevmgr/ui/cmdline/SReadline.hpp>
00026
00027
00031 const std::string K_SEVMGR_DEFAULT_LOG_FILENAME ("sevmgr.log");
00032
00036 const int K_SEVMGR_EARLY_RETURN_STATUS = 99;
00037
00042 typedef std::vector<std::string> TokenList_T;
00043
00047 struct Command_T {
00048 typedef enum {
00049 NOP = 0,
00050 QUIT,
00051 HELP,
00052 LIST,
00053 DISPLAY,
00054 SELECT,
00055 NEXT,
00056 RUN,
00057 JSON_LIST,
00058 JSON_DISPLAY,
00059 LAST_VALUE
00060 } Type_T;
00061 };
00062
00063
00064
00065 template<class T> std::ostream& operator<< (std::ostream& os,
00066 const std::vector<T>& v) {
00067 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
00068 return os;
00069 }
00070
00074 int readConfiguration (int argc, char* argv[], std::string& ioLogFilename) {
00075
00076 boost::program_options::options_description generic ("Generic options");
00077 generic.add_options()
00078 ("prefix", "print installation prefix")
00079 ("version,v", "print version string")
00080 ("help,h", "produce help message");
00081
00082
00083
00084
00085 boost::program_options::options_description config ("Configuration");
00086 config.add_options()
00087 ("log,l",
00088 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_SEVMGR_DEFAULT_LOG_FILENAME),
00089 "Filename for the logs")
00090 ;
00091
00092
00093
00094 boost::program_options::options_description hidden ("Hidden options");
00095 hidden.add_options()
00096 ("copyright",
00097 boost::program_options::value< std::vector<std::string> >(),
00098 "Show the copyright (license)");
00099
00100 boost::program_options::options_description cmdline_options;
00101 cmdline_options.add(generic).add(config).add(hidden);
00102
00103 boost::program_options::options_description config_file_options;
00104 config_file_options.add(config).add(hidden);
00105 boost::program_options::options_description visible ("Allowed options");
00106 visible.add(generic).add(config);
00107
00108 boost::program_options::positional_options_description p;
00109 p.add ("copyright", -1);
00110
00111 boost::program_options::variables_map vm;
00112 boost::program_options::
00113 store (boost::program_options::command_line_parser (argc, argv).
00114 options (cmdline_options).positional(p).run(), vm);
00115
00116 std::ifstream ifs ("sevmgr.cfg");
00117 boost::program_options::store (parse_config_file (ifs, config_file_options),
00118 vm);
00119 boost::program_options::notify (vm);
00120
00121 if (vm.count ("help")) {
00122 std::cout << visible << std::endl;
00123 return K_SEVMGR_EARLY_RETURN_STATUS;
00124 }
00125
00126 if (vm.count ("version")) {
00127 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
00128 return K_SEVMGR_EARLY_RETURN_STATUS;
00129 }
00130
00131 if (vm.count ("prefix")) {
00132 std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
00133 return K_SEVMGR_EARLY_RETURN_STATUS;
00134 }
00135
00136 if (vm.count ("log")) {
00137 ioLogFilename = vm["log"].as< std::string >();
00138 std::cout << "Log filename is: " << ioLogFilename << std::endl;
00139 }
00140
00141 return 0;
00142 }
00143
00144
00145 void initReadline (swift::SReadline& ioInputReader) {
00146
00147
00148 std::vector<std::string> Completers;
00149
00150
00151
00152
00153 Completers.push_back ("help");
00154 Completers.push_back ("list %airline_code %flight_number");
00155 Completers.push_back ("select %airline_code %flight_number %flight_date");
00156 Completers.push_back ("display");
00157 Completers.push_back ("next");
00158 Completers.push_back ("run");
00159 Completers.push_back ("quit");
00160
00161
00162
00163
00164 ioInputReader.RegisterCompletions (Completers);
00165 }
00166
00167
00168 Command_T::Type_T extractCommand (TokenList_T& ioTokenList) {
00169 Command_T::Type_T oCommandType = Command_T::LAST_VALUE;
00170
00171
00172 if (ioTokenList.empty() == false) {
00173 TokenList_T::iterator itTok = ioTokenList.begin();
00174 std::string lCommand (*itTok);
00175 boost::algorithm::to_lower (lCommand);
00176
00177 if (lCommand == "help") {
00178 oCommandType = Command_T::HELP;
00179
00180 } else if (lCommand == "list") {
00181 oCommandType = Command_T::LIST;
00182
00183 } else if (lCommand == "display") {
00184 oCommandType = Command_T::DISPLAY;
00185
00186 } else if (lCommand == "select") {
00187 oCommandType = Command_T::SELECT;
00188
00189 } else if (lCommand == "next") {
00190 oCommandType = Command_T::NEXT;
00191
00192 } else if (lCommand == "run") {
00193 oCommandType = Command_T::RUN;
00194
00195 } else if (lCommand == "json_list") {
00196 oCommandType = Command_T::JSON_LIST;
00197
00198 } else if (lCommand == "json_display") {
00199 oCommandType = Command_T::JSON_DISPLAY;
00200
00201 } else if (lCommand == "quit") {
00202 oCommandType = Command_T::QUIT;
00203 }
00204
00205
00206
00207 ioTokenList.erase (itTok);
00208
00209 } else {
00210 oCommandType = Command_T::NOP;
00211 }
00212
00213 return oCommandType;
00214 }
00215
00216
00217 void parseFlightKey (const TokenList_T& iTokenList,
00218 stdair::AirlineCode_T& ioAirlineCode,
00219 stdair::FlightNumber_T& ioFlightNumber) {
00220
00221 if (iTokenList.empty() == false) {
00222
00223
00224 TokenList_T::const_iterator itTok = iTokenList.begin();
00225 if (itTok->empty() == false) {
00226 ioAirlineCode = *itTok;
00227 boost::algorithm::to_upper (ioAirlineCode);
00228 }
00229
00230
00231 ++itTok;
00232 if (itTok != iTokenList.end()) {
00233
00234 if (itTok->empty() == false) {
00235 try {
00236
00237 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
00238
00239 } catch (boost::bad_lexical_cast& eCast) {
00240 std::cerr << "The flight number ('" << *itTok
00241 << "') cannot be understood. "
00242 << "The default value (all) is kept."
00243 << std::endl;
00244 return;
00245 }
00246 }
00247
00248 } else {
00249 return;
00250 }
00251 }
00252 }
00253
00254
00255 void parseFlightDateKey (const TokenList_T& iTokenList,
00256 stdair::AirlineCode_T& ioAirlineCode,
00257 stdair::FlightNumber_T& ioFlightNumber,
00258 stdair::Date_T& ioDepartureDate) {
00259
00260 const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
00261 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
00262
00263 unsigned short ioDepartureDateYear = ioDepartureDate.year();
00264 unsigned short ioDepartureDateMonth = ioDepartureDate.month();
00265 std::string ioDepartureDateMonthStr = kMonthStr[ioDepartureDateMonth-1];
00266 unsigned short ioDepartureDateDay = ioDepartureDate.day();
00267
00268
00269 if (iTokenList.empty() == false) {
00270
00271
00272 TokenList_T::const_iterator itTok = iTokenList.begin();
00273 if (itTok->empty() == false) {
00274 ioAirlineCode = *itTok;
00275 boost::algorithm::to_upper (ioAirlineCode);
00276 }
00277
00278
00279 ++itTok;
00280 if (itTok != iTokenList.end()) {
00281
00282 if (itTok->empty() == false) {
00283 try {
00284
00285 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
00286
00287 } catch (boost::bad_lexical_cast& eCast) {
00288 std::cerr << "The flight number ('" << *itTok
00289 << "') cannot be understood. "
00290 << "The default value (all) is kept."
00291 << std::endl;
00292 return;
00293 }
00294 }
00295
00296 } else {
00297 return;
00298 }
00299
00300
00301 ++itTok;
00302 if (itTok != iTokenList.end()) {
00303
00304 if (itTok->empty() == false) {
00305 try {
00306
00307 ioDepartureDateYear = boost::lexical_cast<unsigned short> (*itTok);
00308 if (ioDepartureDateYear < 100) {
00309 ioDepartureDateYear += 2000;
00310 }
00311
00312 } catch (boost::bad_lexical_cast& eCast) {
00313 std::cerr << "The year of the flight departure date ('" << *itTok
00314 << "') cannot be understood. The default value ("
00315 << ioDepartureDateYear << ") is kept. " << std::endl;
00316 return;
00317 }
00318 }
00319
00320 } else {
00321 return;
00322 }
00323
00324
00325 ++itTok;
00326 if (itTok != iTokenList.end()) {
00327
00328 if (itTok->empty() == false) {
00329 try {
00330
00331 const boost::regex lMonthRegex ("^(\\d{1,2})$");
00332 const bool isMonthANumber = regex_match (*itTok, lMonthRegex);
00333
00334 if (isMonthANumber == true) {
00335 const unsigned short lMonth =
00336 boost::lexical_cast<unsigned short> (*itTok);
00337 if (lMonth > 12) {
00338 throw boost::bad_lexical_cast();
00339 }
00340 ioDepartureDateMonthStr = kMonthStr[lMonth-1];
00341
00342 } else {
00343 const std::string lMonthStr (*itTok);
00344 if (lMonthStr.size() < 3) {
00345 throw boost::bad_lexical_cast();
00346 }
00347 std::string lMonthStr1 (lMonthStr.substr (0, 1));
00348 boost::algorithm::to_upper (lMonthStr1);
00349 std::string lMonthStr23 (lMonthStr.substr (1, 2));
00350 boost::algorithm::to_lower (lMonthStr23);
00351 ioDepartureDateMonthStr = lMonthStr1 + lMonthStr23;
00352 }
00353
00354 } catch (boost::bad_lexical_cast& eCast) {
00355 std::cerr << "The month of the flight departure date ('" << *itTok
00356 << "') cannot be understood. The default value ("
00357 << ioDepartureDateMonthStr << ") is kept. " << std::endl;
00358 return;
00359 }
00360 }
00361
00362 } else {
00363 return;
00364 }
00365
00366
00367 ++itTok;
00368 if (itTok != iTokenList.end()) {
00369
00370 if (itTok->empty() == false) {
00371 try {
00372
00373 ioDepartureDateDay = boost::lexical_cast<unsigned short> (*itTok);
00374
00375 } catch (boost::bad_lexical_cast& eCast) {
00376 std::cerr << "The day of the flight departure date ('" << *itTok
00377 << "') cannot be understood. The default value ("
00378 << ioDepartureDateDay << ") is kept. " << std::endl;
00379 return;
00380 }
00381 }
00382
00383 } else {
00384 return;
00385 }
00386
00387
00388 std::ostringstream lDepartureDateStr;
00389 lDepartureDateStr << ioDepartureDateYear << "-" << ioDepartureDateMonthStr
00390 << "-" << ioDepartureDateDay;
00391
00392 try {
00393
00394 ioDepartureDate =
00395 boost::gregorian::from_simple_string (lDepartureDateStr.str());
00396
00397 } catch (boost::gregorian::bad_month& eCast) {
00398 std::cerr << "The flight departure date ('" << lDepartureDateStr.str()
00399 << "') cannot be understood. The default value ("
00400 << ioDepartureDate << ") is kept. " << std::endl;
00401 return;
00402 }
00403
00404 }
00405 }
00406
00407
00408 void parseBookingClassKey (const TokenList_T& iTokenList,
00409 stdair::ClassCode_T& ioBookingClass,
00410 stdair::PartySize_T& ioPartySize,
00411 stdair::AirportCode_T& ioOrigin,
00412 stdair::AirportCode_T& ioDestination) {
00413
00414 if (iTokenList.empty() == false) {
00415
00416
00417 TokenList_T::const_iterator itTok = iTokenList.begin();
00418 if (itTok->empty() == false) {
00419 ioBookingClass = *itTok;
00420 boost::algorithm::to_upper (ioBookingClass);
00421 }
00422
00423
00424 ++itTok;
00425 if (itTok != iTokenList.end()) {
00426
00427 if (itTok->empty() == false) {
00428 try {
00429
00430 ioPartySize = boost::lexical_cast<stdair::PartySize_T> (*itTok);
00431
00432 } catch (boost::bad_lexical_cast& eCast) {
00433 std::cerr << "The party size ('" << *itTok
00434 << "') cannot be understood. The default value ("
00435 << ioPartySize << ") is kept." << std::endl;
00436 return;
00437 }
00438 }
00439
00440 } else {
00441 return;
00442 }
00443
00444
00445 ++itTok;
00446 if (itTok != iTokenList.end()) {
00447
00448 if (itTok->empty() == false) {
00449 ioOrigin = *itTok;
00450 boost::algorithm::to_upper (ioOrigin);
00451 }
00452
00453 } else {
00454 return;
00455 }
00456
00457
00458 ++itTok;
00459 if (itTok != iTokenList.end()) {
00460
00461 if (itTok->empty() == false) {
00462 ioDestination = *itTok;
00463 boost::algorithm::to_upper (ioDestination);
00464 }
00465
00466 } else {
00467 return;
00468 }
00469 }
00470 }
00471
00472
00473 std::string toString (const TokenList_T& iTokenList) {
00474 std::ostringstream oStr;
00475
00476
00477 unsigned short idx = 0;
00478 for (TokenList_T::const_iterator itTok = iTokenList.begin();
00479 itTok != iTokenList.end(); ++itTok, ++idx) {
00480 if (idx != 0) {
00481 oStr << " ";
00482 }
00483 oStr << *itTok;
00484 }
00485
00486 return oStr.str();
00487 }
00488
00489
00490 TokenList_T extractTokenList (const TokenList_T& iTokenList,
00491 const std::string& iRegularExpression) {
00492 TokenList_T oTokenList;
00493
00494
00495
00496 const std::string lFullLine = toString (iTokenList);
00497
00498
00499 boost::regex expression (iRegularExpression);
00500
00501 std::string::const_iterator start = lFullLine.begin();
00502 std::string::const_iterator end = lFullLine.end();
00503
00504 boost::match_results<std::string::const_iterator> what;
00505 boost::match_flag_type flags = boost::match_default | boost::format_sed;
00506 regex_search (start, end, what, expression, flags);
00507
00508
00509
00510 const unsigned short lMatchSetSize = what.size();
00511 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
00512 const std::string lMatchedString (std::string (what[matchIdx].first,
00513 what[matchIdx].second));
00514
00515 oTokenList.push_back (lMatchedString);
00516
00517 }
00518
00519
00520
00521
00522 return oTokenList;
00523 }
00524
00525
00526 TokenList_T extractTokenListForFlight (const TokenList_T& iTokenList) {
00533 const std::string lRegEx ("^([[:alpha:]]{2,3})?"
00534 "[[:space:]]*([[:digit:]]{1,4})?$");
00535
00536
00537 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
00538 return oTokenList;
00539 }
00540
00541
00542 TokenList_T extractTokenListForFlightDate (const TokenList_T& iTokenList) {
00553 const std::string lRegEx("^([[:alpha:]]{2,3})?"
00554 "[[:space:]]*([[:digit:]]{1,4})?"
00555 "[/ ]*"
00556 "([[:digit:]]{2,4})?[/-]?[[:space:]]*"
00557 "([[:alpha:]]{3}|[[:digit:]]{1,2})?[/-]?[[:space:]]*"
00558 "([[:digit:]]{1,2})?$");
00559
00560
00561 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
00562 return oTokenList;
00563 }
00564
00565
00566 TokenList_T extractTokenListForClass (const TokenList_T& iTokenList) {
00575 const std::string lRegEx ("^([[:alpha:]])?"
00576 "[[:space:]]*([[:digit:]]{1,3})?"
00577 "[[:space:]]*([[:alpha:]]{3})?"
00578 "[[:space:]]*([[:alpha:]]{3})?$");
00579
00580
00581 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
00582 return oTokenList;
00583 }
00584
00585
00586
00587 int main (int argc, char* argv[]) {
00588
00589
00590 const unsigned int lHistorySize (100);
00591 const std::string lHistoryFilename ("sevmgr.hist");
00592 const std::string lHistoryBackupFilename ("sevmgr.hist.bak");
00593
00594
00595 stdair::AirlineCode_T lLastInteractiveAirlineCode;
00596 stdair::FlightNumber_T lLastInteractiveFlightNumber;
00597 stdair::Date_T lLastInteractiveDate;
00598 stdair::AirlineCode_T lInteractiveAirlineCode;
00599 stdair::FlightNumber_T lInteractiveFlightNumber;
00600 stdair::Date_T lInteractiveDate;
00601 stdair::AirportCode_T lInteractiveOrigin;
00602 stdair::AirportCode_T lInteractiveDestination;
00603 stdair::ClassCode_T lInteractiveBookingClass;
00604
00605
00606 std::string lSegmentDateKey;
00607
00608
00609 stdair::Filename_T lLogFilename;
00610
00611
00612 const int lOptionParserStatus = readConfiguration (argc, argv, lLogFilename);
00613
00614 if (lOptionParserStatus == K_SEVMGR_EARLY_RETURN_STATUS) {
00615 return 0;
00616 }
00617
00618
00619 std::ofstream logOutputFile;
00620
00621 logOutputFile.open (lLogFilename.c_str());
00622 logOutputFile.clear();
00623
00624
00625 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
00626 SEVMGR::SEVMGR_Service sevmgrService (lLogParams);
00627
00628
00629 STDAIR_LOG_DEBUG ("Welcome to SEvMgr");
00630
00631
00632 sevmgrService.buildSampleBom();
00633
00634
00635 lInteractiveAirlineCode = "BA";
00636 lInteractiveFlightNumber = 9;
00637 lInteractiveDate = stdair::Date_T (2011, 06, 10);
00638 lInteractiveBookingClass = "Q";
00639 lInteractiveOrigin = "LHR";
00640 lInteractiveDestination = "SYD";
00641
00642
00643 lLastInteractiveAirlineCode = lInteractiveAirlineCode;
00644 lLastInteractiveFlightNumber = lInteractiveFlightNumber;
00645 lLastInteractiveDate = lInteractiveDate;
00646
00647
00648 STDAIR_LOG_DEBUG ("====================================================");
00649 STDAIR_LOG_DEBUG ("= Beginning of the interactive session =");
00650 STDAIR_LOG_DEBUG ("====================================================");
00651 STDAIR_LOG_DEBUG ("Last saved state: " << lLastInteractiveAirlineCode
00652 << lLastInteractiveFlightNumber << " / "
00653 << lLastInteractiveDate);
00654
00655
00656 swift::SReadline lReader (lHistoryFilename, lHistorySize);
00657 initReadline (lReader);
00658
00659
00660 std::string lUserInput;
00661 bool EndOfInput (false);
00662 Command_T::Type_T lCommandType (Command_T::NOP);
00663
00664 while (lCommandType != Command_T::QUIT && EndOfInput == false) {
00665
00666 std::ostringstream oPromptStr;
00667 oPromptStr << "sevmgr "
00668 << lInteractiveAirlineCode << lInteractiveFlightNumber
00669 << " / " << lInteractiveDate
00670 << "> ";
00671
00672 TokenList_T lTokenListByReadline;
00673 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
00674 EndOfInput);
00675
00676
00677 lReader.SaveHistory (lHistoryBackupFilename);
00678
00679
00680 if (EndOfInput) {
00681 std::cout << std::endl;
00682 break;
00683 }
00684
00685
00686 lCommandType = extractCommand (lTokenListByReadline);
00687
00688 switch (lCommandType) {
00689
00690
00691 case Command_T::HELP: {
00692 std::cout << std::endl;
00693 std::cout << "Commands: " << std::endl;
00694 std::cout << " help" << "\t\t" << "Display this help" << std::endl;
00695 std::cout << " quit" << "\t\t" << "Quit the application" << std::endl;
00696 std::cout << " list" << "\t\t" << "List events" << std::endl;
00697 std::cout << " select" << "\t\t"
00698 << "Select an event to become the current one" << std::endl;
00699 std::cout << " display" << "\t"
00700 << "Display the current event" << std::endl;
00701 std::cout << " next" << "\t\t"
00702 << "Play the current event and pop the next one from the queue"
00703 << std::endl;
00704 std::cout << " run" << "\t\t"
00705 << "Play all the events until the next break-point, if any"
00706 << std::endl;
00707 std::cout << " \nDebug Commands" << std::endl;
00708 std::cout << " json_list" << "\t"
00709 << "List events in a JSON format"
00710 << std::endl;
00711 std::cout << " json_display" << "\t"
00712 << "Display the current event in a JSON format"
00713 << std::endl;
00714 std::cout << std::endl;
00715 break;
00716 }
00717
00718
00719 case Command_T::QUIT: {
00720 break;
00721 }
00722
00723
00724 case Command_T::LIST: {
00725
00726 std::cout << "List" << std::endl;
00727
00728
00729 break;
00730 }
00731
00732
00733 case Command_T::SELECT: {
00734
00735 std::cout << "Select" << std::endl;
00736
00737
00738 break;
00739 }
00740
00741
00742 case Command_T::DISPLAY: {
00743
00744 std::cout << "Display" << std::endl;
00745
00746
00747 break;
00748 }
00749
00750
00751 case Command_T::NEXT: {
00752
00753 std::cout << "Next" << std::endl;
00754
00755
00756 break;
00757 }
00758
00759
00760 case Command_T::RUN: {
00761
00762 std::cout << "Run" << std::endl;
00763
00764
00765 break;
00766 }
00767
00768
00769
00770 case Command_T::JSON_LIST: {
00771
00772 std::cout << "JSON List" << std::endl;
00773
00774
00775 break;
00776 }
00777
00778
00779
00780 case Command_T::JSON_DISPLAY: {
00781
00782 std::cout << "JSON Display" << std::endl;
00783
00784
00785 break;
00786 }
00787
00788
00789 case Command_T::NOP: {
00790 break;
00791 }
00792
00793 case Command_T::LAST_VALUE:
00794 default: {
00795
00796 std::ostringstream oStr;
00797 oStr << "That command is not yet understood: '" << lUserInput
00798 << "' => " << lTokenListByReadline;
00799 STDAIR_LOG_DEBUG (oStr.str());
00800 std::cout << oStr.str() << std::endl;
00801 }
00802 }
00803 }
00804
00805
00806 STDAIR_LOG_DEBUG ("End of the session. Exiting.");
00807 std::cout << "End of the session. Exiting." << std::endl;
00808
00809
00810 logOutputFile.close();
00811
00812
00813
00814
00815
00816
00817
00818
00819 return 0;
00820 }