AirInv Logo  1.00.8
C++ Simulated Airline Inventory Management System Library
Loading...
Searching...
No Matches
airinv.cpp
Go to the documentation of this file.
1
5// STL
6#include <cassert>
7#include <iostream>
8#include <sstream>
9#include <fstream>
10#include <string>
11// Boost (Extended STL)
12#include <boost/program_options.hpp>
13#include <boost/tokenizer.hpp>
14#include <boost/regex.hpp>
15#include <boost/swap.hpp>
16#include <boost/algorithm/string/case_conv.hpp>
17// StdAir
18#include <stdair/basic/BasLogParams.hpp>
19#include <stdair/basic/BasDBParams.hpp>
20#include <stdair/service/Logger.hpp>
21#include <stdair/stdair_json.hpp>
22// GNU Readline Wrapper
23#include <stdair/ui/cmdline/SReadline.hpp>
24// AirInv
26#include <airinv/config/airinv-paths.hpp>
27
28// //////// Constants //////
32const std::string K_AIRINV_DEFAULT_LOG_FILENAME ("airinv.log");
33
37const std::string K_AIRINV_DEFAULT_INVENTORY_FILENAME (STDAIR_SAMPLE_DIR
38 "/invdump01.csv");
42const std::string K_AIRINV_DEFAULT_SCHEDULE_FILENAME (STDAIR_SAMPLE_DIR
43 "/schedule01.csv");
47const std::string K_AIRINV_DEFAULT_OND_FILENAME (STDAIR_SAMPLE_DIR
48 "/ond01.csv");
52const std::string K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME (STDAIR_SAMPLE_DIR
53 "/frat5.csv");
57const std::string K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME (STDAIR_SAMPLE_DIR
58 "/ffDisutility.csv");
62const std::string K_AIRINV_DEFAULT_YIELD_FILENAME (STDAIR_SAMPLE_DIR
63 "/yieldstore01.csv");
64
69const bool K_AIRINV_DEFAULT_BUILT_IN_INPUT = false;
70
75const bool K_AIRINV_DEFAULT_FOR_SCHEDULE = false;
76
80const int K_AIRINV_EARLY_RETURN_STATUS = 99;
81
86typedef std::vector<std::string> TokenList_T;
87
91struct Command_T {
92 typedef enum {
93 NOP = 0,
94 QUIT,
95 HELP,
96 LIST,
97 DISPLAY,
98 SELECT,
99 SELL,
100 JSON_LIST,
101 JSON_DISPLAY,
102 LAST_VALUE
103 } Type_T;
104};
105
106// ///////// Parsing of Options & Configuration /////////
107// A helper function to simplify the main part.
108template<class T> std::ostream& operator<< (std::ostream& os,
109 const std::vector<T>& v) {
110 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
111 return os;
112}
113
117int readConfiguration (int argc, char* argv[],
118 bool& ioIsBuiltin, bool& ioIsForSchedule,
119 stdair::Filename_T& ioInventoryFilename,
120 stdair::Filename_T& ioScheduleInputFilename,
121 stdair::Filename_T& ioODInputFilename,
122 stdair::Filename_T& ioFRAT5Filename,
123 stdair::Filename_T& ioFFDisutilityFilename,
124 stdair::Filename_T& ioYieldInputFilename,
125 std::string& ioLogFilename) {
126 // Default for the built-in input
127 ioIsBuiltin = K_AIRINV_DEFAULT_BUILT_IN_INPUT;
128
129 // Default for the inventory or schedule option
130 ioIsForSchedule = K_AIRINV_DEFAULT_FOR_SCHEDULE;
131
132 // Declare a group of options that will be allowed only on command line
133 boost::program_options::options_description generic ("Generic options");
134 generic.add_options()
135 ("prefix", "print installation prefix")
136 ("version,v", "print version string")
137 ("help,h", "produce help message");
138
139 // Declare a group of options that will be allowed both on command
140 // line and in config file
141
142 boost::program_options::options_description config ("Configuration");
143 config.add_options()
144 ("builtin,b",
145 "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")
146 ("for_schedule,f",
147 "The BOM tree should be built from a schedule file (instead of from an inventory dump)")
148 ("inventory,i",
149 boost::program_options::value< std::string >(&ioInventoryFilename)->default_value(K_AIRINV_DEFAULT_INVENTORY_FILENAME),
150 "(CSV) input file for the inventory")
151 ("schedule,s",
152 boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_AIRINV_DEFAULT_SCHEDULE_FILENAME),
153 "(CSV) input file for the schedule")
154 ("ond,o",
155 boost::program_options::value< std::string >(&ioODInputFilename)->default_value(K_AIRINV_DEFAULT_OND_FILENAME),
156 "(CSV) input file for the O&D")
157 ("frat5,F",
158 boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME),
159 "(CSV) input file for the FRAT5 Curve")
160 ("ff_disutility,D",
161 boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME),
162 "(CSV) input file for the FF disutility Curve")
163 ("yield,y",
164 boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_AIRINV_DEFAULT_YIELD_FILENAME),
165 "(CSV) input file for the yield")
166 ("log,l",
167 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_AIRINV_DEFAULT_LOG_FILENAME),
168 "Filename for the logs")
169 ;
170
171 // Hidden options, will be allowed both on command line and
172 // in config file, but will not be shown to the user.
173 boost::program_options::options_description hidden ("Hidden options");
174 hidden.add_options()
175 ("copyright",
176 boost::program_options::value< std::vector<std::string> >(),
177 "Show the copyright (license)");
178
179 boost::program_options::options_description cmdline_options;
180 cmdline_options.add(generic).add(config).add(hidden);
181
182 boost::program_options::options_description config_file_options;
183 config_file_options.add(config).add(hidden);
184 boost::program_options::options_description visible ("Allowed options");
185 visible.add(generic).add(config);
186
187 boost::program_options::positional_options_description p;
188 p.add ("copyright", -1);
189
190 boost::program_options::variables_map vm;
191 boost::program_options::
192 store (boost::program_options::command_line_parser (argc, argv).
193 options (cmdline_options).positional(p).run(), vm);
194
195 std::ifstream ifs ("airinv.cfg");
196 boost::program_options::store (parse_config_file (ifs, config_file_options),
197 vm);
198 boost::program_options::notify (vm);
199
200 if (vm.count ("help")) {
201 std::cout << visible << std::endl;
202 return K_AIRINV_EARLY_RETURN_STATUS;
203 }
204
205 if (vm.count ("version")) {
206 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
207 return K_AIRINV_EARLY_RETURN_STATUS;
208 }
209
210 if (vm.count ("prefix")) {
211 std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
212 return K_AIRINV_EARLY_RETURN_STATUS;
213 }
214
215 if (vm.count ("builtin")) {
216 ioIsBuiltin = true;
217 }
218 const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
219 std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
220
221 if (vm.count ("for_schedule")) {
222 ioIsForSchedule = true;
223 }
224 const std::string isForScheduleStr = (ioIsForSchedule == true)?"yes":"no";
225 std::cout << "The BOM should be built from schedule? " << isForScheduleStr
226 << std::endl;
227
228 if (ioIsBuiltin == false) {
229
230 if (ioIsForSchedule == false) {
231 // The BOM tree should be built from parsing an inventory dump
232 if (vm.count ("inventory")) {
233 ioInventoryFilename = vm["inventory"].as< std::string >();
234 std::cout << "Input inventory filename is: " << ioInventoryFilename
235 << std::endl;
236
237 } else {
238 // The built-in option is not selected. However, no inventory dump
239 // file is specified
240 std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
241 << " -f/--for_schedule and -s/--schedule options "
242 << "must be specified" << std::endl;
243 }
244
245 } else {
246 // The BOM tree should be built from parsing a schedule (and O&D) file
247 if (vm.count ("schedule")) {
248 ioScheduleInputFilename = vm["schedule"].as< std::string >();
249 std::cout << "Input schedule filename is: " << ioScheduleInputFilename
250 << std::endl;
251
252 } else {
253 // The built-in option is not selected. However, no schedule file
254 // is specified
255 std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
256 << " -f/--for_schedule and -s/--schedule options "
257 << "must be specified" << std::endl;
258 }
259
260 if (vm.count ("ond")) {
261 ioODInputFilename = vm["ond"].as< std::string >();
262 std::cout << "Input O&D filename is: " << ioODInputFilename << std::endl;
263 }
264
265 if (vm.count ("frat5")) {
266 ioFRAT5Filename = vm["frat5"].as< std::string >();
267 std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl;
268
269 }
270
271 if (vm.count ("ff_disutility")) {
272 ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >();
273 std::cout << "FF disutility input filename is: "
274 << ioFFDisutilityFilename << std::endl;
275
276 }
277
278 if (vm.count ("yield")) {
279 ioYieldInputFilename = vm["yield"].as< std::string >();
280 std::cout << "Input yield filename is: " << ioYieldInputFilename << std::endl;
281 }
282 }
283 }
284
285 if (vm.count ("log")) {
286 ioLogFilename = vm["log"].as< std::string >();
287 std::cout << "Log filename is: " << ioLogFilename << std::endl;
288 }
289
290 return 0;
291}
292
293// //////////////////////////////////////////////////////////////////
294void initReadline (swift::SReadline& ioInputReader) {
295
296 // Prepare the list of my own completers
297 std::vector<std::string> Completers;
298
299 // The following is supported:
300 // - "identifiers"
301 // - special identifier %file - means to perform a file name completion
302 Completers.push_back ("help");
303 Completers.push_back ("list %airline_code %flight_number");
304 Completers.push_back ("select %airline_code %flight_number %flight_date");
305 Completers.push_back ("display");
306 Completers.push_back ("sell %booking_class %party_size %origin %destination");
307 Completers.push_back ("quit");
308 Completers.push_back ("json_list");
309 Completers.push_back ("json_display");
310
311
312 // Now register the completers.
313 // Actually it is possible to re-register another set at any time
314 ioInputReader.RegisterCompletions (Completers);
315}
316
317// //////////////////////////////////////////////////////////////////
318Command_T::Type_T extractCommand (TokenList_T& ioTokenList) {
319 Command_T::Type_T oCommandType = Command_T::LAST_VALUE;
320
321 // Interpret the user input
322 if (ioTokenList.empty() == false) {
323 TokenList_T::iterator itTok = ioTokenList.begin();
324 std::string lCommand (*itTok);
325 boost::algorithm::to_lower (lCommand);
326
327 if (lCommand == "help") {
328 oCommandType = Command_T::HELP;
329
330 } else if (lCommand == "list") {
331 oCommandType = Command_T::LIST;
332
333 } else if (lCommand == "display") {
334 oCommandType = Command_T::DISPLAY;
335
336 } else if (lCommand == "select") {
337 oCommandType = Command_T::SELECT;
338
339 } else if (lCommand == "sell") {
340 oCommandType = Command_T::SELL;
341
342 } else if (lCommand == "json_list") {
343 oCommandType = Command_T::JSON_LIST;
344
345 } else if (lCommand == "json_display") {
346 oCommandType = Command_T::JSON_DISPLAY;
347
348 } else if (lCommand == "quit") {
349 oCommandType = Command_T::QUIT;
350 }
351
352 // Remove the first token (the command), as the corresponding information
353 // has been extracted in the form of the returned command type enumeration
354 ioTokenList.erase (itTok);
355
356 } else {
357 oCommandType = Command_T::NOP;
358 }
359
360 return oCommandType;
361}
362
363// //////////////////////////////////////////////////////////////////
364void parseFlightKey (const TokenList_T& iTokenList,
365 stdair::AirlineCode_T& ioAirlineCode,
366 stdair::FlightNumber_T& ioFlightNumber) {
367 // Interpret the user input
368 if (iTokenList.empty() == false) {
369
370 // Read the airline code
371 TokenList_T::const_iterator itTok = iTokenList.begin();
372 if (itTok->empty() == false) {
373 ioAirlineCode = *itTok;
374 boost::algorithm::to_upper (ioAirlineCode);
375 }
376
377 // Read the flight-number
378 ++itTok;
379 if (itTok != iTokenList.end()) {
380
381 if (itTok->empty() == false) {
382 try {
383
384 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
385
386 } catch (boost::bad_lexical_cast& eCast) {
387 std::cerr << "The flight number ('" << *itTok
388 << "') cannot be understood. "
389 << "The default value (all) is kept."
390 << std::endl;
391 return;
392 }
393 }
394
395 } else {
396 return;
397 }
398 }
399}
400
401// //////////////////////////////////////////////////////////////////
402void parseFlightDateKey (const TokenList_T& iTokenList,
403 stdair::AirlineCode_T& ioAirlineCode,
404 stdair::FlightNumber_T& ioFlightNumber,
405 stdair::Date_T& ioDepartureDate) {
406 //
407 const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
408 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
409 //
410 unsigned short ioDepartureDateYear = ioDepartureDate.year();
411 unsigned short ioDepartureDateMonth = ioDepartureDate.month();
412 std::string ioDepartureDateMonthStr = kMonthStr[ioDepartureDateMonth-1];
413 unsigned short ioDepartureDateDay = ioDepartureDate.day();
414
415 // Interpret the user input
416 if (iTokenList.empty() == false) {
417
418 // Read the airline code
419 TokenList_T::const_iterator itTok = iTokenList.begin();
420 if (itTok->empty() == false) {
421 ioAirlineCode = *itTok;
422 boost::algorithm::to_upper (ioAirlineCode);
423 }
424
425 // Read the flight-number
426 ++itTok;
427 if (itTok != iTokenList.end()) {
428
429 if (itTok->empty() == false) {
430 try {
431
432 ioFlightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
433
434 } catch (boost::bad_lexical_cast& eCast) {
435 std::cerr << "The flight number ('" << *itTok
436 << "') cannot be understood. "
437 << "The default value (all) is kept."
438 << std::endl;
439 return;
440 }
441 }
442
443 } else {
444 return;
445 }
446
447 // Read the year for the departure date
448 ++itTok;
449 if (itTok != iTokenList.end()) {
450
451 if (itTok->empty() == false) {
452 try {
453
454 ioDepartureDateYear = boost::lexical_cast<unsigned short> (*itTok);
455 if (ioDepartureDateYear < 100) {
456 ioDepartureDateYear += 2000;
457 }
458
459 } catch (boost::bad_lexical_cast& eCast) {
460 std::cerr << "The year of the flight departure date ('" << *itTok
461 << "') cannot be understood. The default value ("
462 << ioDepartureDateYear << ") is kept. " << std::endl;
463 return;
464 }
465 }
466
467 } else {
468 return;
469 }
470
471 // Read the month for the departure date
472 ++itTok;
473 if (itTok != iTokenList.end()) {
474
475 if (itTok->empty() == false) {
476 try {
477
478 const boost::regex lMonthRegex ("^(\\d{1,2})$");
479 const bool isMonthANumber = regex_match (*itTok, lMonthRegex);
480
481 if (isMonthANumber == true) {
482 const unsigned short lMonth =
483 boost::lexical_cast<unsigned short> (*itTok);
484 if (lMonth > 12) {
485 throw boost::bad_lexical_cast();
486 }
487 ioDepartureDateMonthStr = kMonthStr[lMonth-1];
488
489 } else {
490 const std::string lMonthStr (*itTok);
491 if (lMonthStr.size() < 3) {
492 throw boost::bad_lexical_cast();
493 }
494 std::string lMonthStr1 (lMonthStr.substr (0, 1));
495 boost::algorithm::to_upper (lMonthStr1);
496 std::string lMonthStr23 (lMonthStr.substr (1, 2));
497 boost::algorithm::to_lower (lMonthStr23);
498 ioDepartureDateMonthStr = lMonthStr1 + lMonthStr23;
499 }
500
501 } catch (boost::bad_lexical_cast& eCast) {
502 std::cerr << "The month of the flight departure date ('" << *itTok
503 << "') cannot be understood. The default value ("
504 << ioDepartureDateMonthStr << ") is kept. " << std::endl;
505 return;
506 }
507 }
508
509 } else {
510 return;
511 }
512
513 // Read the day for the departure date
514 ++itTok;
515 if (itTok != iTokenList.end()) {
516
517 if (itTok->empty() == false) {
518 try {
519
520 ioDepartureDateDay = boost::lexical_cast<unsigned short> (*itTok);
521
522 } catch (boost::bad_lexical_cast& eCast) {
523 std::cerr << "The day of the flight departure date ('" << *itTok
524 << "') cannot be understood. The default value ("
525 << ioDepartureDateDay << ") is kept. " << std::endl;
526 return;
527 }
528 }
529
530 } else {
531 return;
532 }
533
534 // Re-compose the departure date
535 std::ostringstream lDepartureDateStr;
536 lDepartureDateStr << ioDepartureDateYear << "-" << ioDepartureDateMonthStr
537 << "-" << ioDepartureDateDay;
538
539 try {
540
541 ioDepartureDate =
542 boost::gregorian::from_simple_string (lDepartureDateStr.str());
543
544 } catch (boost::gregorian::bad_month& eCast) {
545 std::cerr << "The flight departure date ('" << lDepartureDateStr.str()
546 << "') cannot be understood. The default value ("
547 << ioDepartureDate << ") is kept. " << std::endl;
548 return;
549 }
550
551 }
552}
553
554// //////////////////////////////////////////////////////////////////
555void parseBookingClassKey (const TokenList_T& iTokenList,
556 stdair::ClassCode_T& ioBookingClass,
557 stdair::PartySize_T& ioPartySize,
558 stdair::AirportCode_T& ioOrigin,
559 stdair::AirportCode_T& ioDestination) {
560 // Interpret the user input
561 if (iTokenList.empty() == false) {
562
563 // Read the booking class
564 TokenList_T::const_iterator itTok = iTokenList.begin();
565 if (itTok->empty() == false) {
566 ioBookingClass = *itTok;
567 boost::algorithm::to_upper (ioBookingClass);
568 }
569
570 // Read the party size
571 ++itTok;
572 if (itTok != iTokenList.end()) {
573
574 if (itTok->empty() == false) {
575 try {
576
577 ioPartySize = boost::lexical_cast<stdair::PartySize_T> (*itTok);
578
579 } catch (boost::bad_lexical_cast& eCast) {
580 std::cerr << "The party size ('" << *itTok
581 << "') cannot be understood. The default value ("
582 << ioPartySize << ") is kept." << std::endl;
583 return;
584 }
585 }
586
587 } else {
588 return;
589 }
590
591 // Read the origin
592 ++itTok;
593 if (itTok != iTokenList.end()) {
594
595 if (itTok->empty() == false) {
596 ioOrigin = *itTok;
597 boost::algorithm::to_upper (ioOrigin);
598 }
599
600 } else {
601 return;
602 }
603
604 // Read the destination
605 ++itTok;
606 if (itTok != iTokenList.end()) {
607
608 if (itTok->empty() == false) {
609 ioDestination = *itTok;
610 boost::algorithm::to_upper (ioDestination);
611 }
612
613 } else {
614 return;
615 }
616 }
617}
618
619// /////////////////////////////////////////////////////////
620std::string toString (const TokenList_T& iTokenList) {
621 std::ostringstream oStr;
622
623 // Re-create the string with all the tokens, trimmed by read-line
624 unsigned short idx = 0;
625 for (TokenList_T::const_iterator itTok = iTokenList.begin();
626 itTok != iTokenList.end(); ++itTok, ++idx) {
627 if (idx != 0) {
628 oStr << " ";
629 }
630 oStr << *itTok;
631 }
632
633 return oStr.str();
634}
635
636// /////////////////////////////////////////////////////////
637TokenList_T extractTokenList (const TokenList_T& iTokenList,
638 const std::string& iRegularExpression) {
639 TokenList_T oTokenList;
640
641 // Re-create the string with all the tokens (which had been trimmed
642 // by read-line)
643 const std::string lFullLine = toString (iTokenList);
644
645 // See the caller for the regular expression
646 boost::regex expression (iRegularExpression);
647
648 std::string::const_iterator start = lFullLine.begin();
649 std::string::const_iterator end = lFullLine.end();
650
651 boost::match_results<std::string::const_iterator> what;
652 boost::match_flag_type flags = boost::match_default | boost::format_sed;
653 regex_search (start, end, what, expression, flags);
654
655 // Put the matched strings in the list of tokens to be returned back
656 // to the caller
657 const unsigned short lMatchSetSize = what.size();
658 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
659 const std::string lMatchedString (std::string (what[matchIdx].first,
660 what[matchIdx].second));
661 //if (lMatchedString.empty() == false) {
662 oTokenList.push_back (lMatchedString);
663 //}
664 }
665
666 // DEBUG
667 // std::cout << "After (token list): " << oTokenList << std::endl;
668
669 return oTokenList;
670}
671
672// /////////////////////////////////////////////////////////
673TokenList_T extractTokenListForFlight (const TokenList_T& iTokenList) {
680 const std::string lRegEx ("^([[:alpha:]]{2,3})?"
681 "[[:space:]]*([[:digit:]]{1,4})?$");
682
683 //
684 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
685 return oTokenList;
686}
687
688// /////////////////////////////////////////////////////////
689TokenList_T extractTokenListForFlightDate (const TokenList_T& iTokenList) {
700 const std::string lRegEx("^([[:alpha:]]{2,3})?"
701 "[[:space:]]*([[:digit:]]{1,4})?"
702 "[/ ]*"
703 "([[:digit:]]{2,4})?[/-]?[[:space:]]*"
704 "([[:alpha:]]{3}|[[:digit:]]{1,2})?[/-]?[[:space:]]*"
705 "([[:digit:]]{1,2})?$");
706
707 //
708 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
709 return oTokenList;
710}
711
712// /////////////////////////////////////////////////////////
713TokenList_T extractTokenListForClass (const TokenList_T& iTokenList) {
722 const std::string lRegEx ("^([[:alpha:]])?"
723 "[[:space:]]*([[:digit:]]{1,3})?"
724 "[[:space:]]*([[:alpha:]]{3})?"
725 "[[:space:]]*([[:alpha:]]{3})?$");
726
727 //
728 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
729 return oTokenList;
730}
731
732
733// ///////// M A I N ////////////
734int main (int argc, char* argv[]) {
735
736 // State whether the BOM tree should be built-in or parsed from an
737 // input file
738 bool isBuiltin;
739 bool isForSchedule;
740
741 // Input file names
742 stdair::Filename_T lInventoryFilename;
743 stdair::Filename_T lScheduleInputFilename;
744 stdair::Filename_T lODInputFilename;
745 stdair::Filename_T lFRAT5InputFilename;
746 stdair::Filename_T lFFDisutilityInputFilename;
747 stdair::Filename_T lYieldInputFilename;
748
749 // Readline history
750 const unsigned int lHistorySize (100);
751 const std::string lHistoryFilename ("airinv.hist");
752 const std::string lHistoryBackupFilename ("airinv.hist.bak");
753
754 // Default parameters for the interactive session
755 stdair::AirlineCode_T lLastInteractiveAirlineCode;
756 stdair::FlightNumber_T lLastInteractiveFlightNumber;
757 stdair::Date_T lLastInteractiveDate;
758 stdair::AirlineCode_T lInteractiveAirlineCode;
759 stdair::FlightNumber_T lInteractiveFlightNumber;
760 stdair::Date_T lInteractiveDate;
761 stdair::AirportCode_T lInteractiveOrigin;
762 stdair::AirportCode_T lInteractiveDestination;
763 stdair::ClassCode_T lInteractiveBookingClass;
764 stdair::PartySize_T lInteractivePartySize;
765
766 // Parameters for the sale
767 std::string lSegmentDateKey;
768
769 // Output log File
770 stdair::Filename_T lLogFilename;
771
772 // Call the command-line option parser
773 const int lOptionParserStatus =
774 readConfiguration (argc, argv, isBuiltin, isForSchedule, lInventoryFilename,
775 lScheduleInputFilename, lODInputFilename,
776 lFRAT5InputFilename, lFFDisutilityInputFilename,
777 lYieldInputFilename, lLogFilename);
778
779 if (lOptionParserStatus == K_AIRINV_EARLY_RETURN_STATUS) {
780 return 0;
781 }
782
783 // Set the log parameters
784 std::ofstream logOutputFile;
785 // Open and clean the log outputfile
786 logOutputFile.open (lLogFilename.c_str());
787 logOutputFile.clear();
788
789 // Initialise the inventory service
790 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
791 AIRINV::AIRINV_Master_Service airinvService (lLogParams);
792
793 // DEBUG
794 STDAIR_LOG_DEBUG ("Welcome to AirInv");
795
796 // Check wether or not a (CSV) input file should be read
797 if (isBuiltin == true) {
798
799 // Build the sample BOM tree for RMOL
800 airinvService.buildSampleBom();
801
802 // Update the default parameters for the following interactive session
803 lInteractiveAirlineCode = "BA";
804 lInteractiveFlightNumber = 9;
805 lInteractiveDate = stdair::Date_T (2011, 06, 10);
806 lInteractiveBookingClass = "Q";
807 lInteractivePartySize = 2;
808 lInteractiveOrigin = "LHR";
809 lInteractiveDestination = "SYD";
810
811 } else {
812 if (isForSchedule == true) {
813 // Build the BOM tree from parsing a schedule file (and O&D list)
814 stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename);
815 stdair::ODFilePath lODFilePath (lODInputFilename);
816 stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename);
817 stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename);
818 AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename);
819 airinvService.parseAndLoad (lScheduleFilePath, lODFilePath,
820 lFRAT5FilePath, lFFDisutilityFilePath,
821 lYieldFilePath);
822
823 // Update the default parameters for the following interactive session
824 lInteractiveAirlineCode = "SQ";
825 lInteractiveFlightNumber = 11;
826 lInteractiveDate = stdair::Date_T (2010, 01, 15);
827 lInteractiveBookingClass = "Y";
828 lInteractivePartySize = 2;
829 lInteractiveOrigin = "SIN";
830 lInteractiveDestination = "BKK";
831
832 } else {
833 // Build the BOM tree from parsing an inventory dump file
834 AIRINV::InventoryFilePath lInventoryFilePath (lInventoryFilename);
835 airinvService.parseAndLoad (lInventoryFilePath);
836
837 // Update the default parameters for the following interactive session
838 lInteractiveAirlineCode = "SV";
839 lInteractiveFlightNumber = 5;
840 lInteractiveDate = stdair::Date_T (2010, 03, 11);
841 lInteractiveBookingClass = "Y";
842 lInteractivePartySize = 2;
843 lInteractiveOrigin = "KBP";
844 lInteractiveDestination = "JFK";
845 }
846 }
847
848 // Save the last state
849 lLastInteractiveAirlineCode = lInteractiveAirlineCode;
850 lLastInteractiveFlightNumber = lInteractiveFlightNumber;
851 lLastInteractiveDate = lInteractiveDate;
852
853 // DEBUG
854 STDAIR_LOG_DEBUG ("====================================================");
855 STDAIR_LOG_DEBUG ("= Beginning of the interactive session =");
856 STDAIR_LOG_DEBUG ("====================================================");
857
858 // Initialise the GNU readline wrapper
859 swift::SReadline lReader (lHistoryFilename, lHistorySize);
860 initReadline (lReader);
861
862 // Now we can ask user for a line
863 std::string lUserInput;
864 bool EndOfInput (false);
865 Command_T::Type_T lCommandType (Command_T::NOP);
866
867 while (lCommandType != Command_T::QUIT && EndOfInput == false) {
868 // Prompt
869 std::ostringstream oPromptStr;
870 oPromptStr << "airinv "
871 << lInteractiveAirlineCode << lInteractiveFlightNumber
872 << " / " << lInteractiveDate
873 << "> ";
874 // Call read-line, which will fill the list of tokens
875 TokenList_T lTokenListByReadline;
876 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
877 EndOfInput);
878
879 // The history can be saved to an arbitrary file at any time
880 lReader.SaveHistory (lHistoryBackupFilename);
881
882 // The end-of-input typically corresponds to a CTRL-D typed by the user
883 if (EndOfInput) {
884 std::cout << std::endl;
885 break;
886 }
887
888 // Interpret the user input
889 lCommandType = extractCommand (lTokenListByReadline);
890
891 switch (lCommandType) {
892
893 // ////////////////////////////// Help ////////////////////////
894 case Command_T::HELP: {
895 std::cout << std::endl;
896 std::cout << "Commands: " << std::endl;
897 std::cout << " help" << "\t\t" << "Display this help" << std::endl;
898 std::cout << " quit" << "\t\t" << "Quit the application" << std::endl;
899 std::cout << " list" << "\t\t"
900 << "List airlines, flights and departure dates" << std::endl;
901 std::cout << " select" << "\t\t"
902 << "Select a flight-date to become the current one"
903 << std::endl;
904 std::cout << " display" << "\t"
905 << "Display the current flight-date" << std::endl;
906 std::cout << " sell" << "\t\t"
907 << "Make a booking on the current flight-date" << std::endl;
908 std::cout << " \nDebug Commands" << std::endl;
909 std::cout << " json_list" << "\t"
910 << "List airlines, flights and departure dates in a JSON format"
911 << std::endl;
912 std::cout << " json_display" << "\t"
913 << "Display the current flight-date in a JSON format"
914 << std::endl;
915 std::cout << std::endl;
916 break;
917 }
918
919 // ////////////////////////////// Quit ////////////////////////
920 case Command_T::QUIT: {
921 break;
922 }
923
924 // ////////////////////////////// List /////////////////////////
925 case Command_T::LIST: {
926 //
927 TokenList_T lTokenList = extractTokenListForFlight (lTokenListByReadline);
928
929 stdair::AirlineCode_T lAirlineCode ("all");
930 stdair::FlightNumber_T lFlightNumber (0);
931 // Parse the parameters given by the user, giving default values
932 // in case the user does not specify some (or all) of them
933 parseFlightKey (lTokenList, lAirlineCode, lFlightNumber);
934
935 //
936 const std::string lFlightNumberStr = (lFlightNumber ==0)?" (all)":"";
937 std::cout << "List of flights for "
938 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr
939 << std::endl;
940
941 // DEBUG: Display the flight-date
942 const std::string& lFlightDateListStr =
943 airinvService.list (lAirlineCode, lFlightNumber);
944
945 if (lFlightDateListStr.empty() == false) {
946 std::cout << lFlightDateListStr << std::endl;
947 STDAIR_LOG_DEBUG (lFlightDateListStr);
948
949 } else {
950 std::cerr << "There is no result for "
951 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr
952 << ". Just type the list command without any parameter "
953 << "to see the flight-dates for all the airlines and for all "
954 << "the flight numbers."
955 << std::endl;
956 }
957
958 break;
959 }
960
961 // ////////////////////////////// Select ////////////////////////
962 case Command_T::SELECT: {
963 //
964 TokenList_T lTokenList =
965 extractTokenListForFlightDate (lTokenListByReadline);
966
967 // Check whether the user wants to select the last saved flight-date
968 if (lTokenList.empty() == false) {
969 // Read the booking class
970 TokenList_T::const_iterator itTok = lTokenList.begin();
971
972 if (*itTok == "-") {
973
974 // Swap the current state with the last state
975 boost::swap (lInteractiveAirlineCode, lLastInteractiveAirlineCode);
976 boost::swap (lInteractiveFlightNumber, lLastInteractiveFlightNumber);
977 boost::swap (lInteractiveDate, lLastInteractiveDate);
978
979 break;
980 }
981 }
982
983 // Parse the parameters given by the user, giving default values
984 // in case the user does not specify some (or all) of them
985 parseFlightDateKey (lTokenList, lInteractiveAirlineCode,
986 lInteractiveFlightNumber, lInteractiveDate);
987
988 // Check whether the selected flight-date is valid
989 const bool isFlightDateValid =
990 airinvService.check (lInteractiveAirlineCode, lInteractiveFlightNumber,
991 lInteractiveDate);
992 if (isFlightDateValid == false) {
993 std::ostringstream oFDKStr;
994 oFDKStr << "The " << lInteractiveAirlineCode
995 << lInteractiveFlightNumber << " / " << lInteractiveDate
996 << " flight-date is not valid. Make sure it exists (e.g.,"
997 << " with the list command). The current flight-date is kept"
998 << " selected.";
999 std::cout << oFDKStr.str() << std::endl;
1000 STDAIR_LOG_ERROR (oFDKStr.str());
1001
1002 // Restore the last state
1003 lInteractiveAirlineCode = lLastInteractiveAirlineCode;
1004 lInteractiveFlightNumber = lLastInteractiveFlightNumber;
1005 lInteractiveDate = lLastInteractiveDate;
1006
1007 break;
1008 }
1009
1010 // DEBUG: Display the flight-date selection
1011 std::ostringstream oFDKStr;
1012 oFDKStr << "Selected the " << lInteractiveAirlineCode
1013 << lInteractiveFlightNumber << " / " << lInteractiveDate
1014 << " flight-date";
1015 std::cout << oFDKStr.str() << std::endl;
1016 STDAIR_LOG_DEBUG (oFDKStr.str());
1017
1018 // Save the last state
1019 lLastInteractiveAirlineCode = lInteractiveAirlineCode;
1020 lLastInteractiveFlightNumber = lInteractiveFlightNumber;
1021 lLastInteractiveDate = lInteractiveDate;
1022
1023 break;
1024 }
1025
1026 // ////////////////////////////// Display ////////////////////////
1027 case Command_T::DISPLAY: {
1028 // DEBUG: Display the flight-date
1029 const std::string& lCSVFlightDateDump =
1030 airinvService.csvDisplay (lInteractiveAirlineCode,
1031 lInteractiveFlightNumber, lInteractiveDate);
1032 std::cout << lCSVFlightDateDump << std::endl;
1033 STDAIR_LOG_DEBUG (lCSVFlightDateDump);
1034
1035 break;
1036 }
1037
1038 // ////////////////////////////// Sell ////////////////////////
1039 case Command_T::SELL: {
1040 //
1041 TokenList_T lTokenList = extractTokenListForClass (lTokenListByReadline);
1042
1043 // Parse the parameters given by the user, giving default values
1044 // in case the user does not specify some (or all) of them
1045 parseBookingClassKey (lTokenList, lInteractiveBookingClass,
1046 lInteractivePartySize,
1047 lInteractiveOrigin, lInteractiveDestination);
1048
1049 // DEBUG: Display the flight-date before the sell
1050 const std::string& lCSVFlightDateDumpBefore =
1051 airinvService.csvDisplay (lInteractiveAirlineCode,
1052 lInteractiveFlightNumber, lInteractiveDate);
1053 //std::cout << lCSVFlightDateDumpBefore << std::endl;
1054 STDAIR_LOG_DEBUG (lCSVFlightDateDumpBefore);
1055
1056 // Make a booking
1057 std::ostringstream oSDKStr;
1058 oSDKStr << lInteractiveAirlineCode << ","
1059 << lInteractiveFlightNumber << ","
1060 << lInteractiveDate << ","
1061 << lInteractiveOrigin << "," << lInteractiveDestination;
1062 const std::string lSegmentDateKey (oSDKStr.str());
1063
1064 // Perform the sell
1065 const bool isSellSuccessful =
1066 airinvService.sell (lSegmentDateKey,
1067 lInteractiveBookingClass, lInteractivePartySize);
1068
1069 // DEBUG
1070 const std::string isSellSuccessfulStr =
1071 (isSellSuccessful == true)?"Yes":"No";
1072 std::ostringstream oSaleStr;
1073 oSaleStr << "Sale ('" << lSegmentDateKey << "', "
1074 << lInteractiveBookingClass << ": " << lInteractivePartySize
1075 << ") successful? " << isSellSuccessfulStr;
1076 std::cout << oSaleStr.str() << std::endl;
1077
1078 // DEBUG
1079 STDAIR_LOG_DEBUG (oSaleStr.str());
1080
1081 // DEBUG: Display the flight-date after the sell
1082 const std::string& lCSVFlightDateDumpAfter =
1083 airinvService.csvDisplay (lInteractiveAirlineCode,
1084 lInteractiveFlightNumber, lInteractiveDate);
1085 //std::cout << lCSVFlightDateDumpAfter << std::endl;
1086 STDAIR_LOG_DEBUG (lCSVFlightDateDumpAfter);
1087
1088 break;
1089 }
1090
1091 // ////////////////////////////// JSon List ////////////////////////
1092
1093 case Command_T::JSON_LIST: {
1094
1095 //
1096 TokenList_T lTokenList = extractTokenListForFlight (lTokenListByReadline);
1097
1098 stdair::AirlineCode_T lAirlineCode ("all");
1099 stdair::FlightNumber_T lFlightNumber (0);
1100 // Parse the parameters given by the user, giving default values
1101 // in case the user does not specify some (or all) of them
1102 parseFlightKey (lTokenList, lAirlineCode, lFlightNumber);
1103
1104 //
1105 const std::string lFlightNumberStr = (lFlightNumber ==0)?" (all)":"";
1106 std::cout << "JSON list of flights for "
1107 << lAirlineCode << " " << lFlightNumber << lFlightNumberStr
1108 << std::endl;
1109
1110 std::ostringstream lMyCommandJSONstream;
1111 lMyCommandJSONstream << "{\"list\":"
1112 << "{ \"airline_code\":\"" << lAirlineCode
1113 << "\",\"flight_number\":\"" << lFlightNumber
1114 << "\"}}";
1115
1116 const stdair::JSONString lJSONCommandString (lMyCommandJSONstream.str());
1117 const std::string& lFlightDateListJSONStr =
1118 airinvService.jsonHandler (lJSONCommandString);
1119
1120 // Display the flight-date JSON string
1121 std::cout << lFlightDateListJSONStr << std::endl;
1122 STDAIR_LOG_DEBUG (lFlightDateListJSONStr);
1123
1124 break;
1125 }
1126
1127 // ////////////////////////////// JSon Display ////////////////////////
1128
1129 case Command_T::JSON_DISPLAY: {
1130
1131 // Construct the JSON command string for the current parameters (current
1132 // airline code, current flight number and current date)
1133 std::ostringstream lMyCommandJSONstream;
1134 lMyCommandJSONstream << "{\"flight_date\":"
1135 << "{ \"departure_date\":\"" << lInteractiveDate
1136 << "\",\"airline_code\":\"" << lInteractiveAirlineCode
1137 << "\",\"flight_number\":\"" << lInteractiveFlightNumber
1138 << "\"}}";
1139
1140 // Get the flight-date details in a JSON string
1141 const stdair::JSONString lJSONCommandString (lMyCommandJSONstream.str());
1142 const std::string& lCSVFlightDateDump =
1143 airinvService.jsonHandler (lJSONCommandString);
1144
1145 // Display the flight-date JSON string
1146 std::cout << lCSVFlightDateDump << std::endl;
1147 STDAIR_LOG_DEBUG (lCSVFlightDateDump);
1148
1149 break;
1150 }
1151
1152 // /////////////////////////// Default / No value ///////////////////////
1153 case Command_T::NOP: {
1154 break;
1155 }
1156
1157 case Command_T::LAST_VALUE:
1158 default: {
1159 // DEBUG
1160 std::ostringstream oStr;
1161 oStr << "That command is not yet understood: '" << lUserInput
1162 << "' => " << lTokenListByReadline;
1163 STDAIR_LOG_DEBUG (oStr.str());
1164 std::cout << oStr.str() << std::endl;
1165 }
1166 }
1167 }
1168
1169 // DEBUG
1170 STDAIR_LOG_DEBUG ("End of the session. Exiting.");
1171 std::cout << "End of the session. Exiting." << std::endl;
1172
1173 // Close the Log outputFile
1174 logOutputFile.close();
1175
1176 /*
1177 Note: as that program is not intended to be run on a server in
1178 production, it is better not to catch the exceptions. When it
1179 happens (that an exception is throwned), that way we get the
1180 call stack.
1181 */
1182
1183 return 0;
1184}
int main(int argc, char *argv[])
std::basic_ostream< charT, traits > & operator<<(std::basic_ostream< charT, traits > &ioOut, const AIRINV::BomAbstract &iBom)
Interface for the AIRINV Services.