$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 // StdAir 00016 #include <stdair/basic/BasLogParams.hpp> 00017 #include <stdair/basic/BasConst_BomDisplay.hpp> 00018 #include <stdair/basic/BasDBParams.hpp> 00019 #include <stdair/basic/BasConst_DefaultObject.hpp> 00020 #include <stdair/basic/BasConst_Inventory.hpp> 00021 #include <stdair/basic/BasConst_Request.hpp> 00022 #include <stdair/service/Logger.hpp> 00023 #include <stdair/stdair_exceptions.hpp> 00024 #include <stdair/stdair_basic_types.hpp> 00025 #include <stdair/stdair_date_time_types.hpp> 00026 #include <stdair/bom/TravelSolutionStruct.hpp> 00027 #include <stdair/bom/BookingRequestStruct.hpp> 00028 #include <stdair/bom/ParsedKey.hpp> 00029 #include <stdair/bom/BomKeyManager.hpp> 00030 #include <stdair/command/CmdBomManager.hpp> 00031 // Stdair GNU Readline Wrapper 00032 #include <stdair/ui/cmdline/SReadline.hpp> 00033 // Simfqt 00034 #include <simfqt/SIMFQT_Service.hpp> 00035 #include <simfqt/config/simfqt-paths.hpp> 00036 00037 00038 // //////// Constants ////// 00042 const std::string K_SIMFQT_DEFAULT_LOG_FILENAME ("simfqt.log"); 00043 00047 const std::string K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME (STDAIR_SAMPLE_DIR 00048 "/fare01.csv"); 00049 00054 const bool K_SIMFQT_DEFAULT_BUILT_IN_INPUT = false; 00055 00059 const int K_SIMFQT_EARLY_RETURN_STATUS = 99; 00060 00065 typedef std::vector<std::string> TokenList_T; 00066 00070 struct Command_T { 00071 typedef enum { 00072 NOP = 0, 00073 QUIT, 00074 HELP, 00075 LIST, 00076 DISPLAY, 00077 PRICE, 00078 LAST_VALUE 00079 } Type_T; 00080 }; 00081 00082 // ///////// Parsing of Options & Configuration ///////// 00083 // A helper function to simplify the main part. 00084 template<class T> std::ostream& operator<< (std::ostream& os, 00085 const std::vector<T>& v) { 00086 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " ")); 00087 return os; 00088 } 00089 00093 int readConfiguration (int argc, char* argv[], bool& ioIsBuiltin, 00094 stdair::Filename_T& ioFareInputFilename, 00095 std::string& ioLogFilename) { 00096 00097 // Default for the built-in input 00098 ioIsBuiltin = K_SIMFQT_DEFAULT_BUILT_IN_INPUT; 00099 00100 // Declare a group of options that will be allowed only on command line 00101 boost::program_options::options_description generic ("Generic options"); 00102 generic.add_options() 00103 ("prefix", "print installation prefix") 00104 ("version,v", "print version string") 00105 ("help,h", "produce help message"); 00106 00107 // Declare a group of options that will be allowed both on command 00108 // line and in config file 00109 boost::program_options::options_description config ("Configuration"); 00110 config.add_options() 00111 ("builtin,b", 00112 "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -f/--fare option") 00113 ("fare,f", 00114 boost::program_options::value< std::string >(&ioFareInputFilename)->default_value(K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME), 00115 "(CSV) input file for the fare rules") 00116 ("log,l", 00117 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_SIMFQT_DEFAULT_LOG_FILENAME), 00118 "Filename for the logs") 00119 ; 00120 00121 // Hidden options, will be allowed both on command line and 00122 // in config file, but will not be shown to the user. 00123 boost::program_options::options_description hidden ("Hidden options"); 00124 hidden.add_options() 00125 ("copyright", 00126 boost::program_options::value< std::vector<std::string> >(), 00127 "Show the copyright (license)"); 00128 00129 boost::program_options::options_description cmdline_options; 00130 cmdline_options.add(generic).add(config).add(hidden); 00131 00132 boost::program_options::options_description config_file_options; 00133 config_file_options.add(config).add(hidden); 00134 00135 boost::program_options::options_description visible ("Allowed options"); 00136 visible.add(generic).add(config); 00137 00138 boost::program_options::positional_options_description p; 00139 p.add ("copyright", -1); 00140 00141 boost::program_options::variables_map vm; 00142 boost::program_options:: 00143 store (boost::program_options::command_line_parser (argc, argv). 00144 options (cmdline_options).positional(p).run(), vm); 00145 00146 std::ifstream ifs ("simfqt.cfg"); 00147 boost::program_options::store (parse_config_file (ifs, config_file_options), 00148 vm); 00149 boost::program_options::notify (vm); if (vm.count ("help")) { 00150 std::cout << visible << std::endl; 00151 return K_SIMFQT_EARLY_RETURN_STATUS; 00152 } 00153 00154 if (vm.count ("version")) { 00155 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl; 00156 return K_SIMFQT_EARLY_RETURN_STATUS; 00157 } 00158 00159 if (vm.count ("prefix")) { 00160 std::cout << "Installation prefix: " << PREFIXDIR << std::endl; 00161 return K_SIMFQT_EARLY_RETURN_STATUS; 00162 } 00163 00164 if (vm.count ("builtin")) { 00165 ioIsBuiltin = true; 00166 } 00167 const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no"; 00168 std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl; 00169 00170 if (ioIsBuiltin == false) { 00171 00172 // The BOM tree should be built from parsing a fare (and O&D) file 00173 if (vm.count ("fare")) { 00174 ioFareInputFilename = vm["fare"].as< std::string >(); 00175 std::cout << "Input fare filename is: " << ioFareInputFilename 00176 << std::endl; 00177 00178 } else { 00179 // The built-in option is not selected. However, no fare file 00180 // is specified 00181 std::cerr << "Either one among the -b/--builtin and -f/--fare " 00182 << "options must be specified" << std::endl; 00183 } 00184 } 00185 00186 if (vm.count ("log")) { 00187 ioLogFilename = vm["log"].as< std::string >(); 00188 std::cout << "Log filename is: " << ioLogFilename << std::endl; 00189 } 00190 00191 return 0; 00192 00193 } 00194 00195 // ////////////////////////////////////////////////////////////////// 00196 void initReadline (swift::SReadline& ioInputReader) { 00197 00198 // Prepare the list of my own completers 00199 std::vector<std::string> Completers; 00200 00201 // The following is supported: 00202 // - "identifiers" 00203 // - special identifier %file - means to perform a file name completion 00204 Completers.push_back ("help"); 00205 Completers.push_back ("list"); 00206 Completers.push_back ("display %airport_code %airport_code %departure_date"); 00207 Completers.push_back ("price %airline_code %flight_number %departure_date %airport_code %airport_code %departure_time %booking_date %booking_time %POS %channel% %trip_type %stay_duration"); 00208 Completers.push_back ("quit"); 00209 00210 // Now register the completers. 00211 // Actually it is possible to re-register another set at any time 00212 ioInputReader.RegisterCompletions (Completers); 00213 } 00214 00215 // ////////////////////////////////////////////////////////////////// 00216 Command_T::Type_T extractCommand (TokenList_T& ioTokenList) { 00217 Command_T::Type_T oCommandType = Command_T::LAST_VALUE; 00218 00219 // Interpret the user input 00220 if (ioTokenList.empty() == false) { 00221 TokenList_T::iterator itTok = ioTokenList.begin(); 00222 std::string& lCommand (*itTok); 00223 boost::algorithm::to_lower (lCommand); 00224 00225 if (lCommand == "help") { 00226 oCommandType = Command_T::HELP; 00227 00228 } else if (lCommand == "list") { 00229 oCommandType = Command_T::LIST; 00230 00231 } else if (lCommand == "display") { 00232 oCommandType = Command_T::DISPLAY; 00233 00234 } else if (lCommand == "price") { 00235 oCommandType = Command_T::PRICE; 00236 00237 } else if (lCommand == "quit") { 00238 oCommandType = Command_T::QUIT; 00239 00240 } 00241 00242 // Remove the first token (the command), as the corresponding information 00243 // has been extracted in the form of the returned command type enumeration 00244 ioTokenList.erase (itTok); 00245 00246 } else { 00247 oCommandType = Command_T::NOP; 00248 } 00249 00250 return oCommandType; 00251 } 00252 00253 // ////////////////////////////////////////////////////////////////// 00254 // Re-compose a date using three strings: the year, the month and the 00255 // day. Return true if a correct date has been computed, false if not. 00256 bool retrieveDate (std::string iYearString, 00257 std::string iMonthString, 00258 std::string iDayString, 00259 stdair::Date_T& ioDate) { 00260 00261 const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 00262 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 00263 00264 // Check the year. 00265 unsigned short lDateYear; 00266 try { 00267 00268 lDateYear = boost::lexical_cast<unsigned short> (iYearString); 00269 if (lDateYear < 100) { 00270 lDateYear += 2000; 00271 } 00272 00273 } catch (boost::bad_lexical_cast& eCast) { 00274 std::cerr << "The year ('" << iYearString 00275 << "') cannot be understood." << std::endl; 00276 return false; 00277 } 00278 00279 // Check the month. 00280 std::string lDateMonthStr; 00281 try { 00282 00283 const boost::regex lMonthRegex ("^(\\d{1,2})$"); 00284 const bool isMonthANumber = regex_match (iMonthString, lMonthRegex); 00285 00286 if (isMonthANumber == true) { 00287 const unsigned short lMonth = 00288 boost::lexical_cast<unsigned short> (iMonthString); 00289 if (lMonth > 12) { 00290 throw boost::bad_lexical_cast(); 00291 } 00292 if (lMonth != 0) { 00293 lDateMonthStr = kMonthStr[lMonth-1]; 00294 } else { 00295 std::cerr << "The month ('" << iMonthString 00296 << "') cannot be understood." << std::endl; 00297 return false; 00298 } 00299 00300 } else { 00301 if (iMonthString.size() < 3) { 00302 throw boost::bad_lexical_cast(); 00303 } 00304 std::string lMonthStr1 (iMonthString.substr (0, 1)); 00305 boost::algorithm::to_upper (lMonthStr1); 00306 std::string lMonthStr23 (iMonthString.substr (1, 2)); 00307 boost::algorithm::to_lower (lMonthStr23); 00308 lDateMonthStr = lMonthStr1 + lMonthStr23; 00309 } 00310 00311 } catch (boost::bad_lexical_cast& eCast) { 00312 std::cerr << "The month ('" << iMonthString 00313 << "') cannot be understood." << std::endl; 00314 return false; 00315 } 00316 00317 // Check the day. 00318 unsigned short lDateDay; 00319 try { 00320 00321 lDateDay = boost::lexical_cast<unsigned short> (iDayString); 00322 00323 } catch (boost::bad_lexical_cast& eCast) { 00324 std::cerr << "The day ('" << iDayString 00325 << "') cannot be understood." << std::endl; 00326 return false; 00327 } 00328 00329 // Re-compose the date. 00330 std::ostringstream lDateStr; 00331 lDateStr << lDateYear << "-" << lDateMonthStr 00332 << "-" << lDateDay; 00333 try { 00334 00335 ioDate = 00336 boost::gregorian::from_simple_string (lDateStr.str()); 00337 00338 } catch (boost::gregorian::bad_month& eCast) { 00339 std::cerr << "The month of the date ('" << lDateStr.str() 00340 << "') cannot be understood." << std::endl; 00341 return false; 00342 } catch (boost::gregorian::bad_day_of_month& eCast) { 00343 std::cerr << "The date ('" << lDateStr.str() 00344 << "') is not correct: the day of month does not exist." 00345 << std::endl; 00346 return false; 00347 } catch (boost::gregorian::bad_year& eCast) { 00348 std::cerr << "The year ('" << lDateStr.str() 00349 << "') is not correct." 00350 << std::endl; 00351 return false; 00352 } 00353 00354 return true; 00355 } 00356 00357 // ////////////////////////////////////////////////////////////////// 00358 // Re-compose a time using two strings: the hour and the minute. 00359 // Return true if a correct time has been computed, false if not. 00360 bool retrieveTime (std::string iHourString, 00361 std::string iMinuteString, 00362 stdair::Duration_T& oTime) { 00363 00364 // Check the hour 00365 unsigned short lTimeHour; 00366 try { 00367 00368 lTimeHour = boost::lexical_cast<unsigned short> (iHourString); 00369 00370 } catch (boost::bad_lexical_cast& eCast) { 00371 std::cerr << "The hour of the time ('" << iHourString 00372 << "') cannot be understood." << std::endl; 00373 return false; 00374 } 00375 00376 // Check the minutes 00377 unsigned short lTimeMinute; 00378 try { 00379 00380 lTimeMinute = boost::lexical_cast<unsigned short> (iMinuteString); 00381 00382 } catch (boost::bad_lexical_cast& eCast) { 00383 std::cerr << "The minute of the time ('" << iMinuteString 00384 << "') cannot be understood." << std::endl; 00385 return false; 00386 } 00387 00388 00389 // Re-compose the time 00390 std::ostringstream lTimeStr; 00391 lTimeStr << lTimeHour << ":" << lTimeMinute; 00392 oTime = 00393 boost::posix_time::duration_from_string (lTimeStr.str()); 00394 00395 return true; 00396 } 00397 00398 // ////////////////////////////////////////////////////////////////// 00399 // Analyze the tokens of the 'price' command in order to construct 00400 // a travel solution list and a booking request. 00401 const stdair::BookingRequestStruct parseTravelSolutionAndBookingRequestKey 00402 (const TokenList_T& iTokenList, 00403 stdair::TravelSolutionList_T& ioInteractiveTravelSolutionList, 00404 const stdair::BookingRequestStruct& ioBookingRequestStruct) { 00405 00406 TokenList_T::const_iterator itTok = iTokenList.begin(); 00407 00408 if (itTok->empty() == true) { 00409 00410 std::cerr << "Wrong list of parameters. " 00411 << "The default booking request and travel solution list are kept." 00412 << std::endl; 00413 return ioBookingRequestStruct; 00414 00415 00416 } else { 00417 // Parameters corresponding to the tokens. 00418 // Each parameter correponds to one token except the dates 00419 // (three tokens) and the times (two tokens). 00420 stdair::AirlineCode_T lAirlineCode; 00421 stdair::FlightNumber_T lflightNumber; 00422 stdair::Date_T lDepartureDate; 00423 stdair::Duration_T lDepartureTime; 00424 stdair::AirportCode_T lOriginAirport; 00425 stdair::AirportCode_T lDestinationAirport; 00426 stdair::Date_T lRequestDate; 00427 stdair::Duration_T lRequestTime; 00428 stdair::CityCode_T lPOS; 00429 stdair::ChannelLabel_T lChannel; 00430 stdair::TripType_T lTripType; 00431 unsigned short lStayDuration; 00432 00433 // Read the airline code. 00434 lAirlineCode = *itTok; 00435 boost::algorithm::to_upper (lAirlineCode); 00436 00437 // Read the flight-number . 00438 ++itTok; 00439 if (itTok->empty() == false) { 00440 try { 00441 00442 lflightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok); 00443 00444 } catch (boost::bad_lexical_cast& eCast) { 00445 std::cerr << "The flight number ('" << *itTok 00446 << "') cannot be understood." 00447 << std::endl; 00448 return ioBookingRequestStruct; 00449 } 00450 } 00451 00452 // Read the departure date. 00453 ++itTok; 00454 if (itTok->empty() == true) { 00455 return ioBookingRequestStruct; 00456 } 00457 const std::string lDepartureYearString = *itTok; 00458 ++itTok; 00459 if (itTok->empty() == true) { 00460 return ioBookingRequestStruct; 00461 } 00462 const std::string lDepartureMonthString = *itTok; 00463 ++itTok; 00464 if (itTok->empty() == true) { 00465 return ioBookingRequestStruct; 00466 } 00467 const std::string lDepartureDayString = *itTok; 00468 const bool IsDepartureDateReadable = 00469 retrieveDate (lDepartureYearString, lDepartureMonthString, 00470 lDepartureDayString, lDepartureDate); 00471 00472 if (IsDepartureDateReadable == false) { 00473 std::cerr << "The default booking request and travel solution list are kept." 00474 << std::endl; 00475 return ioBookingRequestStruct; 00476 } 00477 00478 // Read the origin. 00479 ++itTok; 00480 if (itTok->empty() == false) { 00481 lOriginAirport = *itTok; 00482 boost::algorithm::to_upper (lOriginAirport); 00483 } 00484 00485 // Read the destination. 00486 ++itTok; 00487 if (itTok->empty() == false) { 00488 lDestinationAirport = *itTok; 00489 boost::algorithm::to_upper (lDestinationAirport); 00490 } 00491 00492 // Read the departure time. 00493 ++itTok; 00494 if (itTok->empty() == true) { 00495 return ioBookingRequestStruct; 00496 } 00497 const std::string lDepartureHourString = *itTok; 00498 ++itTok; 00499 if (itTok->empty() == true) { 00500 return ioBookingRequestStruct; 00501 } 00502 const std::string lDepartureMinuteString = *itTok; 00503 const bool IsDepartureTimeReadable = 00504 retrieveTime (lDepartureHourString, lDepartureMinuteString, 00505 lDepartureTime); 00506 00507 if (IsDepartureTimeReadable == false) { 00508 std::cerr << "The default booking request and travel solution list are kept." 00509 << std::endl; 00510 return ioBookingRequestStruct; 00511 } 00512 00513 // Read the request date. 00514 ++itTok; 00515 if (itTok->empty() == true) { 00516 return ioBookingRequestStruct; 00517 } 00518 const std::string lRequestYearString = *itTok; 00519 ++itTok; 00520 if (itTok->empty() == true) { 00521 return ioBookingRequestStruct; 00522 } 00523 const std::string lRequestMonthString = *itTok; 00524 ++itTok; 00525 if (itTok->empty() == true) { 00526 return ioBookingRequestStruct; 00527 } 00528 const std::string lRequestDayString = *itTok; 00529 const bool IsRequestDateReadable = 00530 retrieveDate (lRequestYearString, lRequestMonthString, 00531 lRequestDayString, lRequestDate); 00532 00533 if (IsRequestDateReadable == false) { 00534 std::cerr << "The default booking request and travel solution list are kept." 00535 << std::endl; 00536 return ioBookingRequestStruct; 00537 } 00538 00539 // Read the request time. 00540 ++itTok; 00541 if (itTok->empty() == true) { 00542 return ioBookingRequestStruct; 00543 } 00544 const std::string lRequestHourString = *itTok; 00545 ++itTok; 00546 if (itTok->empty() == true) { 00547 return ioBookingRequestStruct; 00548 } 00549 const std::string lRequestMinuteString = *itTok; 00550 const bool IsRequestTimeReadable = 00551 retrieveTime (lRequestHourString, lRequestMinuteString, 00552 lRequestTime); 00553 00554 if (IsRequestTimeReadable == false) { 00555 std::cerr << "The default booking request and travel solution list are kept." 00556 << std::endl; 00557 return ioBookingRequestStruct; 00558 } 00559 00560 // Read the POS. 00561 ++itTok; 00562 if (itTok->empty() == false) { 00563 lPOS = *itTok; 00564 boost::algorithm::to_upper (lPOS); 00565 } 00566 00567 // Read the channel. 00568 ++itTok; 00569 if (itTok->empty() == false) { 00570 lChannel = *itTok; 00571 boost::algorithm::to_upper (lChannel); 00572 } 00573 00574 // Read the trip type. 00575 ++itTok; 00576 if (itTok->empty() == false) { 00577 lTripType = *itTok; 00578 boost::algorithm::to_upper (lTripType); 00579 } 00580 00581 // Read the stay duration. 00582 ++itTok; 00583 if (itTok->empty() == false) { 00584 try { 00585 00586 lStayDuration = boost::lexical_cast<unsigned short> (*itTok); 00587 00588 } catch (boost::bad_lexical_cast& eCast) { 00589 std::cerr << "The stay duration ('" << *itTok 00590 << "') cannot be understood." << std::endl; 00591 return ioBookingRequestStruct; 00592 } 00593 } 00594 00595 // At this step we know that all the parameters designed to construct 00596 // the travel solution and the booking request are correct. 00597 00598 // Empty the travel solution list to store a new travel solution. 00599 ioInteractiveTravelSolutionList.pop_front(); 00600 // Construct the new travel solution. 00601 stdair::TravelSolutionStruct lTravelSolution; 00602 std::ostringstream oStr; 00603 oStr << lAirlineCode 00604 << stdair::DEFAULT_KEY_FLD_DELIMITER 00605 << lflightNumber 00606 << stdair::DEFAULT_KEY_SUB_FLD_DELIMITER 00607 << lDepartureDate 00608 << stdair::DEFAULT_KEY_FLD_DELIMITER 00609 << lOriginAirport 00610 << stdair::DEFAULT_KEY_SUB_FLD_DELIMITER 00611 << lDestinationAirport 00612 << stdair::DEFAULT_KEY_FLD_DELIMITER 00613 << lDepartureTime; 00614 lTravelSolution.addSegment (oStr.str()); 00615 ioInteractiveTravelSolutionList.push_front(lTravelSolution); 00616 00617 // Construct the new booking request. 00618 stdair::DateTime_T lRequestDateTime (lRequestDate, lRequestTime); 00619 const stdair::BookingRequestStruct &lBookingRequestStruct = 00620 stdair::BookingRequestStruct(lOriginAirport, 00621 lDestinationAirport, 00622 lPOS, 00623 lDepartureDate, 00624 lRequestDateTime, 00625 stdair::CABIN_ECO, 00626 stdair::DEFAULT_PARTY_SIZE, 00627 lChannel, 00628 lTripType, 00629 lStayDuration, 00630 stdair::FREQUENT_FLYER_MEMBER, 00631 lDepartureTime, 00632 stdair::DEFAULT_WTP, 00633 stdair::DEFAULT_VALUE_OF_TIME, 00634 true, 50, true, 50); 00635 00636 return lBookingRequestStruct; 00637 } 00638 } 00639 00640 // ////////////////////////////////////////////////////////////////// 00641 // Analyze the tokens of the 'display' command in order to retrieve 00642 // an airport pair and a departure date. 00643 void parseFlightDateKey (const TokenList_T& iTokenList, 00644 stdair::AirportCode_T& ioOrigin, 00645 stdair::AirportCode_T& ioDestination, 00646 stdair::Date_T& ioDepartureDate) { 00647 00648 TokenList_T::const_iterator itTok = iTokenList.begin(); 00649 00650 // Interpret the user input. 00651 if (itTok->empty() == true) { 00652 00653 std::cerr << "Wrong parameters specified. Default paramaters '" 00654 << ioOrigin << "-" << ioDestination 00655 << "/" << ioDepartureDate 00656 << "' are kept." 00657 << std::endl; 00658 00659 } else { 00660 00661 // Read the origin. 00662 ioOrigin = *itTok; 00663 boost::algorithm::to_upper (ioOrigin); 00664 00665 // Read the destination. 00666 ++itTok; 00667 if (itTok->empty() == false) { 00668 ioDestination = *itTok; 00669 boost::algorithm::to_upper (ioDestination); 00670 } 00671 00672 // Read the departure date. 00673 ++itTok; 00674 if (itTok->empty() == true) { 00675 return; 00676 } 00677 std::string lYearString = *itTok; 00678 ++itTok; 00679 if (itTok->empty() == true) { 00680 return; 00681 } 00682 std::string lMonthString = *itTok; 00683 ++itTok; 00684 if (itTok->empty() == true) { 00685 return; 00686 } 00687 std::string lDayString = *itTok; 00688 const bool IsDepartureDateReadable = 00689 retrieveDate (lYearString, lMonthString, lDayString, 00690 ioDepartureDate); 00691 if (IsDepartureDateReadable == false) { 00692 std::cerr << "Default paramaters '" 00693 << ioOrigin << "-" << ioDestination 00694 << "/" << ioDepartureDate 00695 << "' are kept." 00696 << std::endl; 00697 return; 00698 } 00699 } 00700 } 00701 00702 // ///////////////////////////////////////////////////////// 00703 std::string toString (const TokenList_T& iTokenList) { 00704 std::ostringstream oStr; 00705 00706 // Re-create the string with all the tokens, trimmed by read-line 00707 unsigned short idx = 0; 00708 for (TokenList_T::const_iterator itTok = iTokenList.begin(); 00709 itTok != iTokenList.end(); ++itTok, ++idx) { 00710 if (idx != 0) { 00711 oStr << " "; 00712 } 00713 oStr << *itTok; 00714 } 00715 00716 return oStr.str(); 00717 } 00718 00719 // ///////////////////////////////////////////////////////// 00720 TokenList_T extractTokenList (const TokenList_T& iTokenList, 00721 const std::string& iRegularExpression) { 00722 TokenList_T oTokenList; 00723 00724 // Re-create the string with all the tokens (which had been trimmed 00725 // by read-line) 00726 const std::string lFullLine = toString (iTokenList); 00727 00728 // See the caller for the regular expression 00729 boost::regex expression (iRegularExpression); 00730 00731 std::string::const_iterator start = lFullLine.begin(); 00732 std::string::const_iterator end = lFullLine.end(); 00733 00734 boost::match_results<std::string::const_iterator> what; 00735 boost::match_flag_type flags = boost::match_default | boost::format_sed; 00736 regex_search (start, end, what, expression, flags); 00737 00738 // Put the matched strings in the list of tokens to be returned back 00739 // to the caller 00740 const unsigned short lMatchSetSize = what.size(); 00741 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) { 00742 const std::string lMatchedString (std::string (what[matchIdx].first, 00743 what[matchIdx].second)); 00744 //if (lMatchedString.empty() == false) { 00745 oTokenList.push_back (lMatchedString); 00746 //} 00747 } 00748 00749 // DEBUG 00750 // std::cout << "After (token list): " << oTokenList << std::endl; 00751 00752 return oTokenList; 00753 } 00754 00755 // ///////////////////////////////////////////////////////// 00756 // Parse the token list of the 'price' command. 00757 TokenList_T extractTokenListForTSAndBR (const TokenList_T& iTokenList) { 00779 const std::string lRegEx("^([[:alpha:]]{2,3})" 00780 "[[:space:]]+([[:digit:]]{1,4})" 00781 "[/ ]*" 00782 "[[:space:]]+([[:digit:]]{2,4})[/-]?" 00783 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?" 00784 "[[:space:]]*([[:digit:]]{1,2})[[:space:]]*" 00785 "[[:space:]]+([[:alpha:]]{3})" 00786 "[[:space:]]+([[:alpha:]]{3})" 00787 "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})" 00788 "[[:space:]]+([[:digit:]]{2,4})[/-]?" 00789 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?" 00790 "[[:space:]]*([[:digit:]]{1,2})" 00791 "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})" 00792 "[[:space:]]+([[:alpha:]]{3})" 00793 "[[:space:]]+([[:alpha:]]{2})" 00794 "[[:space:]]+([[:alpha:]]{2})" 00795 "[[:space:]]+([[:digit:]]{1})$"); 00796 00797 // 00798 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx); 00799 return oTokenList; 00800 } 00801 00802 // ///////////////////////////////////////////////////////// 00803 // Parse the token list of the 'display' command. 00804 TokenList_T extractTokenListForOriDestDate (const TokenList_T& iTokenList) { 00814 const std::string lRegEx("^([[:alpha:]]{3})" 00815 "[[:space:]]*[/-]?" 00816 "[[:space:]]*([[:alpha:]]{3})" 00817 "[[:space:]]*[/-]?" 00818 "[[:space:]]*([[:digit:]]{2,4})" 00819 "[[:space:]]*[/-]?" 00820 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})" 00821 "[[:space:]]*[/-]?" 00822 "[[:space:]]*([[:digit:]]{1,2})$"); 00823 00824 // 00825 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx); 00826 return oTokenList; 00827 } 00828 00829 // ///////// M A I N //////////// 00830 int main (int argc, char* argv[]) { 00831 00832 // State whether the BOM tree should be built-in or parsed from an 00833 // input file 00834 bool isBuiltin; 00835 00836 // Fare input file name 00837 stdair::Filename_T lFareInputFilename; 00838 00839 // Readline history 00840 const unsigned int lHistorySize (100); 00841 const std::string lHistoryFilename ("simfqt.hist"); 00842 const std::string lHistoryBackupFilename ("simfqt.hist.bak"); 00843 00844 // Default parameters for the interactive session 00845 stdair::AirportCode_T lInteractiveOrigin; 00846 stdair::AirportCode_T lInteractiveDestination; 00847 stdair::Date_T lInteractiveDepartureDate; 00848 00849 // Output log File 00850 stdair::Filename_T lLogFilename; 00851 00852 // Call the command-line option parser 00853 const int lOptionParserStatus = 00854 readConfiguration (argc, argv, isBuiltin, lFareInputFilename, lLogFilename); 00855 00856 if (lOptionParserStatus == K_SIMFQT_EARLY_RETURN_STATUS) { 00857 return 0; 00858 } 00859 00860 // Set the log parameters 00861 std::ofstream logOutputFile; 00862 // Open and clean the log outputfile 00863 logOutputFile.open (lLogFilename.c_str()); 00864 logOutputFile.clear(); 00865 00866 // Initialise the fareQuote service 00867 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile); 00868 SIMFQT::SIMFQT_Service simfqtService (lLogParams); 00869 00870 // DEBUG 00871 STDAIR_LOG_DEBUG ("Welcome to SimFQT display"); 00872 00873 // Check wether or not a (CSV) input file should be read 00874 if (isBuiltin == true) { 00875 // Build the sample BOM tree (filled with fares) for Simfqt 00876 simfqtService.buildSampleBom(); 00877 } else { 00878 // Build the BOM tree from parsing a fare file 00879 SIMFQT::FareFilePath lFareFilePath (lFareInputFilename); 00880 simfqtService.parseAndLoad (lFareFilePath); 00881 } 00882 00883 // DEBUG: Display the whole BOM tree 00884 const std::string& lCSVDump = simfqtService.csvDisplay(); 00885 STDAIR_LOG_DEBUG (lCSVDump); 00886 00887 // DEBUG 00888 STDAIR_LOG_DEBUG ("===================================================="); 00889 STDAIR_LOG_DEBUG ("= Beginning of the interactive session ="); 00890 STDAIR_LOG_DEBUG ("===================================================="); 00891 00892 // Initialise the GNU readline wrapper 00893 swift::SReadline lReader (lHistoryFilename, lHistorySize); 00894 initReadline (lReader); 00895 00896 // Now we can ask user for a line 00897 std::string lUserInput; 00898 bool EndOfInput (false); 00899 Command_T::Type_T lCommandType (Command_T::NOP); 00900 00901 while (lCommandType != Command_T::QUIT && EndOfInput == false) { 00902 00903 stdair::TravelSolutionList_T lInteractiveTravelSolutionList; 00904 stdair::TravelSolutionStruct lInteractiveTravelSolution; 00905 00906 // Update the default booking request. 00907 // If there is an input file, we want the CRS booking request (defined in stdair). 00908 // If not, we want the default booking request. 00909 const bool isCRSBookingRequest = !isBuiltin; 00910 const stdair::BookingRequestStruct& lInteractiveBookingRequest = 00911 simfqtService.buildBookingRequest (isCRSBookingRequest); 00912 00913 // Update the default parameters for the following interactive session. 00914 if (isBuiltin == true) { 00915 lInteractiveOrigin = "LHR"; 00916 lInteractiveDestination = "SYD"; 00917 lInteractiveDepartureDate = stdair::Date_T(2011,06,10); 00918 simfqtService.buildSampleTravelSolutions (lInteractiveTravelSolutionList); 00919 } else { 00920 lInteractiveOrigin = "SIN"; 00921 lInteractiveDestination = "BKK"; 00922 lInteractiveDepartureDate = stdair::Date_T(2010,01,30); 00923 // 00924 const std::string lBA9_SegmentDateKey ("SQ, 970, 2010-01-30, SIN, BKK, 07:10"); 00925 00926 // Add the segment date key to the travel solution. 00927 lInteractiveTravelSolution.addSegment (lBA9_SegmentDateKey); 00928 00929 // Add the travel solution to the list 00930 lInteractiveTravelSolutionList.push_back (lInteractiveTravelSolution); 00931 } 00932 00933 // Prompt. 00934 std::ostringstream oPromptStr; 00935 oPromptStr << "simfqt " 00936 << "> "; 00937 // The last parameter could be ommited. 00938 TokenList_T lTokenListByReadline; 00939 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline, 00940 EndOfInput); 00941 00942 // The history could be saved to an arbitrary file at any time. 00943 lReader.SaveHistory (lHistoryBackupFilename); 00944 00945 if (EndOfInput) { 00946 std::cout << std::endl; 00947 break; 00948 } 00949 00950 // Interpret the user input. 00951 lCommandType = extractCommand (lTokenListByReadline); 00952 00953 switch (lCommandType) { 00954 00955 // ////////////////////////////// Help //////////////////////// 00956 case Command_T::HELP: { 00957 // Search for information to display default parameters lists. 00958 // Get the first travel solution. 00959 stdair::TravelSolutionStruct& lTravelSolutionStruct = 00960 lInteractiveTravelSolutionList.front(); 00961 // Get the segment-path of the first travel solution. 00962 const stdair::SegmentPath_T& lSegmentPath = 00963 lTravelSolutionStruct.getSegmentPath(); 00964 // Get the first segment of the first travel solution. 00965 const std::string& lSegmentDateKey = lSegmentPath.front(); 00966 // Get the parsed key of the first segment of the first travel solution. 00967 const stdair::ParsedKey& lParsedKey = 00968 stdair::BomKeyManager::extractKeys (lSegmentDateKey); 00969 // Get the request date time 00970 const stdair::DateTime_T& lRequestDateTime = 00971 lInteractiveBookingRequest.getRequestDateTime(); 00972 const stdair::Time_T lRequestTime = 00973 lRequestDateTime.time_of_day(); 00974 std::cout << std::endl; 00975 // Display help. 00976 std::cout << "Commands: " << std::endl; 00977 std::cout << " help" << "\t\t" << "Display this help" << std::endl; 00978 std::cout << " quit" << "\t\t" << "Quit the application" << std::endl; 00979 std::cout << " list" << "\t\t" 00980 << "List all the fare rule O&Ds and the corresponding date ranges" << std::endl; 00981 std::cout << " display" << "\t" 00982 << "Display all fare rules for an O&D and a departure date. \n" << "\t\t" 00983 << "If no parameters specified or wrong list of parameters, default values are used: \n"<< "\t\t" 00984 << " display " << lInteractiveOrigin << " " 00985 << lInteractiveDestination << " " 00986 << lInteractiveDepartureDate << std::endl; 00987 std::cout << " price" << "\t\t" 00988 << "Price the travel solution corresponding to a booking request. \n" << "\t\t" 00989 << "If no parameters specified or wrong list of parameters, default value are used: \n" << "\t\t" 00990 << " price " 00991 << lParsedKey._airlineCode << " " 00992 << lParsedKey._flightNumber << " " 00993 << lParsedKey._departureDate << " " 00994 << lParsedKey._boardingPoint << " " 00995 << lParsedKey._offPoint << " " 00996 << lParsedKey._boardingTime << " " 00997 << lRequestDateTime.date() << " " 00998 << lRequestTime.hours() << ":" << lRequestTime.minutes() << " " 00999 << lInteractiveBookingRequest.getPOS() << " " 01000 << lInteractiveBookingRequest.getBookingChannel() << " " 01001 << lInteractiveBookingRequest.getTripType() << " " 01002 << lInteractiveBookingRequest.getStayDuration() << std::endl; 01003 std::cout << std::endl; 01004 break; 01005 } 01006 01007 // ////////////////////////////// Quit //////////////////////// 01008 case Command_T::QUIT: { 01009 break; 01010 } 01011 01012 // ////////////////////////////// List ///////////////////////// 01013 case Command_T::LIST: { 01014 01015 // Get the list of all airport pairs and date ranges for which 01016 // there are fares available. 01017 const std::string& lAirportPairDateListStr = 01018 simfqtService.list (); 01019 01020 if (lAirportPairDateListStr.empty() == false) { 01021 std::cout << lAirportPairDateListStr << std::endl; 01022 STDAIR_LOG_DEBUG (lAirportPairDateListStr); 01023 01024 } else { 01025 std::cerr << "There is no result for airport pairs and date ranges." 01026 << "Make sure your input file is not empty." 01027 << std::endl; 01028 } 01029 01030 break; 01031 } 01032 01033 // ////////////////////////////// Display ///////////////////////// 01034 case Command_T::DISPLAY: { 01035 01036 // If no parameters are entered by the user, keep default ones. 01037 if (lTokenListByReadline.empty() == true) { 01038 01039 std::cout << "No parameters specified. Default paramaters '" 01040 << lInteractiveOrigin << "-" << lInteractiveDestination 01041 << "/" << lInteractiveDepartureDate 01042 << "' are kept." 01043 << std::endl; 01044 01045 } else { 01046 01047 // Find the best match corresponding to the given parameters. 01048 TokenList_T lTokenList = 01049 extractTokenListForOriDestDate (lTokenListByReadline); 01050 01051 // Parse the best match, and give default values in case the 01052 // user does not specify all the parameters or does not 01053 // specify some of them correctly. 01054 parseFlightDateKey (lTokenList, lInteractiveOrigin, 01055 lInteractiveDestination, lInteractiveDepartureDate); 01056 01057 } 01058 01059 // Check whether the selected airportpair-date is valid: 01060 // i.e. if there are corresponding fare rules. 01061 const bool isAirportPairDateValid = 01062 simfqtService.check (lInteractiveOrigin, lInteractiveDestination, 01063 lInteractiveDepartureDate); 01064 01065 if (isAirportPairDateValid == false) { 01066 std::ostringstream oFDKStr; 01067 oFDKStr << "The airport pair/departure date: " 01068 << lInteractiveOrigin << "-" << lInteractiveDestination 01069 << "/" << lInteractiveDepartureDate 01070 << " does not correpond to any fare rule.\n" 01071 << "Make sure it exists with the 'list' command."; 01072 std::cout << oFDKStr.str() << std::endl; 01073 STDAIR_LOG_ERROR (oFDKStr.str()); 01074 01075 break; 01076 } 01077 01078 // Display the list of corresponding fare rules. 01079 std::cout << "List of fare rules for " 01080 << lInteractiveOrigin << "-" 01081 << lInteractiveDestination << "/" 01082 << lInteractiveDepartureDate 01083 << std::endl; 01084 01085 const std::string& lFareRuleListStr = 01086 simfqtService.csvDisplay (lInteractiveOrigin, 01087 lInteractiveDestination, 01088 lInteractiveDepartureDate); 01089 01090 assert (lFareRuleListStr.empty() == false); 01091 std::cout << lFareRuleListStr << std::endl; 01092 STDAIR_LOG_DEBUG (lFareRuleListStr); 01093 01094 break; 01095 } 01096 01097 // ////////////////////////////// Price //////////////////////// 01098 case Command_T::PRICE: { 01099 01100 // If no parameters are entered by the user, keep default ones. 01101 if (lTokenListByReadline.empty() == true) { 01102 01103 lInteractiveTravelSolution = lInteractiveTravelSolutionList.front(); 01104 01105 std::cout << "No parameters specified. Default booking request and default travel solution list are kept.\n" 01106 << "Booking request: << " 01107 << lInteractiveBookingRequest.display() << " >>" 01108 << "\nTravel Solution: << " 01109 << lInteractiveTravelSolution.display() << " >>" 01110 << "\n********** \n" 01111 << "Fare quote" 01112 << "\n**********" 01113 << std::endl; 01114 01115 // Try to fareQuote the sample list of travel solutions. 01116 try { 01117 simfqtService.quotePrices (lInteractiveBookingRequest, 01118 lInteractiveTravelSolutionList); 01119 } catch (stdair::ObjectNotFoundException& E) { 01120 std::cerr << "The given travel solution corresponding to the given booking request can not be priced.\n" 01121 << E.what() 01122 << std::endl; 01123 break; 01124 } 01125 } else { 01126 01127 // Find the best match corresponding to the given parameters. 01128 TokenList_T lTokenList = 01129 extractTokenListForTSAndBR (lTokenListByReadline); 01130 01131 // Parse the best match, and give default values in case the 01132 // user does not specify all the parameters or does not 01133 // specify some of them correctly. 01134 stdair::BookingRequestStruct lFinalBookingRequest 01135 = parseTravelSolutionAndBookingRequestKey (lTokenList, 01136 lInteractiveTravelSolutionList, 01137 lInteractiveBookingRequest); 01138 01139 01140 assert (lInteractiveTravelSolutionList.size() >= 1); 01141 lInteractiveTravelSolution = lInteractiveTravelSolutionList.front(); 01142 01143 // Display the booking request and the first travel solution 01144 // before pricing. 01145 std::cout << "Booking request: << " 01146 << lFinalBookingRequest.display() << " >>" 01147 << "\nTravel Solution: << " 01148 << lInteractiveTravelSolution.display() << " >>" 01149 << "\n********** \n" 01150 << "Fare quote" 01151 << "\n**********" 01152 << std::endl; 01153 01154 // Try to fareQuote the sample list of travel solutions. 01155 try { 01156 simfqtService.quotePrices (lFinalBookingRequest, 01157 lInteractiveTravelSolutionList); 01158 } catch (stdair::ObjectNotFoundException& E) { 01159 std::cerr << "The given travel solution corresponding to the given booking request can not be priced.\n" 01160 << E.what() 01161 << std::endl; 01162 break; 01163 } 01164 } 01165 01166 // Display the first travel solution after pricing: 01167 // one or more fare option have been added. 01168 lInteractiveTravelSolution = lInteractiveTravelSolutionList.front(); 01169 std::cout << "Travel Solution: << " 01170 << lInteractiveTravelSolution.display() << " >>\n" 01171 << std::endl; 01172 01173 break; 01174 } 01175 01176 // /////////////////////////// Default / No value /////////////////////// 01177 case Command_T::NOP: { 01178 break; 01179 } 01180 case Command_T::LAST_VALUE: 01181 default: { 01182 // DEBUG 01183 std::ostringstream oStr; 01184 oStr << "The '" << lUserInput << "' command is not yet understood.\n" 01185 << "Type help to have more information." << std::endl; 01186 01187 STDAIR_LOG_DEBUG (oStr.str()); 01188 std::cout << oStr.str() << std::endl; 01189 } 01190 } 01191 } 01192 01193 // DEBUG 01194 STDAIR_LOG_DEBUG ("End of the session. Exiting."); 01195 std::cout << "End of the session. Exiting." << std::endl; 01196 01197 // Close the Log outputFile 01198 logOutputFile.close(); 01199 01200 /* 01201 Note: as that program is not intended to be run on a server in 01202 production, it is better not to catch the exceptions. When it 01203 happens (that an exception is throwned), that way we get the 01204 call stack. 01205 */ 01206 01207 return 0; 01208 }