$treeview $search $mathjax
00001 00005 // STL 00006 #include <cassert> 00007 #include <iostream> 00008 #include <sstream> 00009 #include <fstream> 00010 #include <string> 00011 // Boost (Extended STL) 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 // StdAir 00018 #include <stdair/basic/BasLogParams.hpp> 00019 #include <stdair/basic/BasDBParams.hpp> 00020 #include <stdair/service/Logger.hpp> 00021 #include <stdair/stdair_json.hpp> 00022 // GNU Readline Wrapper 00023 #include <stdair/ui/cmdline/SReadline.hpp> 00024 // AirInv 00025 #include <airinv/AIRINV_Master_Service.hpp> 00026 #include <airinv/config/airinv-paths.hpp> 00027 00028 // //////// Constants ////// 00032 const std::string K_AIRINV_DEFAULT_LOG_FILENAME ("airinv.log"); 00033 00037 const std::string K_AIRINV_DEFAULT_INVENTORY_FILENAME (STDAIR_SAMPLE_DIR 00038 "/invdump01.csv"); 00042 const std::string K_AIRINV_DEFAULT_SCHEDULE_FILENAME (STDAIR_SAMPLE_DIR 00043 "/schedule01.csv"); 00047 const std::string K_AIRINV_DEFAULT_OND_FILENAME (STDAIR_SAMPLE_DIR 00048 "/ond01.csv"); 00052 const std::string K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME (STDAIR_SAMPLE_DIR 00053 "/frat5.csv"); 00057 const std::string K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME (STDAIR_SAMPLE_DIR 00058 "/ffDisutility.csv"); 00062 const std::string K_AIRINV_DEFAULT_YIELD_FILENAME (STDAIR_SAMPLE_DIR 00063 "/yieldstore01.csv"); 00064 00069 const bool K_AIRINV_DEFAULT_BUILT_IN_INPUT = false; 00070 00075 const bool K_AIRINV_DEFAULT_FOR_SCHEDULE = false; 00076 00080 const int K_AIRINV_EARLY_RETURN_STATUS = 99; 00081 00086 typedef std::vector<std::string> TokenList_T; 00087 00091 struct Command_T { 00092 typedef enum { 00093 NOP = 0, 00094 QUIT, 00095 HELP, 00096 LIST, 00097 DISPLAY, 00098 SELECT, 00099 SELL, 00100 JSON_LIST, 00101 JSON_DISPLAY, 00102 LAST_VALUE 00103 } Type_T; 00104 }; 00105 00106 // ///////// Parsing of Options & Configuration ///////// 00107 // A helper function to simplify the main part. 00108 template<class T> std::ostream& operator<< (std::ostream& os, 00109 const std::vector<T>& v) { 00110 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " ")); 00111 return os; 00112 } 00113 00117 int readConfiguration (int argc, char* argv[], 00118 bool& ioIsBuiltin, bool& ioIsForSchedule, 00119 stdair::Filename_T& ioInventoryFilename, 00120 stdair::Filename_T& ioScheduleInputFilename, 00121 stdair::Filename_T& ioODInputFilename, 00122 stdair::Filename_T& ioFRAT5Filename, 00123 stdair::Filename_T& ioFFDisutilityFilename, 00124 stdair::Filename_T& ioYieldInputFilename, 00125 std::string& ioLogFilename) { 00126 // Default for the built-in input 00127 ioIsBuiltin = K_AIRINV_DEFAULT_BUILT_IN_INPUT; 00128 00129 // Default for the inventory or schedule option 00130 ioIsForSchedule = K_AIRINV_DEFAULT_FOR_SCHEDULE; 00131 00132 // Declare a group of options that will be allowed only on command line 00133 boost::program_options::options_description generic ("Generic options"); 00134 generic.add_options() 00135 ("prefix", "print installation prefix") 00136 ("version,v", "print version string") 00137 ("help,h", "produce help message"); 00138 00139 // Declare a group of options that will be allowed both on command 00140 // line and in config file 00141 00142 boost::program_options::options_description config ("Configuration"); 00143 config.add_options() 00144 ("builtin,b", 00145 "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -i/--inventory or -s/--schedule option") 00146 ("for_schedule,f", 00147 "The BOM tree should be built from a schedule file (instead of from an inventory dump)") 00148 ("inventory,i", 00149 boost::program_options::value< std::string >(&ioInventoryFilename)->default_value(K_AIRINV_DEFAULT_INVENTORY_FILENAME), 00150 "(CSV) input file for the inventory") 00151 ("schedule,s", 00152 boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_AIRINV_DEFAULT_SCHEDULE_FILENAME), 00153 "(CSV) input file for the schedule") 00154 ("ond,o", 00155 boost::program_options::value< std::string >(&ioODInputFilename)->default_value(K_AIRINV_DEFAULT_OND_FILENAME), 00156 "(CSV) input file for the O&D") 00157 ("frat5,F", 00158 boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME), 00159 "(CSV) input file for the FRAT5 Curve") 00160 ("ff_disutility,D", 00161 boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME), 00162 "(CSV) input file for the FF disutility Curve") 00163 ("yield,y", 00164 boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_AIRINV_DEFAULT_YIELD_FILENAME), 00165 "(CSV) input file for the yield") 00166 ("log,l", 00167 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_AIRINV_DEFAULT_LOG_FILENAME), 00168 "Filename for the logs") 00169 ; 00170 00171 // Hidden options, will be allowed both on command line and 00172 // in config file, but will not be shown to the user. 00173 boost::program_options::options_description hidden ("Hidden options"); 00174 hidden.add_options() 00175 ("copyright", 00176 boost::program_options::value< std::vector<std::string> >(), 00177 "Show the copyright (license)"); 00178 00179 boost::program_options::options_description cmdline_options; 00180 cmdline_options.add(generic).add(config).add(hidden); 00181 00182 boost::program_options::options_description config_file_options; 00183 config_file_options.add(config).add(hidden); 00184 boost::program_options::options_description visible ("Allowed options"); 00185 visible.add(generic).add(config); 00186 00187 boost::program_options::positional_options_description p; 00188 p.add ("copyright", -1); 00189 00190 boost::program_options::variables_map vm; 00191 boost::program_options:: 00192 store (boost::program_options::command_line_parser (argc, argv). 00193 options (cmdline_options).positional(p).run(), vm); 00194 00195 std::ifstream ifs ("airinv.cfg"); 00196 boost::program_options::store (parse_config_file (ifs, config_file_options), 00197 vm); 00198 boost::program_options::notify (vm); 00199 00200 if (vm.count ("help")) { 00201 std::cout << visible << std::endl; 00202 return K_AIRINV_EARLY_RETURN_STATUS; 00203 } 00204 00205 if (vm.count ("version")) { 00206 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl; 00207 return K_AIRINV_EARLY_RETURN_STATUS; 00208 } 00209 00210 if (vm.count ("prefix")) { 00211 std::cout << "Installation prefix: " << PREFIXDIR << std::endl; 00212 return K_AIRINV_EARLY_RETURN_STATUS; 00213 } 00214 00215 if (vm.count ("builtin")) { 00216 ioIsBuiltin = true; 00217 } 00218 const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no"; 00219 std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl; 00220 00221 if (vm.count ("for_schedule")) { 00222 ioIsForSchedule = true; 00223 } 00224 const std::string isForScheduleStr = (ioIsForSchedule == true)?"yes":"no"; 00225 std::cout << "The BOM should be built from schedule? " << isForScheduleStr 00226 << std::endl; 00227 00228 if (ioIsBuiltin == false) { 00229 00230 if (ioIsForSchedule == false) { 00231 // The BOM tree should be built from parsing an inventory dump 00232 if (vm.count ("inventory")) { 00233 ioInventoryFilename = vm["inventory"].as< std::string >(); 00234 std::cout << "Input inventory filename is: " << ioInventoryFilename 00235 << std::endl; 00236 00237 } else { 00238 // The built-in option is not selected. However, no inventory dump 00239 // file is specified 00240 std::cerr << "Either one among the -b/--builtin, -i/--inventory or " 00241 << " -f/--for_schedule and -s/--schedule options " 00242 << "must be specified" << std::endl; 00243 } 00244 00245 } else { 00246 // The BOM tree should be built from parsing a schedule (and O&D) file 00247 if (vm.count ("schedule")) { 00248 ioScheduleInputFilename = vm["schedule"].as< std::string >(); 00249 std::cout << "Input schedule filename is: " << ioScheduleInputFilename 00250 << std::endl; 00251 00252 } else { 00253 // The built-in option is not selected. However, no schedule file 00254 // is specified 00255 std::cerr << "Either one among the -b/--builtin, -i/--inventory or " 00256 << " -f/--for_schedule and -s/--schedule options " 00257 << "must be specified" << std::endl; 00258 } 00259 00260 if (vm.count ("ond")) { 00261 ioODInputFilename = vm["ond"].as< std::string >(); 00262 std::cout << "Input O&D filename is: " << ioODInputFilename << std::endl; 00263 } 00264 00265 if (vm.count ("frat5")) { 00266 ioFRAT5Filename = vm["frat5"].as< std::string >(); 00267 std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl; 00268 00269 } 00270 00271 if (vm.count ("ff_disutility")) { 00272 ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >(); 00273 std::cout << "FF disutility input filename is: " 00274 << ioFFDisutilityFilename << std::endl; 00275 00276 } 00277 00278 if (vm.count ("yield")) { 00279 ioYieldInputFilename = vm["yield"].as< std::string >(); 00280 std::cout << "Input yield filename is: " << ioYieldInputFilename << std::endl; 00281 } 00282 } 00283 } 00284 00285 if (vm.count ("log")) { 00286 ioLogFilename = vm["log"].as< std::string >(); 00287 std::cout << "Log filename is: " << ioLogFilename << std::endl; 00288 } 00289 00290 return 0; 00291 } 00292 00293 // ////////////////////////////////////////////////////////////////// 00294 void initReadline (swift::SReadline& ioInputReader) { 00295 00296 // Prepare the list of my own completers 00297 std::vector<std::string> Completers; 00298 00299 // The following is supported: 00300 // - "identifiers" 00301 // - special identifier %file - means to perform a file name completion 00302 Completers.push_back ("help"); 00303 Completers.push_back ("list %airline_code %flight_number"); 00304 Completers.push_back ("select %airline_code %flight_number %flight_date"); 00305 Completers.push_back ("display"); 00306 Completers.push_back ("sell %booking_class %party_size %origin %destination"); 00307 Completers.push_back ("quit"); 00308 Completers.push_back ("json_list"); 00309 Completers.push_back ("json_display"); 00310 00311 00312 // Now register the completers. 00313 // Actually it is possible to re-register another set at any time 00314 ioInputReader.RegisterCompletions (Completers); 00315 } 00316 00317 // ////////////////////////////////////////////////////////////////// 00318 Command_T::Type_T extractCommand (TokenList_T& ioTokenList) { 00319 Command_T::Type_T oCommandType = Command_T::LAST_VALUE; 00320 00321 // Interpret the user input 00322 if (ioTokenList.empty() == false) { 00323 TokenList_T::iterator itTok = ioTokenList.begin(); 00324 std::string lCommand (*itTok); 00325 boost::algorithm::to_lower (lCommand); 00326 00327 if (lCommand == "help") { 00328 oCommandType = Command_T::HELP; 00329 00330 } else if (lCommand == "list") { 00331 oCommandType = Command_T::LIST; 00332 00333 } else if (lCommand == "display") { 00334 oCommandType = Command_T::DISPLAY; 00335 00336 } else if (lCommand == "select") { 00337 oCommandType = Command_T::SELECT; 00338 00339 } else if (lCommand == "sell") { 00340 oCommandType = Command_T::SELL; 00341 00342 } else if (lCommand == "json_list") { 00343 oCommandType = Command_T::JSON_LIST; 00344 00345 } else if (lCommand == "json_display") { 00346 oCommandType = Command_T::JSON_DISPLAY; 00347 00348 } else if (lCommand == "quit") { 00349 oCommandType = Command_T::QUIT; 00350 } 00351 00352 // Remove the first token (the command), as the corresponding information 00353 // has been extracted in the form of the returned command type enumeration 00354 ioTokenList.erase (itTok); 00355 00356 } else { 00357 oCommandType = Command_T::NOP; 00358 } 00359 00360 return oCommandType; 00361 } 00362 00363 // ////////////////////////////////////////////////////////////////// 00364 void parseFlightKey (const TokenList_T& iTokenList, 00365 stdair::AirlineCode_T& ioAirlineCode, 00366 stdair::FlightNumber_T& ioFlightNumber) { 00367 // Interpret the user input 00368 if (iTokenList.empty() == false) { 00369 00370 // Read the airline code 00371 TokenList_T::const_iterator itTok = iTokenList.begin(); 00372 if (itTok->empty() == false) { 00373 ioAirlineCode = *itTok; 00374 boost::algorithm::to_upper (ioAirlineCode); 00375 } 00376 00377 // Read the flight-number 00378 ++itTok; 00379 if (itTok != iTokenList.end()) { 00380 00381 if (itTok->empty() == false) { 00382 try { 00383 00384 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok); 00385 00386 } catch (boost::bad_lexical_cast& eCast) { 00387 std::cerr << "The flight number ('" << *itTok 00388 << "') cannot be understood. " 00389 << "The default value (all) is kept." 00390 << std::endl; 00391 return; 00392 } 00393 } 00394 00395 } else { 00396 return; 00397 } 00398 } 00399 } 00400 00401 // ////////////////////////////////////////////////////////////////// 00402 void parseFlightDateKey (const TokenList_T& iTokenList, 00403 stdair::AirlineCode_T& ioAirlineCode, 00404 stdair::FlightNumber_T& ioFlightNumber, 00405 stdair::Date_T& ioDepartureDate) { 00406 // 00407 const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 00408 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 00409 // 00410 unsigned short ioDepartureDateYear = ioDepartureDate.year(); 00411 unsigned short ioDepartureDateMonth = ioDepartureDate.month(); 00412 std::string ioDepartureDateMonthStr = kMonthStr[ioDepartureDateMonth-1]; 00413 unsigned short ioDepartureDateDay = ioDepartureDate.day(); 00414 00415 // Interpret the user input 00416 if (iTokenList.empty() == false) { 00417 00418 // Read the airline code 00419 TokenList_T::const_iterator itTok = iTokenList.begin(); 00420 if (itTok->empty() == false) { 00421 ioAirlineCode = *itTok; 00422 boost::algorithm::to_upper (ioAirlineCode); 00423 } 00424 00425 // Read the flight-number 00426 ++itTok; 00427 if (itTok != iTokenList.end()) { 00428 00429 if (itTok->empty() == false) { 00430 try { 00431 00432 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok); 00433 00434 } catch (boost::bad_lexical_cast& eCast) { 00435 std::cerr << "The flight number ('" << *itTok 00436 << "') cannot be understood. " 00437 << "The default value (all) is kept." 00438 << std::endl; 00439 return; 00440 } 00441 } 00442 00443 } else { 00444 return; 00445 } 00446 00447 // Read the year for the departure date 00448 ++itTok; 00449 if (itTok != iTokenList.end()) { 00450 00451 if (itTok->empty() == false) { 00452 try { 00453 00454 ioDepartureDateYear = boost::lexical_cast<unsigned short> (*itTok); 00455 if (ioDepartureDateYear < 100) { 00456 ioDepartureDateYear += 2000; 00457 } 00458 00459 } catch (boost::bad_lexical_cast& eCast) { 00460 std::cerr << "The year of the flight departure date ('" << *itTok 00461 << "') cannot be understood. The default value (" 00462 << ioDepartureDateYear << ") is kept. " << std::endl; 00463 return; 00464 } 00465 } 00466 00467 } else { 00468 return; 00469 } 00470 00471 // Read the month for the departure date 00472 ++itTok; 00473 if (itTok != iTokenList.end()) { 00474 00475 if (itTok->empty() == false) { 00476 try { 00477 00478 const boost::regex lMonthRegex ("^(\\d{1,2})$"); 00479 const bool isMonthANumber = regex_match (*itTok, lMonthRegex); 00480 00481 if (isMonthANumber == true) { 00482 const unsigned short lMonth = 00483 boost::lexical_cast<unsigned short> (*itTok); 00484 if (lMonth > 12) { 00485 throw boost::bad_lexical_cast(); 00486 } 00487 ioDepartureDateMonthStr = kMonthStr[lMonth-1]; 00488 00489 } else { 00490 const std::string lMonthStr (*itTok); 00491 if (lMonthStr.size() < 3) { 00492 throw boost::bad_lexical_cast(); 00493 } 00494 std::string lMonthStr1 (lMonthStr.substr (0, 1)); 00495 boost::algorithm::to_upper (lMonthStr1); 00496 std::string lMonthStr23 (lMonthStr.substr (1, 2)); 00497 boost::algorithm::to_lower (lMonthStr23); 00498 ioDepartureDateMonthStr = lMonthStr1 + lMonthStr23; 00499 } 00500 00501 } catch (boost::bad_lexical_cast& eCast) { 00502 std::cerr << "The month of the flight departure date ('" << *itTok 00503 << "') cannot be understood. The default value (" 00504 << ioDepartureDateMonthStr << ") is kept. " << std::endl; 00505 return; 00506 } 00507 } 00508 00509 } else { 00510 return; 00511 } 00512 00513 // Read the day for the departure date 00514 ++itTok; 00515 if (itTok != iTokenList.end()) { 00516 00517 if (itTok->empty() == false) { 00518 try { 00519 00520 ioDepartureDateDay = boost::lexical_cast<unsigned short> (*itTok); 00521 00522 } catch (boost::bad_lexical_cast& eCast) { 00523 std::cerr << "The day of the flight departure date ('" << *itTok 00524 << "') cannot be understood. The default value (" 00525 << ioDepartureDateDay << ") is kept. " << std::endl; 00526 return; 00527 } 00528 } 00529 00530 } else { 00531 return; 00532 } 00533 00534 // Re-compose the departure date 00535 std::ostringstream lDepartureDateStr; 00536 lDepartureDateStr << ioDepartureDateYear << "-" << ioDepartureDateMonthStr 00537 << "-" << ioDepartureDateDay; 00538 00539 try { 00540 00541 ioDepartureDate = 00542 boost::gregorian::from_simple_string (lDepartureDateStr.str()); 00543 00544 } catch (boost::gregorian::bad_month& eCast) { 00545 std::cerr << "The flight departure date ('" << lDepartureDateStr.str() 00546 << "') cannot be understood. The default value (" 00547 << ioDepartureDate << ") is kept. " << std::endl; 00548 return; 00549 } 00550 00551 } 00552 } 00553 00554 // ////////////////////////////////////////////////////////////////// 00555 void parseBookingClassKey (const TokenList_T& iTokenList, 00556 stdair::ClassCode_T& ioBookingClass, 00557 stdair::PartySize_T& ioPartySize, 00558 stdair::AirportCode_T& ioOrigin, 00559 stdair::AirportCode_T& ioDestination) { 00560 // Interpret the user input 00561 if (iTokenList.empty() == false) { 00562 00563 // Read the booking class 00564 TokenList_T::const_iterator itTok = iTokenList.begin(); 00565 if (itTok->empty() == false) { 00566 ioBookingClass = *itTok; 00567 boost::algorithm::to_upper (ioBookingClass); 00568 } 00569 00570 // Read the party size 00571 ++itTok; 00572 if (itTok != iTokenList.end()) { 00573 00574 if (itTok->empty() == false) { 00575 try { 00576 00577 ioPartySize = boost::lexical_cast<stdair::PartySize_T> (*itTok); 00578 00579 } catch (boost::bad_lexical_cast& eCast) { 00580 std::cerr << "The party size ('" << *itTok 00581 << "') cannot be understood. The default value (" 00582 << ioPartySize << ") is kept." << std::endl; 00583 return; 00584 } 00585 } 00586 00587 } else { 00588 return; 00589 } 00590 00591 // Read the origin 00592 ++itTok; 00593 if (itTok != iTokenList.end()) { 00594 00595 if (itTok->empty() == false) { 00596 ioOrigin = *itTok; 00597 boost::algorithm::to_upper (ioOrigin); 00598 } 00599 00600 } else { 00601 return; 00602 } 00603 00604 // Read the destination 00605 ++itTok; 00606 if (itTok != iTokenList.end()) { 00607 00608 if (itTok->empty() == false) { 00609 ioDestination = *itTok; 00610 boost::algorithm::to_upper (ioDestination); 00611 } 00612 00613 } else { 00614 return; 00615 } 00616 } 00617 } 00618 00619 // ///////////////////////////////////////////////////////// 00620 std::string toString (const TokenList_T& iTokenList) { 00621 std::ostringstream oStr; 00622 00623 // Re-create the string with all the tokens, trimmed by read-line 00624 unsigned short idx = 0; 00625 for (TokenList_T::const_iterator itTok = iTokenList.begin(); 00626 itTok != iTokenList.end(); ++itTok, ++idx) { 00627 if (idx != 0) { 00628 oStr << " "; 00629 } 00630 oStr << *itTok; 00631 } 00632 00633 return oStr.str(); 00634 } 00635 00636 // ///////////////////////////////////////////////////////// 00637 TokenList_T extractTokenList (const TokenList_T& iTokenList, 00638 const std::string& iRegularExpression) { 00639 TokenList_T oTokenList; 00640 00641 // Re-create the string with all the tokens (which had been trimmed 00642 // by read-line) 00643 const std::string lFullLine = toString (iTokenList); 00644 00645 // See the caller for the regular expression 00646 boost::regex expression (iRegularExpression); 00647 00648 std::string::const_iterator start = lFullLine.begin(); 00649 std::string::const_iterator end = lFullLine.end(); 00650 00651 boost::match_results<std::string::const_iterator> what; 00652 boost::match_flag_type flags = boost::match_default | boost::format_sed; 00653 regex_search (start, end, what, expression, flags); 00654 00655 // Put the matched strings in the list of tokens to be returned back 00656 // to the caller 00657 const unsigned short lMatchSetSize = what.size(); 00658 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) { 00659 const std::string lMatchedString (std::string (what[matchIdx].first, 00660 what[matchIdx].second)); 00661 //if (lMatchedString.empty() == false) { 00662 oTokenList.push_back (lMatchedString); 00663 //} 00664 } 00665 00666 // DEBUG 00667 // std::cout << "After (token list): " << oTokenList << std::endl; 00668 00669 return oTokenList; 00670 } 00671 00672 // ///////////////////////////////////////////////////////// 00673 TokenList_T extractTokenListForFlight (const TokenList_T& iTokenList) { 00680 const std::string lRegEx ("^([[:alpha:]]{2,3})?" 00681 "[[:space:]]*([[:digit:]]{1,4})?$"); 00682 00683 // 00684 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx); 00685 return oTokenList; 00686 } 00687 00688 // ///////////////////////////////////////////////////////// 00689 TokenList_T extractTokenListForFlightDate (const TokenList_T& iTokenList) { 00700 const std::string lRegEx("^([[:alpha:]]{2,3})?" 00701 "[[:space:]]*([[:digit:]]{1,4})?" 00702 "[/ ]*" 00703 "([[:digit:]]{2,4})?[/-]?[[:space:]]*" 00704 "([[:alpha:]]{3}|[[:digit:]]{1,2})?[/-]?[[:space:]]*" 00705 "([[:digit:]]{1,2})?$"); 00706 00707 // 00708 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx); 00709 return oTokenList; 00710 } 00711 00712 // ///////////////////////////////////////////////////////// 00713 TokenList_T extractTokenListForClass (const TokenList_T& iTokenList) { 00722 const std::string lRegEx ("^([[:alpha:]])?" 00723 "[[:space:]]*([[:digit:]]{1,3})?" 00724 "[[:space:]]*([[:alpha:]]{3})?" 00725 "[[:space:]]*([[:alpha:]]{3})?$"); 00726 00727 // 00728 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx); 00729 return oTokenList; 00730 } 00731 00732 00733 // ///////// M A I N //////////// 00734 int main (int argc, char* argv[]) { 00735 00736 // State whether the BOM tree should be built-in or parsed from an 00737 // input file 00738 bool isBuiltin; 00739 bool isForSchedule; 00740 00741 // Input file names 00742 stdair::Filename_T lInventoryFilename; 00743 stdair::Filename_T lScheduleInputFilename; 00744 stdair::Filename_T lODInputFilename; 00745 stdair::Filename_T lFRAT5InputFilename; 00746 stdair::Filename_T lFFDisutilityInputFilename; 00747 stdair::Filename_T lYieldInputFilename; 00748 00749 // Readline history 00750 const unsigned int lHistorySize (100); 00751 const std::string lHistoryFilename ("airinv.hist"); 00752 const std::string lHistoryBackupFilename ("airinv.hist.bak"); 00753 00754 // Default parameters for the interactive session 00755 stdair::AirlineCode_T lLastInteractiveAirlineCode; 00756 stdair::FlightNumber_T lLastInteractiveFlightNumber; 00757 stdair::Date_T lLastInteractiveDate; 00758 stdair::AirlineCode_T lInteractiveAirlineCode; 00759 stdair::FlightNumber_T lInteractiveFlightNumber; 00760 stdair::Date_T lInteractiveDate; 00761 stdair::AirportCode_T lInteractiveOrigin; 00762 stdair::AirportCode_T lInteractiveDestination; 00763 stdair::ClassCode_T lInteractiveBookingClass; 00764 stdair::PartySize_T lInteractivePartySize; 00765 00766 // Parameters for the sale 00767 std::string lSegmentDateKey; 00768 00769 // Output log File 00770 stdair::Filename_T lLogFilename; 00771 00772 // Call the command-line option parser 00773 const int lOptionParserStatus = 00774 readConfiguration (argc, argv, isBuiltin, isForSchedule, lInventoryFilename, 00775 lScheduleInputFilename, lODInputFilename, 00776 lFRAT5InputFilename, lFFDisutilityInputFilename, 00777 lYieldInputFilename, lLogFilename); 00778 00779 if (lOptionParserStatus == K_AIRINV_EARLY_RETURN_STATUS) { 00780 return 0; 00781 } 00782 00783 // Set the log parameters 00784 std::ofstream logOutputFile; 00785 // Open and clean the log outputfile 00786 logOutputFile.open (lLogFilename.c_str()); 00787 logOutputFile.clear(); 00788 00789 // Initialise the inventory service 00790 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile); 00791 AIRINV::AIRINV_Master_Service airinvService (lLogParams); 00792 00793 // DEBUG 00794 STDAIR_LOG_DEBUG ("Welcome to AirInv"); 00795 00796 // Check wether or not a (CSV) input file should be read 00797 if (isBuiltin == true) { 00798 00799 // Build the sample BOM tree for RMOL 00800 airinvService.buildSampleBom(); 00801 00802 // Update the default parameters for the following interactive session 00803 lInteractiveAirlineCode = "BA"; 00804 lInteractiveFlightNumber = 9; 00805 lInteractiveDate = stdair::Date_T (2011, 06, 10); 00806 lInteractiveBookingClass = "Q"; 00807 lInteractivePartySize = 2; 00808 lInteractiveOrigin = "LHR"; 00809 lInteractiveDestination = "SYD"; 00810 00811 } else { 00812 if (isForSchedule == true) { 00813 // Build the BOM tree from parsing a schedule file (and O&D list) 00814 stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename); 00815 stdair::ODFilePath lODFilePath (lODInputFilename); 00816 stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename); 00817 stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename); 00818 AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename); 00819 airinvService.parseAndLoad (lScheduleFilePath, lODFilePath, 00820 lFRAT5FilePath, lFFDisutilityFilePath, 00821 lYieldFilePath); 00822 00823 // Update the default parameters for the following interactive session 00824 lInteractiveAirlineCode = "SQ"; 00825 lInteractiveFlightNumber = 11; 00826 lInteractiveDate = stdair::Date_T (2010, 01, 15); 00827 lInteractiveBookingClass = "Y"; 00828 lInteractivePartySize = 2; 00829 lInteractiveOrigin = "SIN"; 00830 lInteractiveDestination = "BKK"; 00831 00832 } else { 00833 // Build the BOM tree from parsing an inventory dump file 00834 AIRINV::InventoryFilePath lInventoryFilePath (lInventoryFilename); 00835 airinvService.parseAndLoad (lInventoryFilePath); 00836 00837 // Update the default parameters for the following interactive session 00838 lInteractiveAirlineCode = "SV"; 00839 lInteractiveFlightNumber = 5; 00840 lInteractiveDate = stdair::Date_T (2010, 03, 11); 00841 lInteractiveBookingClass = "Y"; 00842 lInteractivePartySize = 2; 00843 lInteractiveOrigin = "KBP"; 00844 lInteractiveDestination = "JFK"; 00845 } 00846 } 00847 00848 // Save the last state 00849 lLastInteractiveAirlineCode = lInteractiveAirlineCode; 00850 lLastInteractiveFlightNumber = lInteractiveFlightNumber; 00851 lLastInteractiveDate = lInteractiveDate; 00852 00853 // DEBUG 00854 STDAIR_LOG_DEBUG ("===================================================="); 00855 STDAIR_LOG_DEBUG ("= Beginning of the interactive session ="); 00856 STDAIR_LOG_DEBUG ("===================================================="); 00857 00858 // Initialise the GNU readline wrapper 00859 swift::SReadline lReader (lHistoryFilename, lHistorySize); 00860 initReadline (lReader); 00861 00862 // Now we can ask user for a line 00863 std::string lUserInput; 00864 bool EndOfInput (false); 00865 Command_T::Type_T lCommandType (Command_T::NOP); 00866 00867 while (lCommandType != Command_T::QUIT && EndOfInput == false) { 00868 // Prompt 00869 std::ostringstream oPromptStr; 00870 oPromptStr << "airinv " 00871 << lInteractiveAirlineCode << lInteractiveFlightNumber 00872 << " / " << lInteractiveDate 00873 << "> "; 00874 // Call read-line, which will fill the list of tokens 00875 TokenList_T lTokenListByReadline; 00876 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline, 00877 EndOfInput); 00878 00879 // The history can be saved to an arbitrary file at any time 00880 lReader.SaveHistory (lHistoryBackupFilename); 00881 00882 // The end-of-input typically corresponds to a CTRL-D typed by the user 00883 if (EndOfInput) { 00884 std::cout << std::endl; 00885 break; 00886 } 00887 00888 // Interpret the user input 00889 lCommandType = extractCommand (lTokenListByReadline); 00890 00891 switch (lCommandType) { 00892 00893 // ////////////////////////////// Help //////////////////////// 00894 case Command_T::HELP: { 00895 std::cout << std::endl; 00896 std::cout << "Commands: " << std::endl; 00897 std::cout << " help" << "\t\t" << "Display this help" << std::endl; 00898 std::cout << " quit" << "\t\t" << "Quit the application" << std::endl; 00899 std::cout << " list" << "\t\t" 00900 << "List airlines, flights and departure dates" << std::endl; 00901 std::cout << " select" << "\t\t" 00902 << "Select a flight-date to become the current one" 00903 << std::endl; 00904 std::cout << " display" << "\t" 00905 << "Display the current flight-date" << std::endl; 00906 std::cout << " sell" << "\t\t" 00907 << "Make a booking on the current flight-date" << std::endl; 00908 std::cout << " \nDebug Commands" << std::endl; 00909 std::cout << " json_list" << "\t" 00910 << "List airlines, flights and departure dates in a JSON format" 00911 << std::endl; 00912 std::cout << " json_display" << "\t" 00913 << "Display the current flight-date in a JSON format" 00914 << std::endl; 00915 std::cout << std::endl; 00916 break; 00917 } 00918 00919 // ////////////////////////////// Quit //////////////////////// 00920 case Command_T::QUIT: { 00921 break; 00922 } 00923 00924 // ////////////////////////////// List ///////////////////////// 00925 case Command_T::LIST: { 00926 // 00927 TokenList_T lTokenList = extractTokenListForFlight (lTokenListByReadline); 00928 00929 stdair::AirlineCode_T lAirlineCode ("all"); 00930 stdair::FlightNumber_T lFlightNumber (0); 00931 // Parse the parameters given by the user, giving default values 00932 // in case the user does not specify some (or all) of them 00933 parseFlightKey (lTokenList, lAirlineCode, lFlightNumber); 00934 00935 // 00936 const std::string lFlightNumberStr = (lFlightNumber ==0)?" (all)":""; 00937 std::cout << "List of flights for " 00938 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr 00939 << std::endl; 00940 00941 // DEBUG: Display the flight-date 00942 const std::string& lFlightDateListStr = 00943 airinvService.list (lAirlineCode, lFlightNumber); 00944 00945 if (lFlightDateListStr.empty() == false) { 00946 std::cout << lFlightDateListStr << std::endl; 00947 STDAIR_LOG_DEBUG (lFlightDateListStr); 00948 00949 } else { 00950 std::cerr << "There is no result for " 00951 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr 00952 << ". Just type the list command without any parameter " 00953 << "to see the flight-dates for all the airlines and for all " 00954 << "the flight numbers." 00955 << std::endl; 00956 } 00957 00958 break; 00959 } 00960 00961 // ////////////////////////////// Select //////////////////////// 00962 case Command_T::SELECT: { 00963 // 00964 TokenList_T lTokenList = 00965 extractTokenListForFlightDate (lTokenListByReadline); 00966 00967 // Check whether the user wants to select the last saved flight-date 00968 if (lTokenList.empty() == false) { 00969 // Read the booking class 00970 TokenList_T::const_iterator itTok = lTokenList.begin(); 00971 00972 if (*itTok == "-") { 00973 00974 // Swap the current state with the last state 00975 boost::swap (lInteractiveAirlineCode, lLastInteractiveAirlineCode); 00976 boost::swap (lInteractiveFlightNumber, lLastInteractiveFlightNumber); 00977 boost::swap (lInteractiveDate, lLastInteractiveDate); 00978 00979 break; 00980 } 00981 } 00982 00983 // Parse the parameters given by the user, giving default values 00984 // in case the user does not specify some (or all) of them 00985 parseFlightDateKey (lTokenList, lInteractiveAirlineCode, 00986 lInteractiveFlightNumber, lInteractiveDate); 00987 00988 // Check whether the selected flight-date is valid 00989 const bool isFlightDateValid = 00990 airinvService.check (lInteractiveAirlineCode, lInteractiveFlightNumber, 00991 lInteractiveDate); 00992 if (isFlightDateValid == false) { 00993 std::ostringstream oFDKStr; 00994 oFDKStr << "The " << lInteractiveAirlineCode 00995 << lInteractiveFlightNumber << " / " << lInteractiveDate 00996 << " flight-date is not valid. Make sure it exists (e.g.," 00997 << " with the list command). The current flight-date is kept" 00998 << " selected."; 00999 std::cout << oFDKStr.str() << std::endl; 01000 STDAIR_LOG_ERROR (oFDKStr.str()); 01001 01002 // Restore the last state 01003 lInteractiveAirlineCode = lLastInteractiveAirlineCode; 01004 lInteractiveFlightNumber = lLastInteractiveFlightNumber; 01005 lInteractiveDate = lLastInteractiveDate; 01006 01007 break; 01008 } 01009 01010 // DEBUG: Display the flight-date selection 01011 std::ostringstream oFDKStr; 01012 oFDKStr << "Selected the " << lInteractiveAirlineCode 01013 << lInteractiveFlightNumber << " / " << lInteractiveDate 01014 << " flight-date"; 01015 std::cout << oFDKStr.str() << std::endl; 01016 STDAIR_LOG_DEBUG (oFDKStr.str()); 01017 01018 // Save the last state 01019 lLastInteractiveAirlineCode = lInteractiveAirlineCode; 01020 lLastInteractiveFlightNumber = lInteractiveFlightNumber; 01021 lLastInteractiveDate = lInteractiveDate; 01022 01023 break; 01024 } 01025 01026 // ////////////////////////////// Display //////////////////////// 01027 case Command_T::DISPLAY: { 01028 // DEBUG: Display the flight-date 01029 const std::string& lCSVFlightDateDump = 01030 airinvService.csvDisplay (lInteractiveAirlineCode, 01031 lInteractiveFlightNumber, lInteractiveDate); 01032 std::cout << lCSVFlightDateDump << std::endl; 01033 STDAIR_LOG_DEBUG (lCSVFlightDateDump); 01034 01035 break; 01036 } 01037 01038 // ////////////////////////////// Sell //////////////////////// 01039 case Command_T::SELL: { 01040 // 01041 TokenList_T lTokenList = extractTokenListForClass (lTokenListByReadline); 01042 01043 // Parse the parameters given by the user, giving default values 01044 // in case the user does not specify some (or all) of them 01045 parseBookingClassKey (lTokenList, lInteractiveBookingClass, 01046 lInteractivePartySize, 01047 lInteractiveOrigin, lInteractiveDestination); 01048 01049 // DEBUG: Display the flight-date before the sell 01050 const std::string& lCSVFlightDateDumpBefore = 01051 airinvService.csvDisplay (lInteractiveAirlineCode, 01052 lInteractiveFlightNumber, lInteractiveDate); 01053 //std::cout << lCSVFlightDateDumpBefore << std::endl; 01054 STDAIR_LOG_DEBUG (lCSVFlightDateDumpBefore); 01055 01056 // Make a booking 01057 std::ostringstream oSDKStr; 01058 oSDKStr << lInteractiveAirlineCode << "," 01059 << lInteractiveFlightNumber << "," 01060 << lInteractiveDate << "," 01061 << lInteractiveOrigin << "," << lInteractiveDestination; 01062 const std::string lSegmentDateKey (oSDKStr.str()); 01063 01064 // Perform the sell 01065 const bool isSellSuccessful = 01066 airinvService.sell (lSegmentDateKey, 01067 lInteractiveBookingClass, lInteractivePartySize); 01068 01069 // DEBUG 01070 const std::string isSellSuccessfulStr = 01071 (isSellSuccessful == true)?"Yes":"No"; 01072 std::ostringstream oSaleStr; 01073 oSaleStr << "Sale ('" << lSegmentDateKey << "', " 01074 << lInteractiveBookingClass << ": " << lInteractivePartySize 01075 << ") successful? " << isSellSuccessfulStr; 01076 std::cout << oSaleStr.str() << std::endl; 01077 01078 // DEBUG 01079 STDAIR_LOG_DEBUG (oSaleStr.str()); 01080 01081 // DEBUG: Display the flight-date after the sell 01082 const std::string& lCSVFlightDateDumpAfter = 01083 airinvService.csvDisplay (lInteractiveAirlineCode, 01084 lInteractiveFlightNumber, lInteractiveDate); 01085 //std::cout << lCSVFlightDateDumpAfter << std::endl; 01086 STDAIR_LOG_DEBUG (lCSVFlightDateDumpAfter); 01087 01088 break; 01089 } 01090 01091 // ////////////////////////////// JSon List //////////////////////// 01092 01093 case Command_T::JSON_LIST: { 01094 01095 // 01096 TokenList_T lTokenList = extractTokenListForFlight (lTokenListByReadline); 01097 01098 stdair::AirlineCode_T lAirlineCode ("all"); 01099 stdair::FlightNumber_T lFlightNumber (0); 01100 // Parse the parameters given by the user, giving default values 01101 // in case the user does not specify some (or all) of them 01102 parseFlightKey (lTokenList, lAirlineCode, lFlightNumber); 01103 01104 // 01105 const std::string lFlightNumberStr = (lFlightNumber ==0)?" (all)":""; 01106 std::cout << "JSON list of flights for " 01107 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr 01108 << std::endl; 01109 01110 std::ostringstream lMyCommandJSONstream; 01111 lMyCommandJSONstream << "{\"list\":" 01112 << "{ \"airline_code\":\"" << lAirlineCode 01113 << "\",\"flight_number\":\"" << lFlightNumber 01114 << "\"}}"; 01115 01116 const stdair::JSONString lJSONCommandString (lMyCommandJSONstream.str()); 01117 const std::string& lFlightDateListJSONStr = 01118 airinvService.jsonHandler (lJSONCommandString); 01119 01120 // Display the flight-date JSON string 01121 std::cout << lFlightDateListJSONStr << std::endl; 01122 STDAIR_LOG_DEBUG (lFlightDateListJSONStr); 01123 01124 break; 01125 } 01126 01127 // ////////////////////////////// JSon Display //////////////////////// 01128 01129 case Command_T::JSON_DISPLAY: { 01130 01131 // Construct the JSON command string for the current parameters (current 01132 // airline code, current flight number and current date) 01133 std::ostringstream lMyCommandJSONstream; 01134 lMyCommandJSONstream << "{\"flight_date\":" 01135 << "{ \"departure_date\":\"" << lInteractiveDate 01136 << "\",\"airline_code\":\"" << lInteractiveAirlineCode 01137 << "\",\"flight_number\":\"" << lInteractiveFlightNumber 01138 << "\"}}"; 01139 01140 // Get the flight-date details in a JSON string 01141 const stdair::JSONString lJSONCommandString (lMyCommandJSONstream.str()); 01142 const std::string& lCSVFlightDateDump = 01143 airinvService.jsonHandler (lJSONCommandString); 01144 01145 // Display the flight-date JSON string 01146 std::cout << lCSVFlightDateDump << std::endl; 01147 STDAIR_LOG_DEBUG (lCSVFlightDateDump); 01148 01149 break; 01150 } 01151 01152 // /////////////////////////// Default / No value /////////////////////// 01153 case Command_T::NOP: { 01154 break; 01155 } 01156 01157 case Command_T::LAST_VALUE: 01158 default: { 01159 // DEBUG 01160 std::ostringstream oStr; 01161 oStr << "That command is not yet understood: '" << lUserInput 01162 << "' => " << lTokenListByReadline; 01163 STDAIR_LOG_DEBUG (oStr.str()); 01164 std::cout << oStr.str() << std::endl; 01165 } 01166 } 01167 } 01168 01169 // DEBUG 01170 STDAIR_LOG_DEBUG ("End of the session. Exiting."); 01171 std::cout << "End of the session. Exiting." << std::endl; 01172 01173 // Close the Log outputFile 01174 logOutputFile.close(); 01175 01176 /* 01177 Note: as that program is not intended to be run on a server in 01178 production, it is better not to catch the exceptions. When it 01179 happens (that an exception is throwned), that way we get the 01180 call stack. 01181 */ 01182 01183 return 0; 01184 }