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