$treeview $search $mathjax
AirInv Logo  1.00.1
$projectbrief
$projectbrief
$searchbox

airinv.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 #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 }