SimFQT Logo  0.1.3
C++ Simulated Fare Quote System Library
simfqt.cpp
Go to the documentation of this file.
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 
00635     return lBookingRequestStruct;
00636   }
00637 }
00638 
00639 // //////////////////////////////////////////////////////////////////
00640 // Analyze the tokens of the 'display' command in order to retrieve
00641 // an airport pair and a departure date.
00642 void parseFlightDateKey (const TokenList_T& iTokenList,
00643                          stdair::AirportCode_T& ioOrigin,
00644                          stdair::AirportCode_T& ioDestination,
00645                          stdair::Date_T& ioDepartureDate) {
00646 
00647   TokenList_T::const_iterator itTok = iTokenList.begin();
00648   
00649   // Interpret the user input.
00650   if (itTok->empty() == true) {
00651 
00652     std::cerr << "Wrong parameters specified. Default paramaters '" 
00653               << ioOrigin << "-" << ioDestination
00654               << "/" << ioDepartureDate
00655               << "' are kept."
00656              << std::endl;
00657 
00658   } else {
00659     
00660     // Read the origin.
00661     ioOrigin = *itTok;
00662     boost::algorithm::to_upper (ioOrigin);
00663 
00664     // Read the destination.
00665     ++itTok;
00666     if (itTok->empty() == false) {
00667       ioDestination  = *itTok;
00668       boost::algorithm::to_upper (ioDestination);
00669     }
00670 
00671     // Read the departure date.
00672     ++itTok;
00673     if (itTok->empty() == true) {
00674       return;
00675     }
00676     std::string lYearString = *itTok;
00677     ++itTok;
00678     if (itTok->empty() == true) {
00679       return;
00680     }
00681     std::string lMonthString = *itTok;
00682     ++itTok;
00683     if (itTok->empty() == true) {
00684       return;
00685     }
00686     std::string lDayString = *itTok;
00687     const bool IsDepartureDateReadable =
00688       retrieveDate (lYearString, lMonthString, lDayString,
00689                     ioDepartureDate);
00690     if (IsDepartureDateReadable == false) {
00691       std::cerr << "Default paramaters '" 
00692                 << ioOrigin << "-" << ioDestination
00693                 << "/" << ioDepartureDate
00694                 << "' are kept." 
00695                 << std::endl;
00696       return;
00697     }
00698   }
00699 }
00700 
00701 // /////////////////////////////////////////////////////////
00702 std::string toString (const TokenList_T& iTokenList) {
00703   std::ostringstream oStr;
00704 
00705   // Re-create the string with all the tokens, trimmed by read-line
00706   unsigned short idx = 0;
00707   for (TokenList_T::const_iterator itTok = iTokenList.begin();
00708        itTok != iTokenList.end(); ++itTok, ++idx) {
00709     if (idx != 0) {
00710       oStr << " ";
00711     }
00712     oStr << *itTok;
00713   }
00714 
00715   return oStr.str();
00716 }
00717 
00718 // /////////////////////////////////////////////////////////
00719 TokenList_T extractTokenList (const TokenList_T& iTokenList,
00720                               const std::string& iRegularExpression) {
00721   TokenList_T oTokenList;
00722 
00723   // Re-create the string with all the tokens (which had been trimmed
00724   // by read-line)
00725   const std::string lFullLine = toString (iTokenList);
00726 
00727   // See the caller for the regular expression
00728   boost::regex expression (iRegularExpression);
00729   
00730   std::string::const_iterator start = lFullLine.begin();
00731   std::string::const_iterator end = lFullLine.end();
00732 
00733   boost::match_results<std::string::const_iterator> what;
00734   boost::match_flag_type flags = boost::match_default | boost::format_sed; 
00735   regex_search (start, end, what, expression, flags);
00736   
00737   // Put the matched strings in the list of tokens to be returned back
00738   // to the caller
00739   const unsigned short lMatchSetSize = what.size();
00740   for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
00741     const std::string lMatchedString (std::string (what[matchIdx].first,
00742                                                    what[matchIdx].second));
00743     //if (lMatchedString.empty() == false) {
00744     oTokenList.push_back (lMatchedString);
00745     //}
00746   }
00747 
00748   // DEBUG
00749   // std::cout << "After (token list): " << oTokenList << std::endl;
00750 
00751   return oTokenList;
00752 }
00753 
00754 // /////////////////////////////////////////////////////////
00755 // Parse the token list of the 'price' command.
00756 TokenList_T extractTokenListForTSAndBR (const TokenList_T& iTokenList) {
00778   const std::string lRegEx("^([[:alpha:]]{2,3})"
00779                            "[[:space:]]+([[:digit:]]{1,4})"
00780                            "[/ ]*"
00781                            "[[:space:]]+([[:digit:]]{2,4})[/-]?"
00782                            "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?"
00783                            "[[:space:]]*([[:digit:]]{1,2})[[:space:]]*"
00784                            "[[:space:]]+([[:alpha:]]{3})"
00785                            "[[:space:]]+([[:alpha:]]{3})"
00786                            "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})"
00787                            "[[:space:]]+([[:digit:]]{2,4})[/-]?"
00788                            "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?"
00789                            "[[:space:]]*([[:digit:]]{1,2})"
00790                            "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})"
00791                            "[[:space:]]+([[:alpha:]]{3})"
00792                            "[[:space:]]+([[:alpha:]]{2})"
00793                            "[[:space:]]+([[:alpha:]]{2})"
00794                            "[[:space:]]+([[:digit:]]{1})$");
00795 
00796   //
00797   const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
00798   return oTokenList;
00799 } 
00800 
00801 // /////////////////////////////////////////////////////////
00802 // Parse the token list of the 'display' command.
00803 TokenList_T extractTokenListForOriDestDate (const TokenList_T& iTokenList) {
00813   const std::string lRegEx("^([[:alpha:]]{3})"
00814                            "[[:space:]]*[/-]?"
00815                            "[[:space:]]*([[:alpha:]]{3})"
00816                            "[[:space:]]*[/-]?"
00817                            "[[:space:]]*([[:digit:]]{2,4})"
00818                            "[[:space:]]*[/-]?"
00819                            "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})"
00820                            "[[:space:]]*[/-]?"
00821                            "[[:space:]]*([[:digit:]]{1,2})$");
00822 
00823   //
00824   const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
00825   return oTokenList;
00826 }
00827 
00828 // ///////// M A I N ////////////
00829 int main (int argc, char* argv[]) {
00830 
00831   // State whether the BOM tree should be built-in or parsed from an
00832   // input file
00833   bool isBuiltin;
00834 
00835   // Fare input file name
00836   stdair::Filename_T lFareInputFilename;
00837 
00838   // Readline history
00839   const unsigned int lHistorySize (100);
00840   const std::string lHistoryFilename ("simfqt.hist");
00841   const std::string lHistoryBackupFilename ("simfqt.hist.bak");
00842 
00843   // Default parameters for the interactive session
00844   stdair::AirportCode_T lInteractiveOrigin;
00845   stdair::AirportCode_T lInteractiveDestination;
00846   stdair::Date_T lInteractiveDepartureDate;
00847 
00848   // Output log File
00849   stdair::Filename_T lLogFilename;
00850 
00851   // Call the command-line option parser
00852   const int lOptionParserStatus =
00853     readConfiguration (argc, argv, isBuiltin, lFareInputFilename, lLogFilename);
00854 
00855   if (lOptionParserStatus == K_SIMFQT_EARLY_RETURN_STATUS) {
00856     return 0;
00857   }
00858 
00859   // Set the log parameters
00860   std::ofstream logOutputFile;
00861   // Open and clean the log outputfile
00862   logOutputFile.open (lLogFilename.c_str());
00863   logOutputFile.clear();
00864 
00865   // Initialise the fareQuote service
00866   const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile); 
00867   SIMFQT::SIMFQT_Service simfqtService (lLogParams);
00868 
00869   // DEBUG
00870   STDAIR_LOG_DEBUG ("Welcome to SimFQT display");
00871 
00872   // Check wether or not a (CSV) input file should be read
00873   if (isBuiltin == true) {
00874     // Build the sample BOM tree (filled with fares) for Simfqt
00875     simfqtService.buildSampleBom();
00876   } else {
00877     // Build the BOM tree from parsing a fare file
00878     SIMFQT::FareFilePath lFareFilePath (lFareInputFilename);
00879     simfqtService.parseAndLoad (lFareFilePath);
00880   }
00881 
00882   // DEBUG: Display the whole BOM tree
00883   const std::string& lCSVDump = simfqtService.csvDisplay();
00884   STDAIR_LOG_DEBUG (lCSVDump);
00885 
00886   // DEBUG
00887   STDAIR_LOG_DEBUG ("====================================================");
00888   STDAIR_LOG_DEBUG ("=       Beginning of the interactive session       =");
00889   STDAIR_LOG_DEBUG ("====================================================");
00890 
00891   // Initialise the GNU readline wrapper
00892   swift::SReadline lReader (lHistoryFilename, lHistorySize);
00893   initReadline (lReader);
00894 
00895   // Now we can ask user for a line
00896   std::string lUserInput;
00897   bool EndOfInput (false);
00898   Command_T::Type_T lCommandType (Command_T::NOP);
00899   
00900   while (lCommandType != Command_T::QUIT && EndOfInput == false) {
00901 
00902     stdair::TravelSolutionList_T lInteractiveTravelSolutionList;
00903     stdair::TravelSolutionStruct lInteractiveTravelSolution;
00904 
00905     // Update the default booking request.
00906     // If there is an input file, we want the CRS booking request (defined in stdair).
00907     // If not, we want the default booking request.
00908     const bool isCRSBookingRequest = !isBuiltin;
00909     const stdair::BookingRequestStruct& lInteractiveBookingRequest =
00910       simfqtService.buildBookingRequest (isCRSBookingRequest);
00911 
00912     // Update the default parameters for the following interactive session.
00913     if (isBuiltin == true) {
00914       lInteractiveOrigin = "LHR";
00915       lInteractiveDestination = "SYD";
00916       lInteractiveDepartureDate = stdair::Date_T(2011,06,10);
00917       simfqtService.buildSampleTravelSolutions (lInteractiveTravelSolutionList);
00918     } else {
00919       lInteractiveOrigin = "SIN";
00920       lInteractiveDestination = "BKK";
00921       lInteractiveDepartureDate = stdair::Date_T(2010,01,30);
00922       //
00923       const std::string lBA9_SegmentDateKey ("SQ, 970, 2010-01-30, SIN, BKK, 07:10");
00924       
00925       // Add the segment date key to the travel solution.
00926       lInteractiveTravelSolution.addSegment (lBA9_SegmentDateKey);
00927 
00928       // Add the travel solution to the list
00929       lInteractiveTravelSolutionList.push_back (lInteractiveTravelSolution);
00930     }
00931     
00932     // Prompt.
00933     std::ostringstream oPromptStr;
00934     oPromptStr << "simfqt "
00935                << "> ";
00936     // The last parameter could be ommited.
00937     TokenList_T lTokenListByReadline;
00938     lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
00939                                   EndOfInput);
00940 
00941     // The history could be saved to an arbitrary file at any time.
00942     lReader.SaveHistory (lHistoryBackupFilename);
00943 
00944     if (EndOfInput) {
00945       std::cout << std::endl;
00946       break;
00947     }
00948 
00949     // Interpret the user input.
00950     lCommandType = extractCommand (lTokenListByReadline);
00951     
00952     switch (lCommandType) {
00953 
00954       // ////////////////////////////// Help ////////////////////////
00955     case Command_T::HELP: {
00956       // Search for information to display default parameters lists.
00957       // Get the first travel solution.
00958       stdair::TravelSolutionStruct& lTravelSolutionStruct =
00959         lInteractiveTravelSolutionList.front();  
00960       // Get the segment-path of the first travel solution.
00961       const stdair::SegmentPath_T& lSegmentPath =
00962         lTravelSolutionStruct.getSegmentPath();  
00963       // Get the first segment of the first travel solution.
00964       const std::string& lSegmentDateKey = lSegmentPath.front();
00965       // Get the parsed key of the first segment of the first travel solution.
00966       const stdair::ParsedKey& lParsedKey =
00967         stdair::BomKeyManager::extractKeys (lSegmentDateKey);
00968       // Get the request date time
00969       const stdair::DateTime_T& lRequestDateTime =
00970         lInteractiveBookingRequest.getRequestDateTime();
00971       const stdair::Time_T lRequestTime =
00972         lRequestDateTime.time_of_day();
00973       std::cout << std::endl;
00974       // Display help.
00975       std::cout << "Commands: " << std::endl;
00976       std::cout << " help" << "\t\t" << "Display this help" << std::endl;
00977       std::cout << " quit" << "\t\t" << "Quit the application" << std::endl;
00978       std::cout << " list" << "\t\t"
00979                 << "List all the fare rule O&Ds and the corresponding date ranges" << std::endl;
00980       std::cout << " display" << "\t"
00981                 << "Display all fare rules for an O&D and a departure date. \n" << "\t\t"
00982                 << "If no parameters specified or wrong list of parameters, default values are used: \n"<< "\t\t"
00983                 << "      display " <<  lInteractiveOrigin << " "
00984                 << lInteractiveDestination << " "
00985                 << lInteractiveDepartureDate << std::endl;
00986       std::cout << " price" << "\t\t"
00987                 << "Price the travel solution corresponding to a booking request. \n" << "\t\t"
00988                 << "If no parameters specified or wrong list of parameters, default value are used: \n" << "\t\t"
00989                 << "      price "
00990                 << lParsedKey._airlineCode << " "
00991                 << lParsedKey._flightNumber << " "
00992                 << lParsedKey._departureDate << " "
00993                 << lParsedKey._boardingPoint << " "
00994                 << lParsedKey._offPoint << " "
00995                 << lParsedKey._boardingTime << " "
00996                 << lRequestDateTime.date() << " "
00997                 << lRequestTime.hours() << ":" << lRequestTime.minutes() << " " 
00998                 << lInteractiveBookingRequest.getPOS() << " "
00999                 << lInteractiveBookingRequest.getBookingChannel() << " " 
01000                 << lInteractiveBookingRequest.getTripType() << " "
01001                 << lInteractiveBookingRequest.getStayDuration() << std::endl;
01002       std::cout << std::endl;
01003       break;
01004     }
01005       
01006       // ////////////////////////////// Quit ////////////////////////
01007     case Command_T::QUIT: {
01008       break;
01009     }
01010 
01011       // ////////////////////////////// List /////////////////////////
01012     case Command_T::LIST: {
01013       
01014       // Get the list of all airport pairs and date ranges for which
01015       // there are fares available.
01016       const std::string& lAirportPairDateListStr =
01017         simfqtService.list ();
01018 
01019       if (lAirportPairDateListStr.empty() == false) {
01020         std::cout << lAirportPairDateListStr << std::endl;
01021         STDAIR_LOG_DEBUG (lAirportPairDateListStr);
01022 
01023       } else {
01024         std::cerr << "There is no result for airport pairs and date ranges."
01025                   << "Make sure your input file is not empty."
01026                   << std::endl;
01027       }
01028 
01029       break;
01030     }
01031 
01032       // ////////////////////////////// Display /////////////////////////
01033     case Command_T::DISPLAY: {
01034 
01035       // If no parameters are entered by the user, keep default ones.
01036       if (lTokenListByReadline.empty() == true) {
01037 
01038         std::cout << "No parameters specified. Default paramaters '" 
01039                   << lInteractiveOrigin << "-" << lInteractiveDestination
01040                   << "/" << lInteractiveDepartureDate
01041                   << "' are kept."
01042                   << std::endl;
01043 
01044       } else {
01045 
01046         // Find the best match corresponding to the given parameters.
01047         TokenList_T lTokenList =
01048           extractTokenListForOriDestDate (lTokenListByReadline);
01049         
01050         // Parse the best match, and give default values in case the
01051         // user does not specify all the parameters or does not
01052         // specify some of them correctly.
01053         parseFlightDateKey (lTokenList, lInteractiveOrigin,
01054                             lInteractiveDestination, lInteractiveDepartureDate);
01055         
01056       }
01057 
01058       // Check whether the selected airportpair-date is valid:
01059       // i.e. if there are corresponding fare rules.
01060       const bool isAirportPairDateValid =
01061         simfqtService.check (lInteractiveOrigin, lInteractiveDestination,
01062                              lInteractiveDepartureDate);
01063 
01064       if (isAirportPairDateValid == false) {
01065         std::ostringstream oFDKStr;
01066         oFDKStr << "The airport pair/departure date: "
01067                 << lInteractiveOrigin << "-" << lInteractiveDestination
01068                 << "/" << lInteractiveDepartureDate
01069                 << " does not correpond to any fare rule.\n"
01070                 << "Make sure it exists with the 'list' command.";
01071         std::cout << oFDKStr.str() << std::endl;
01072         STDAIR_LOG_ERROR (oFDKStr.str());
01073 
01074         break;
01075       }
01076       
01077       // Display the list of corresponding fare rules.
01078       std::cout << "List of fare rules for "
01079                 << lInteractiveOrigin << "-"
01080                 << lInteractiveDestination << "/"
01081                 << lInteractiveDepartureDate 
01082                 << std::endl;
01083 
01084       const std::string& lFareRuleListStr =
01085         simfqtService.csvDisplay (lInteractiveOrigin,
01086                                   lInteractiveDestination,
01087                                   lInteractiveDepartureDate);
01088 
01089       assert (lFareRuleListStr.empty() == false);
01090       std::cout << lFareRuleListStr << std::endl;
01091       STDAIR_LOG_DEBUG (lFareRuleListStr);
01092 
01093       break;
01094     }
01095       
01096       // ////////////////////////////// Price ////////////////////////
01097     case Command_T::PRICE: {
01098 
01099       // If no parameters are entered by the user, keep default ones.
01100       if (lTokenListByReadline.empty() == true) {
01101 
01102         lInteractiveTravelSolution = lInteractiveTravelSolutionList.front();
01103         
01104         std::cout << "No parameters specified. Default booking request and default travel solution list are kept.\n"
01105                   << "Booking request: << "
01106                   << lInteractiveBookingRequest.display()  << " >>"
01107                   << "\nTravel Solution: << "
01108                   << lInteractiveTravelSolution.display() << " >>"
01109                   << "\n********** \n"
01110                   << "Fare quote"
01111                   << "\n**********"
01112                 << std::endl;
01113         
01114         // Try to fareQuote the sample list of travel solutions.
01115         try {
01116         simfqtService.quotePrices (lInteractiveBookingRequest,
01117                                    lInteractiveTravelSolutionList);
01118         } catch (stdair::ObjectNotFoundException& E) {
01119           std::cerr << "The given travel solution corresponding to the given booking request can not be priced.\n"
01120                     << E.what()
01121                     << std::endl;
01122           break;
01123         }
01124       } else {
01125       
01126         // Find the best match corresponding to the given parameters.
01127         TokenList_T lTokenList =
01128           extractTokenListForTSAndBR (lTokenListByReadline);
01129 
01130         // Parse the best match, and give default values in case the
01131         // user does not specify all the parameters or does not
01132         // specify some of them correctly.
01133         stdair::BookingRequestStruct lFinalBookingRequest
01134           = parseTravelSolutionAndBookingRequestKey (lTokenList,
01135                                                      lInteractiveTravelSolutionList,
01136                                                      lInteractiveBookingRequest);
01137 
01138         
01139         assert (lInteractiveTravelSolutionList.size() >= 1);
01140         lInteractiveTravelSolution = lInteractiveTravelSolutionList.front();
01141 
01142         // Display the booking request and the first travel solution
01143         // before pricing.
01144         std::cout << "Booking request: << "
01145                   << lFinalBookingRequest.display()  << " >>"
01146                   << "\nTravel Solution: << "
01147                   << lInteractiveTravelSolution.display() << " >>"
01148                   << "\n********** \n"
01149                   << "Fare quote"
01150                   << "\n**********"
01151                 << std::endl;
01152         
01153         // Try to fareQuote the sample list of travel solutions.
01154         try {
01155           simfqtService.quotePrices (lFinalBookingRequest,
01156                                      lInteractiveTravelSolutionList);
01157         } catch (stdair::ObjectNotFoundException& E) {
01158           std::cerr << "The given travel solution corresponding to the given booking request can not be priced.\n"
01159                     << E.what()
01160                     << std::endl;
01161           break;
01162         }
01163       }
01164 
01165       // Display the first travel solution after pricing:
01166       // one or more fare option have been added.
01167       lInteractiveTravelSolution = lInteractiveTravelSolutionList.front();
01168       std::cout << "Travel Solution: << "
01169                 << lInteractiveTravelSolution.display() << " >>\n"
01170                 << std::endl;
01171 
01172       break;
01173     }
01174       
01175       // /////////////////////////// Default / No value ///////////////////////
01176     case Command_T::NOP: {
01177       break;
01178     } 
01179     case Command_T::LAST_VALUE:
01180     default: {
01181       // DEBUG
01182       std::ostringstream oStr;
01183       oStr << "The '" << lUserInput << "' command is not yet understood.\n"
01184            << "Type help to have more information." << std::endl;
01185 
01186       STDAIR_LOG_DEBUG (oStr.str());
01187       std::cout << oStr.str() << std::endl;
01188     }
01189     }
01190   }
01191 
01192   // DEBUG
01193   STDAIR_LOG_DEBUG ("End of the session. Exiting.");
01194   std::cout << "End of the session. Exiting." << std::endl;
01195 
01196   // Close the Log outputFile
01197   logOutputFile.close();
01198 
01199   /*
01200     Note: as that program is not intended to be run on a server in
01201     production, it is better not to catch the exceptions. When it
01202     happens (that an exception is throwned), that way we get the
01203     call stack.
01204   */
01205 
01206   return 0;     
01207 }
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines