SimFQT Logo  1.00.6
C++ Simulated Fare Quote System Library
simfqt.cpp
Go to the documentation of this file.
1
6// STL
7#include <cassert>
8#include <iostream>
9#include <sstream>
10#include <fstream>
11#include <string>
12// Boost (Extended STL)
13#include <boost/date_time/gregorian/gregorian.hpp>
14#include <boost/date_time/posix_time/posix_time.hpp>
15#include <boost/program_options.hpp>
16#include <boost/tokenizer.hpp>
17#include <boost/regex.hpp>
18// StdAir
19#include <stdair/stdair_exceptions.hpp>
20#include <stdair/stdair_basic_types.hpp>
21#include <stdair/stdair_date_time_types.hpp>
22#include <stdair/basic/BasConst_DefaultObject.hpp>
23#include <stdair/basic/BasConst_Inventory.hpp>
24#include <stdair/basic/BasConst_Request.hpp>
25#include <stdair/basic/BasLogParams.hpp>
26#include <stdair/basic/BasConst_BomDisplay.hpp>
27#include <stdair/basic/BasDBParams.hpp>
28#include <stdair/bom/TravelSolutionStruct.hpp>
29#include <stdair/bom/BookingRequestStruct.hpp>
30#include <stdair/bom/ParsedKey.hpp>
31#include <stdair/bom/BomKeyManager.hpp>
32#include <stdair/command/CmdBomManager.hpp>
33#include <stdair/service/Logger.hpp>
34// Stdair GNU Readline Wrapper
35#include <stdair/ui/cmdline/SReadline.hpp>
36// Simfqt
38#include <simfqt/config/simfqt-paths.hpp>
39
40// //////// Constants //////
44const std::string K_SIMFQT_DEFAULT_LOG_FILENAME ("simfqt.log");
45
49const std::string K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME (STDAIR_SAMPLE_DIR
50 "/fare01.csv");
51
56const bool K_SIMFQT_DEFAULT_BUILT_IN_INPUT = false;
57
61const int K_SIMFQT_EARLY_RETURN_STATUS = 99;
62
67typedef std::vector<std::string> TokenList_T;
68
72struct Command_T {
73 typedef enum {
74 NOP = 0,
75 QUIT,
76 HELP,
77 LIST,
78 DISPLAY,
79 PRICE,
80 LAST_VALUE
81 } Type_T;
82};
83
84// ///////// Parsing of Options & Configuration /////////
85// A helper function to simplify the main part.
86template<class T> std::ostream& operator<< (std::ostream& os,
87 const std::vector<T>& v) {
88 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
89 return os;
90}
91
95int readConfiguration (int argc, char* argv[], bool& ioIsBuiltin,
96 stdair::Filename_T& ioFareInputFilename,
97 std::string& ioLogFilename) {
98
99 // Default for the built-in input
101
102 // Declare a group of options that will be allowed only on command line
103 boost::program_options::options_description generic ("Generic options");
104 generic.add_options()
105 ("prefix", "print installation prefix")
106 ("version,v", "print version string")
107 ("help,h", "produce help message");
108
109 // Declare a group of options that will be allowed both on command
110 // line and in config file
111 boost::program_options::options_description config ("Configuration");
112 config.add_options()
113 ("builtin,b",
114 "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -f/--fare option")
115 ("fare,f",
116 boost::program_options::value< std::string >(&ioFareInputFilename)->default_value(K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME),
117 "(CSV) input file for the fare rules")
118 ("log,l",
119 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_SIMFQT_DEFAULT_LOG_FILENAME),
120 "Filename for the logs")
121 ;
122
123 // Hidden options, will be allowed both on command line and
124 // in config file, but will not be shown to the user.
125 boost::program_options::options_description hidden ("Hidden options");
126 hidden.add_options()
127 ("copyright",
128 boost::program_options::value< std::vector<std::string> >(),
129 "Show the copyright (license)");
130
131 boost::program_options::options_description cmdline_options;
132 cmdline_options.add(generic).add(config).add(hidden);
133
134 boost::program_options::options_description config_file_options;
135 config_file_options.add(config).add(hidden);
136
137 boost::program_options::options_description visible ("Allowed options");
138 visible.add(generic).add(config);
139
140 boost::program_options::positional_options_description p;
141 p.add ("copyright", -1);
142
143 boost::program_options::variables_map vm;
144 boost::program_options::
145 store (boost::program_options::command_line_parser (argc, argv).
146 options (cmdline_options).positional(p).run(), vm);
147
148 std::ifstream ifs ("simfqt.cfg");
149 boost::program_options::store (parse_config_file (ifs, config_file_options),
150 vm);
151 boost::program_options::notify (vm); if (vm.count ("help")) {
152 std::cout << visible << std::endl;
154 }
155
156 if (vm.count ("version")) {
157 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
159 }
160
161 if (vm.count ("prefix")) {
162 std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
164 }
165
166 if (vm.count ("builtin")) {
167 ioIsBuiltin = true;
168 }
169 const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
170 std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
171
172 if (ioIsBuiltin == false) {
173
174 // The BOM tree should be built from parsing a fare (and O&D) file
175 if (vm.count ("fare")) {
176 ioFareInputFilename = vm["fare"].as< std::string >();
177 std::cout << "Input fare filename is: " << ioFareInputFilename
178 << std::endl;
179
180 } else {
181 // The built-in option is not selected. However, no fare file
182 // is specified
183 std::cerr << "Either one among the -b/--builtin and -f/--fare "
184 << "options must be specified" << std::endl;
185 }
186 }
187
188 if (vm.count ("log")) {
189 ioLogFilename = vm["log"].as< std::string >();
190 std::cout << "Log filename is: " << ioLogFilename << std::endl;
191 }
192
193 return 0;
194
195}
196
197// //////////////////////////////////////////////////////////////////
198void initReadline (swift::SReadline& ioInputReader) {
199
200 // Prepare the list of my own completers
201 std::vector<std::string> Completers;
202
203 // The following is supported:
204 // - "identifiers"
205 // - special identifier %file - means to perform a file name completion
206 Completers.push_back ("help");
207 Completers.push_back ("list");
208 Completers.push_back ("display %airport_code %airport_code %departure_date");
209 Completers.push_back ("price %airline_code %flight_number %departure_date %airport_code %airport_code %departure_time %booking_date %booking_time %POS %channel% %trip_type %stay_duration");
210 Completers.push_back ("quit");
211
212 // Now register the completers.
213 // Actually it is possible to re-register another set at any time
214 ioInputReader.RegisterCompletions (Completers);
215}
216
217// //////////////////////////////////////////////////////////////////
218Command_T::Type_T extractCommand (TokenList_T& ioTokenList) {
219 Command_T::Type_T oCommandType = Command_T::LAST_VALUE;
220
221 // Interpret the user input
222 if (ioTokenList.empty() == false) {
223 TokenList_T::iterator itTok = ioTokenList.begin();
224 std::string& lCommand (*itTok);
225 boost::algorithm::to_lower (lCommand);
226
227 if (lCommand == "help") {
228 oCommandType = Command_T::HELP;
229
230 } else if (lCommand == "list") {
231 oCommandType = Command_T::LIST;
232
233 } else if (lCommand == "display") {
234 oCommandType = Command_T::DISPLAY;
235
236 } else if (lCommand == "price") {
237 oCommandType = Command_T::PRICE;
238
239 } else if (lCommand == "quit") {
240 oCommandType = Command_T::QUIT;
241
242 }
243
244 // Remove the first token (the command), as the corresponding information
245 // has been extracted in the form of the returned command type enumeration
246 ioTokenList.erase (itTok);
247
248 } else {
249 oCommandType = Command_T::NOP;
250 }
251
252 return oCommandType;
253}
254
255// //////////////////////////////////////////////////////////////////
256// Re-compose a date using three strings: the year, the month and the
257// day. Return true if a correct date has been computed, false if not.
258bool retrieveDate (std::string iYearString,
259 std::string iMonthString,
260 std::string iDayString,
261 stdair::Date_T& ioDate) {
262
263 const std::string kMonthStr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
264 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
265
266 // Check the year.
267 unsigned short lDateYear;
268 try {
269
270 lDateYear = boost::lexical_cast<unsigned short> (iYearString);
271 if (lDateYear < 100) {
272 lDateYear += 2000;
273 }
274
275 } catch (boost::bad_lexical_cast& eCast) {
276 std::cerr << "The year ('" << iYearString
277 << "') cannot be understood." << std::endl;
278 return false;
279 }
280
281 // Check the month.
282 std::string lDateMonthStr;
283 try {
284
285 const boost::regex lMonthRegex ("^(\\d{1,2})$");
286 const bool isMonthANumber = regex_match (iMonthString, lMonthRegex);
287
288 if (isMonthANumber == true) {
289 const unsigned short lMonth =
290 boost::lexical_cast<unsigned short> (iMonthString);
291 if (lMonth > 12) {
292 throw boost::bad_lexical_cast();
293 }
294 if (lMonth != 0) {
295 lDateMonthStr = kMonthStr[lMonth-1];
296 } else {
297 std::cerr << "The month ('" << iMonthString
298 << "') cannot be understood." << std::endl;
299 return false;
300 }
301
302 } else {
303 if (iMonthString.size() < 3) {
304 throw boost::bad_lexical_cast();
305 }
306 std::string lMonthStr1 (iMonthString.substr (0, 1));
307 boost::algorithm::to_upper (lMonthStr1);
308 std::string lMonthStr23 (iMonthString.substr (1, 2));
309 boost::algorithm::to_lower (lMonthStr23);
310 lDateMonthStr = lMonthStr1 + lMonthStr23;
311 }
312
313 } catch (boost::bad_lexical_cast& eCast) {
314 std::cerr << "The month ('" << iMonthString
315 << "') cannot be understood." << std::endl;
316 return false;
317 }
318
319 // Check the day.
320 unsigned short lDateDay;
321 try {
322
323 lDateDay = boost::lexical_cast<unsigned short> (iDayString);
324
325 } catch (boost::bad_lexical_cast& eCast) {
326 std::cerr << "The day ('" << iDayString
327 << "') cannot be understood." << std::endl;
328 return false;
329 }
330
331 // Re-compose the date.
332 std::ostringstream lDateStr;
333 lDateStr << lDateYear << "-" << lDateMonthStr
334 << "-" << lDateDay;
335 try {
336
337 ioDate =
338 boost::gregorian::from_simple_string (lDateStr.str());
339
340 } catch (boost::gregorian::bad_month& eCast) {
341 std::cerr << "The month of the date ('" << lDateStr.str()
342 << "') cannot be understood." << std::endl;
343 return false;
344 } catch (boost::gregorian::bad_day_of_month& eCast) {
345 std::cerr << "The date ('" << lDateStr.str()
346 << "') is not correct: the day of month does not exist."
347 << std::endl;
348 return false;
349 } catch (boost::gregorian::bad_year& eCast) {
350 std::cerr << "The year ('" << lDateStr.str()
351 << "') is not correct."
352 << std::endl;
353 return false;
354 }
355
356 return true;
357}
358
359// //////////////////////////////////////////////////////////////////
360// Re-compose a time using two strings: the hour and the minute.
361// Return true if a correct time has been computed, false if not.
362bool retrieveTime (std::string iHourString,
363 std::string iMinuteString,
364 stdair::Duration_T& oTime) {
365
366 // Check the hour
367 unsigned short lTimeHour;
368 try {
369
370 lTimeHour = boost::lexical_cast<unsigned short> (iHourString);
371
372 } catch (boost::bad_lexical_cast& eCast) {
373 std::cerr << "The hour of the time ('" << iHourString
374 << "') cannot be understood." << std::endl;
375 return false;
376 }
377
378 // Check the minutes
379 unsigned short lTimeMinute;
380 try {
381
382 lTimeMinute = boost::lexical_cast<unsigned short> (iMinuteString);
383
384 } catch (boost::bad_lexical_cast& eCast) {
385 std::cerr << "The minute of the time ('" << iMinuteString
386 << "') cannot be understood." << std::endl;
387 return false;
388 }
389
390
391 // Re-compose the time
392 std::ostringstream lTimeStr;
393 lTimeStr << lTimeHour << ":" << lTimeMinute;
394 oTime =
395 boost::posix_time::duration_from_string (lTimeStr.str());
396
397 return true;
398}
399
400// //////////////////////////////////////////////////////////////////
401// Analyze the tokens of the 'price' command in order to construct
402// a travel solution list and a booking request.
403const stdair::BookingRequestStruct parseTravelSolutionAndBookingRequestKey
404(const TokenList_T& iTokenList,
405 stdair::TravelSolutionList_T& ioInteractiveTravelSolutionList,
406 const stdair::BookingRequestStruct& ioBookingRequestStruct) {
407
408 TokenList_T::const_iterator itTok = iTokenList.begin();
409
410 if (itTok->empty() == true) {
411
412 std::cerr << "Wrong list of parameters. "
413 << "The default booking request and travel solution list are kept."
414 << std::endl;
415 return ioBookingRequestStruct;
416
417
418 } else {
419 // Parameters corresponding to the tokens.
420 // Each parameter correponds to one token except the dates
421 // (three tokens) and the times (two tokens).
422 stdair::AirlineCode_T lAirlineCode;
423 stdair::FlightNumber_T lflightNumber;
424 stdair::Date_T lDepartureDate;
425 stdair::Duration_T lDepartureTime;
426 stdair::AirportCode_T lOriginAirport;
427 stdair::AirportCode_T lDestinationAirport;
428 stdair::Date_T lRequestDate;
429 stdair::Duration_T lRequestTime;
430 stdair::CityCode_T lPOS;
431 stdair::ChannelLabel_T lChannel;
432 stdair::TripType_T lTripType;
433 unsigned short lStayDuration (stdair::DEFAULT_STAY_DURATION);
434
435 // Read the airline code.
436 lAirlineCode = *itTok;
437 boost::algorithm::to_upper (lAirlineCode);
438
439 // Read the flight-number .
440 ++itTok;
441 if (itTok->empty() == false) {
442 try {
443
444 lflightNumber = boost::lexical_cast<stdair::FlightNumber_T> (*itTok);
445
446 } catch (boost::bad_lexical_cast& eCast) {
447 std::cerr << "The flight number ('" << *itTok
448 << "') cannot be understood."
449 << std::endl;
450 return ioBookingRequestStruct;
451 }
452 }
453
454 // Read the departure date.
455 ++itTok;
456 if (itTok->empty() == true) {
457 return ioBookingRequestStruct;
458 }
459 const std::string lDepartureYearString = *itTok;
460 ++itTok;
461 if (itTok->empty() == true) {
462 return ioBookingRequestStruct;
463 }
464 const std::string lDepartureMonthString = *itTok;
465 ++itTok;
466 if (itTok->empty() == true) {
467 return ioBookingRequestStruct;
468 }
469 const std::string lDepartureDayString = *itTok;
470 const bool IsDepartureDateReadable =
471 retrieveDate (lDepartureYearString, lDepartureMonthString,
472 lDepartureDayString, lDepartureDate);
473
474 if (IsDepartureDateReadable == false) {
475 std::cerr << "The default booking request and travel solution list are kept."
476 << std::endl;
477 return ioBookingRequestStruct;
478 }
479
480 // Read the origin.
481 ++itTok;
482 if (itTok->empty() == false) {
483 lOriginAirport = *itTok;
484 boost::algorithm::to_upper (lOriginAirport);
485 }
486
487 // Read the destination.
488 ++itTok;
489 if (itTok->empty() == false) {
490 lDestinationAirport = *itTok;
491 boost::algorithm::to_upper (lDestinationAirport);
492 }
493
494 // Read the departure time.
495 ++itTok;
496 if (itTok->empty() == true) {
497 return ioBookingRequestStruct;
498 }
499 const std::string lDepartureHourString = *itTok;
500 ++itTok;
501 if (itTok->empty() == true) {
502 return ioBookingRequestStruct;
503 }
504 const std::string lDepartureMinuteString = *itTok;
505 const bool IsDepartureTimeReadable =
506 retrieveTime (lDepartureHourString, lDepartureMinuteString,
507 lDepartureTime);
508
509 if (IsDepartureTimeReadable == false) {
510 std::cerr << "The default booking request and travel solution list are kept."
511 << std::endl;
512 return ioBookingRequestStruct;
513 }
514
515 // Read the request date.
516 ++itTok;
517 if (itTok->empty() == true) {
518 return ioBookingRequestStruct;
519 }
520 const std::string lRequestYearString = *itTok;
521 ++itTok;
522 if (itTok->empty() == true) {
523 return ioBookingRequestStruct;
524 }
525 const std::string lRequestMonthString = *itTok;
526 ++itTok;
527 if (itTok->empty() == true) {
528 return ioBookingRequestStruct;
529 }
530 const std::string lRequestDayString = *itTok;
531 const bool IsRequestDateReadable =
532 retrieveDate (lRequestYearString, lRequestMonthString,
533 lRequestDayString, lRequestDate);
534
535 if (IsRequestDateReadable == false) {
536 std::cerr << "The default booking request and travel solution list are kept."
537 << std::endl;
538 return ioBookingRequestStruct;
539 }
540
541 // Read the request time.
542 ++itTok;
543 if (itTok->empty() == true) {
544 return ioBookingRequestStruct;
545 }
546 const std::string lRequestHourString = *itTok;
547 ++itTok;
548 if (itTok->empty() == true) {
549 return ioBookingRequestStruct;
550 }
551 const std::string lRequestMinuteString = *itTok;
552 const bool IsRequestTimeReadable =
553 retrieveTime (lRequestHourString, lRequestMinuteString,
554 lRequestTime);
555
556 if (IsRequestTimeReadable == false) {
557 std::cerr << "The default booking request and travel solution list are kept."
558 << std::endl;
559 return ioBookingRequestStruct;
560 }
561
562 // Read the POS.
563 ++itTok;
564 if (itTok->empty() == false) {
565 lPOS = *itTok;
566 boost::algorithm::to_upper (lPOS);
567 }
568
569 // Read the channel.
570 ++itTok;
571 if (itTok->empty() == false) {
572 lChannel = *itTok;
573 boost::algorithm::to_upper (lChannel);
574 }
575
576 // Read the trip type.
577 ++itTok;
578 if (itTok->empty() == false) {
579 lTripType = *itTok;
580 boost::algorithm::to_upper (lTripType);
581 }
582
583 // Read the stay duration.
584 ++itTok;
585 if (itTok->empty() == false) {
586 try {
587
588 lStayDuration = boost::lexical_cast<unsigned short> (*itTok);
589
590 } catch (boost::bad_lexical_cast& eCast) {
591 std::cerr << "The stay duration ('" << *itTok
592 << "') cannot be understood." << std::endl;
593 return ioBookingRequestStruct;
594 }
595 }
596
597 // At this step we know that all the parameters designed to construct
598 // the travel solution and the booking request are correct.
599
600 // Empty the travel solution list to store a new travel solution.
601 ioInteractiveTravelSolutionList.clear();
602
603 // Construct the new travel solution.
604 stdair::TravelSolutionStruct lTravelSolution;
605 std::ostringstream oStr;
606 oStr << lAirlineCode
607 << stdair::DEFAULT_KEY_FLD_DELIMITER
608 << lflightNumber
609 << stdair::DEFAULT_KEY_SUB_FLD_DELIMITER
610 << lDepartureDate
611 << stdair::DEFAULT_KEY_FLD_DELIMITER
612 << lOriginAirport
613 << stdair::DEFAULT_KEY_SUB_FLD_DELIMITER
614 << lDestinationAirport
615 << stdair::DEFAULT_KEY_FLD_DELIMITER
616 << lDepartureTime;
617 lTravelSolution.addSegment (oStr.str());
618 ioInteractiveTravelSolutionList.push_front (lTravelSolution);
619
620 // Construct the new booking request.
621 stdair::DateTime_T lRequestDateTime (lRequestDate, lRequestTime);
622 const stdair::BookingRequestStruct& lBookingRequestStruct =
623 stdair::BookingRequestStruct(lOriginAirport,
624 lDestinationAirport,
625 lPOS,
626 lDepartureDate,
627 lRequestDateTime,
628 stdair::CABIN_ECO,
629 stdair::DEFAULT_PARTY_SIZE,
630 lChannel,
631 lTripType,
632 lStayDuration,
633 stdair::FREQUENT_FLYER_MEMBER,
634 lDepartureTime,
635 stdair::DEFAULT_WTP,
636 stdair::DEFAULT_VALUE_OF_TIME,
637 true, 50, true, 50);
638
639 return lBookingRequestStruct;
640 }
641}
642
643// //////////////////////////////////////////////////////////////////
644// Analyze the tokens of the 'display' command in order to retrieve
645// an airport pair and a departure date.
646void parseFlightDateKey (const TokenList_T& iTokenList,
647 stdair::AirportCode_T& ioOrigin,
648 stdair::AirportCode_T& ioDestination,
649 stdair::Date_T& ioDepartureDate) {
650
651 TokenList_T::const_iterator itTok = iTokenList.begin();
652
653 // Interpret the user input.
654 if (itTok->empty() == true) {
655
656 std::cerr << "Wrong parameters specified. Default paramaters '"
657 << ioOrigin << "-" << ioDestination
658 << "/" << ioDepartureDate
659 << "' are kept."
660 << std::endl;
661
662 } else {
663
664 // Read the origin.
665 ioOrigin = *itTok;
666 boost::algorithm::to_upper (ioOrigin);
667
668 // Read the destination.
669 ++itTok;
670 if (itTok->empty() == false) {
671 ioDestination = *itTok;
672 boost::algorithm::to_upper (ioDestination);
673 }
674
675 // Read the departure date.
676 ++itTok;
677 if (itTok->empty() == true) {
678 return;
679 }
680 std::string lYearString = *itTok;
681 ++itTok;
682 if (itTok->empty() == true) {
683 return;
684 }
685 std::string lMonthString = *itTok;
686 ++itTok;
687 if (itTok->empty() == true) {
688 return;
689 }
690 std::string lDayString = *itTok;
691 const bool IsDepartureDateReadable =
692 retrieveDate (lYearString, lMonthString, lDayString,
693 ioDepartureDate);
694 if (IsDepartureDateReadable == false) {
695 std::cerr << "Default paramaters '"
696 << ioOrigin << "-" << ioDestination
697 << "/" << ioDepartureDate
698 << "' are kept."
699 << std::endl;
700 return;
701 }
702 }
703}
704
705// /////////////////////////////////////////////////////////
706std::string toString (const TokenList_T& iTokenList) {
707 std::ostringstream oStr;
708
709 // Re-create the string with all the tokens, trimmed by read-line
710 unsigned short idx = 0;
711 for (TokenList_T::const_iterator itTok = iTokenList.begin();
712 itTok != iTokenList.end(); ++itTok, ++idx) {
713 if (idx != 0) {
714 oStr << " ";
715 }
716 oStr << *itTok;
717 }
718
719 return oStr.str();
720}
721
722// /////////////////////////////////////////////////////////
723TokenList_T extractTokenList (const TokenList_T& iTokenList,
724 const std::string& iRegularExpression) {
725 TokenList_T oTokenList;
726
727 // Re-create the string with all the tokens (which had been trimmed
728 // by read-line)
729 const std::string lFullLine = toString (iTokenList);
730
731 // See the caller for the regular expression
732 boost::regex expression (iRegularExpression);
733
734 std::string::const_iterator start = lFullLine.begin();
735 std::string::const_iterator end = lFullLine.end();
736
737 boost::match_results<std::string::const_iterator> what;
738 boost::match_flag_type flags = boost::match_default | boost::format_sed;
739 regex_search (start, end, what, expression, flags);
740
741 // Put the matched strings in the list of tokens to be returned back
742 // to the caller
743 const unsigned short lMatchSetSize = what.size();
744 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
745 const std::string lMatchedString (std::string (what[matchIdx].first,
746 what[matchIdx].second));
747 //if (lMatchedString.empty() == false) {
748 oTokenList.push_back (lMatchedString);
749 //}
750 }
751
752 // DEBUG
753 // std::cout << "After (token list): " << oTokenList << std::endl;
754
755 return oTokenList;
756}
757
758// /////////////////////////////////////////////////////////
759// Parse the token list of the 'price' command.
760TokenList_T extractTokenListForTSAndBR (const TokenList_T& iTokenList) {
782 const std::string lRegEx("^([[:alpha:]]{2,3})"
783 "[[:space:]]+([[:digit:]]{1,4})"
784 "[/ ]*"
785 "[[:space:]]+([[:digit:]]{2,4})[/-]?"
786 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?"
787 "[[:space:]]*([[:digit:]]{1,2})[[:space:]]*"
788 "[[:space:]]+([[:alpha:]]{3})"
789 "[[:space:]]+([[:alpha:]]{3})"
790 "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})"
791 "[[:space:]]+([[:digit:]]{2,4})[/-]?"
792 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})[/-]?"
793 "[[:space:]]*([[:digit:]]{1,2})"
794 "[[:space:]]+([[:digit:]]{1,2})[:]?([[:digit:]]{1,2})"
795 "[[:space:]]+([[:alpha:]]{3})"
796 "[[:space:]]+([[:alpha:]]{2})"
797 "[[:space:]]+([[:alpha:]]{2})"
798 "[[:space:]]+([[:digit:]]{1})$");
799
800 //
801 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
802 return oTokenList;
803}
804
805// /////////////////////////////////////////////////////////
806// Parse the token list of the 'display' command.
807TokenList_T extractTokenListForOriDestDate (const TokenList_T& iTokenList) {
817 const std::string lRegEx("^([[:alpha:]]{3})"
818 "[[:space:]]*[/-]?"
819 "[[:space:]]*([[:alpha:]]{3})"
820 "[[:space:]]*[/-]?"
821 "[[:space:]]*([[:digit:]]{2,4})"
822 "[[:space:]]*[/-]?"
823 "[[:space:]]*([[:alpha:]]{3}|[[:digit:]]{1,2})"
824 "[[:space:]]*[/-]?"
825 "[[:space:]]*([[:digit:]]{1,2})$");
826
827 //
828 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
829 return oTokenList;
830}
831
832
833// ///////// M A I N ////////////
834int main (int argc, char* argv[]) {
835
836 // State whether the BOM tree should be built-in or parsed from an
837 // input file
838 bool isBuiltin;
839
840 // Fare input file name
841 stdair::Filename_T lFareInputFilename;
842
843 // Readline history
844 const unsigned int lHistorySize (100);
845 const std::string lHistoryFilename ("simfqt.hist");
846 const std::string lHistoryBackupFilename ("simfqt.hist.bak");
847
848 // Default parameters for the interactive session
849 stdair::AirportCode_T lInteractiveOrigin;
850 stdair::AirportCode_T lInteractiveDestination;
851 stdair::Date_T lInteractiveDepartureDate;
852
853 // Output log File
854 stdair::Filename_T lLogFilename;
855
856 // Call the command-line option parser
857 const int lOptionParserStatus =
858 readConfiguration (argc, argv, isBuiltin, lFareInputFilename, lLogFilename);
859
860 if (lOptionParserStatus == K_SIMFQT_EARLY_RETURN_STATUS) {
861 return 0;
862 }
863
864 // Set the log parameters
865 std::ofstream logOutputFile;
866 // Open and clean the log outputfile
867 logOutputFile.open (lLogFilename.c_str());
868 logOutputFile.clear();
869
870 // Initialise the fareQuote service
871 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
872 SIMFQT::SIMFQT_Service simfqtService (lLogParams);
873
874 // DEBUG
875 STDAIR_LOG_DEBUG ("Welcome to SimFQT display");
876
877 // Check wether or not a (CSV) input file should be read
878 if (isBuiltin == true) {
879 // Build the sample BOM tree (filled with fares) for Simfqt
880 simfqtService.buildSampleBom();
881 } else {
882 // Build the BOM tree from parsing a fare file
883 SIMFQT::FareFilePath lFareFilePath (lFareInputFilename);
884 simfqtService.parseAndLoad (lFareFilePath);
885 }
886
887 // DEBUG: Display the whole BOM tree
888 const std::string& lCSVDump = simfqtService.csvDisplay();
889 STDAIR_LOG_DEBUG (lCSVDump);
890
891 // DEBUG
892 STDAIR_LOG_DEBUG ("====================================================");
893 STDAIR_LOG_DEBUG ("= Beginning of the interactive session =");
894 STDAIR_LOG_DEBUG ("====================================================");
895
896 // Initialise the GNU readline wrapper
897 swift::SReadline lReader (lHistoryFilename, lHistorySize);
898 initReadline (lReader);
899
900 // Now we can ask user for a line
901 std::string lUserInput;
902 bool EndOfInput (false);
903 Command_T::Type_T lCommandType (Command_T::NOP);
904
905 while (lCommandType != Command_T::QUIT && EndOfInput == false) {
906 stdair::TravelSolutionList_T lInteractiveTravelSolutionList;
907
908 // Update the default booking request.
909 // If there is an input file, we want the CRS booking request (defined
910 // in stdair).
911 // If not, we want the default booking request.
912 const bool isCRSBookingRequest = !isBuiltin;
913 const stdair::BookingRequestStruct& lInteractiveBookingRequest =
914 simfqtService.buildBookingRequest (isCRSBookingRequest);
915
916 // Update the default parameters for the following interactive session.
917 if (isBuiltin == true) {
918 lInteractiveOrigin = "LHR";
919 lInteractiveDestination = "SYD";
920 lInteractiveDepartureDate = stdair::Date_T(2011,06,10);
921 simfqtService.buildSampleTravelSolutions (lInteractiveTravelSolutionList);
922
923 } else {
924 lInteractiveOrigin = "SIN";
925 lInteractiveDestination = "BKK";
926 lInteractiveDepartureDate = stdair::Date_T(2010,01,30);
927 //
928 const std::string
929 lBA9_SegmentDateKey ("SQ, 970, 2010-01-30, SIN, BKK, 07:10");
930
931 // Add the segment date key to the travel solution.
932 stdair::TravelSolutionStruct lInteractiveTravelSolution;
933 lInteractiveTravelSolution.addSegment (lBA9_SegmentDateKey);
934
935 // Add the travel solution to the list
936 lInteractiveTravelSolutionList.push_back (lInteractiveTravelSolution);
937 }
938
939 // Prompt.
940 std::ostringstream oPromptStr;
941 oPromptStr << "simfqt "
942 << "> ";
943 // The last parameter could be ommited.
944 TokenList_T lTokenListByReadline;
945 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
946 EndOfInput);
947
948 // The history could be saved to an arbitrary file at any time.
949 lReader.SaveHistory (lHistoryBackupFilename);
950
951 if (EndOfInput) {
952 std::cout << std::endl;
953 break;
954 }
955
956 // Interpret the user input.
957 lCommandType = extractCommand (lTokenListByReadline);
958
959 switch (lCommandType) {
960
961 // ////////////////////////////// Help ////////////////////////
962 case Command_T::HELP: {
963 // Search for information to display default parameters lists.
964 // Get the first travel solution.
965 const stdair::TravelSolutionStruct& lInteractiveTravelSolution =
966 lInteractiveTravelSolutionList.front();
967 // Get the segment-path of the first travel solution.
968 const stdair::SegmentPath_T& lSegmentPath =
969 lInteractiveTravelSolution.getSegmentPath();
970 // Get the first segment of the first travel solution.
971 const std::string& lSegmentDateKey = lSegmentPath.front();
972 // Get the parsed key of the first segment of the first travel solution.
973 const stdair::ParsedKey& lParsedKey =
974 stdair::BomKeyManager::extractKeys (lSegmentDateKey);
975 // Get the request date time
976 const stdair::DateTime_T& lRequestDateTime =
977 lInteractiveBookingRequest.getRequestDateTime();
978 const stdair::Time_T lRequestTime =
979 lRequestDateTime.time_of_day();
980 std::cout << std::endl;
981 // Display help.
982 std::cout << "Commands: " << std::endl;
983 std::cout << " help" << "\t\t" << "Display this help" << std::endl;
984 std::cout << " quit" << "\t\t" << "Quit the application" << std::endl;
985 std::cout << " list" << "\t\t"
986 << "List all the fare rule O&Ds and the corresponding date ranges" << std::endl;
987 std::cout << " display" << "\t"
988 << "Display all fare rules for an O&D and a departure date. \n" << "\t\t"
989 << "If no parameters specified or wrong list of parameters, default values are used: \n"<< "\t\t"
990 << " display " << lInteractiveOrigin << " "
991 << lInteractiveDestination << " "
992 << lInteractiveDepartureDate << std::endl;
993 std::cout << " price" << "\t\t"
994 << "Price the travel solution corresponding to a booking request. \n" << "\t\t"
995 << "If no parameters specified or wrong list of parameters, default value are used: \n" << "\t\t"
996 << " price "
997 << lParsedKey._airlineCode << " "
998 << lParsedKey._flightNumber << " "
999 << lParsedKey._departureDate << " "
1000 << lParsedKey._boardingPoint << " "
1001 << lParsedKey._offPoint << " "
1002 << lParsedKey._boardingTime << " "
1003 << lRequestDateTime.date() << " "
1004 << lRequestTime.hours() << ":" << lRequestTime.minutes() << " "
1005 << lInteractiveBookingRequest.getPOS() << " "
1006 << lInteractiveBookingRequest.getBookingChannel() << " "
1007 << lInteractiveBookingRequest.getTripType() << " "
1008 << lInteractiveBookingRequest.getStayDuration() << std::endl;
1009 std::cout << std::endl;
1010 break;
1011 }
1012
1013 // ////////////////////////////// Quit ////////////////////////
1014 case Command_T::QUIT: {
1015 break;
1016 }
1017
1018 // ////////////////////////////// List /////////////////////////
1019 case Command_T::LIST: {
1020
1021 // Get the list of all airport pairs and date ranges for which
1022 // there are fares available.
1023 const std::string& lAirportPairDateListStr =
1024 simfqtService.list ();
1025
1026 if (lAirportPairDateListStr.empty() == false) {
1027 std::cout << lAirportPairDateListStr << std::endl;
1028 STDAIR_LOG_DEBUG (lAirportPairDateListStr);
1029
1030 } else {
1031 std::cerr << "There is no result for airport pairs and date ranges."
1032 << "Make sure your input file is not empty."
1033 << std::endl;
1034 }
1035
1036 break;
1037 }
1038
1039 // ////////////////////////////// Display /////////////////////////
1040 case Command_T::DISPLAY: {
1041
1042 // If no parameters are entered by the user, keep default ones.
1043 if (lTokenListByReadline.empty() == true) {
1044
1045 std::cout << "No parameters specified. Default paramaters '"
1046 << lInteractiveOrigin << "-" << lInteractiveDestination
1047 << "/" << lInteractiveDepartureDate
1048 << "' are kept."
1049 << std::endl;
1050
1051 } else {
1052
1053 // Find the best match corresponding to the given parameters.
1054 TokenList_T lTokenList =
1055 extractTokenListForOriDestDate (lTokenListByReadline);
1056
1057 // Parse the best match, and give default values in case the
1058 // user does not specify all the parameters or does not
1059 // specify some of them correctly.
1060 parseFlightDateKey (lTokenList, lInteractiveOrigin,
1061 lInteractiveDestination, lInteractiveDepartureDate);
1062
1063 }
1064
1065 // Check whether the selected airportpair-date is valid:
1066 // i.e. if there are corresponding fare rules.
1067 const bool isAirportPairDateValid =
1068 simfqtService.check (lInteractiveOrigin, lInteractiveDestination,
1069 lInteractiveDepartureDate);
1070
1071 if (isAirportPairDateValid == false) {
1072 std::ostringstream oFDKStr;
1073 oFDKStr << "The airport pair/departure date: "
1074 << lInteractiveOrigin << "-" << lInteractiveDestination
1075 << "/" << lInteractiveDepartureDate
1076 << " does not correpond to any fare rule.\n"
1077 << "Make sure it exists with the 'list' command.";
1078 std::cout << oFDKStr.str() << std::endl;
1079 STDAIR_LOG_ERROR (oFDKStr.str());
1080
1081 break;
1082 }
1083
1084 // Display the list of corresponding fare rules.
1085 std::cout << "List of fare rules for "
1086 << lInteractiveOrigin << "-"
1087 << lInteractiveDestination << "/"
1088 << lInteractiveDepartureDate
1089 << std::endl;
1090
1091 const std::string& lFareRuleListStr =
1092 simfqtService.csvDisplay (lInteractiveOrigin,
1093 lInteractiveDestination,
1094 lInteractiveDepartureDate);
1095
1096 assert (lFareRuleListStr.empty() == false);
1097 std::cout << lFareRuleListStr << std::endl;
1098 STDAIR_LOG_DEBUG (lFareRuleListStr);
1099
1100 break;
1101 }
1102
1103 // ////////////////////////////// Price ////////////////////////
1104 case Command_T::PRICE: {
1105
1106 // If no parameters are entered by the user, keep default ones.
1107 if (lTokenListByReadline.empty() == true) {
1108 const stdair::TravelSolutionStruct& lInteractiveTravelSolution =
1109 lInteractiveTravelSolutionList.front();
1110
1111 std::cout << "No parameters specified. Default booking request "
1112 << "and default travel solution list are kept.\n"
1113 << "Booking request: << "
1114 << lInteractiveBookingRequest.display() << " >>"
1115 << "\nTravel Solution: << "
1116 << lInteractiveTravelSolution.display() << " >>"
1117 << "\n********** \n"
1118 << "Fare quote"
1119 << "\n**********"
1120 << std::endl;
1121
1122 // Try to fareQuote the sample list of travel solutions.
1123 try {
1124
1125 simfqtService.quotePrices (lInteractiveBookingRequest,
1126 lInteractiveTravelSolutionList);
1127
1128 } catch (stdair::ObjectNotFoundException& E) {
1129 std::cerr << "The given travel solution corresponding to the given"
1130 << "booking request can not be priced.\n"
1131 << E.what()
1132 << std::endl;
1133 break;
1134 }
1135
1136 } else {
1137 // Find the best match corresponding to the given parameters.
1138 TokenList_T lTokenList =
1139 extractTokenListForTSAndBR (lTokenListByReadline);
1140
1141 // Parse the best match, and give default values in case the
1142 // user does not specify all the parameters or does not
1143 // specify some of them correctly.
1144 stdair::BookingRequestStruct lFinalBookingRequest =
1145 parseTravelSolutionAndBookingRequestKey(lTokenList,
1146 lInteractiveTravelSolutionList,
1147 lInteractiveBookingRequest);
1148
1149
1150 assert (lInteractiveTravelSolutionList.size() >= 1);
1151 const stdair::TravelSolutionStruct& lInteractiveTravelSolution =
1152 lInteractiveTravelSolutionList.front();
1153
1154 // Display the booking request and the first travel solution
1155 // before pricing.
1156 std::cout << "Booking request: << "
1157 << lFinalBookingRequest.display() << " >>"
1158 << "\nTravel Solution: << "
1159 << lInteractiveTravelSolution.display() << " >>"
1160 << "\n********** \n"
1161 << "Fare quote"
1162 << "\n**********"
1163 << std::endl;
1164
1165 // Try to fareQuote the sample list of travel solutions.
1166 try {
1167
1168 simfqtService.quotePrices (lFinalBookingRequest,
1169 lInteractiveTravelSolutionList);
1170
1171 } catch (stdair::ObjectNotFoundException& E) {
1172 std::cerr << "The given travel solution corresponding to the given"
1173 << "booking request can not be priced.\n"
1174 << E.what()
1175 << std::endl;
1176 break;
1177 }
1178 }
1179
1180 // Display the first travel solution after pricing:
1181 // one or more fare option have been added.
1182 const stdair::TravelSolutionStruct& lInteractiveTravelSolution =
1183 lInteractiveTravelSolutionList.front();
1184 std::cout << "Travel Solution: << "
1185 << lInteractiveTravelSolution.display() << " >>\n"
1186 << std::endl;
1187 break;
1188 }
1189
1190 // /////////////////////////// Default / No value ///////////////////////
1191 case Command_T::NOP: {
1192 break;
1193 }
1194 case Command_T::LAST_VALUE:
1195 default: {
1196 // DEBUG
1197 std::ostringstream oStr;
1198 oStr << "The '" << lUserInput << "' command is not yet understood.\n"
1199 << "Type help to have more information." << std::endl;
1200
1201 STDAIR_LOG_DEBUG (oStr.str());
1202 std::cout << oStr.str() << std::endl;
1203 }
1204 }
1205
1206 }
1207
1208 return 0;
1209}
Interface for the SIMFQT Services.
int main(int argc, char *argv[])
const int K_SIMFQT_EARLY_RETURN_STATUS
const std::string K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME(STDAIR_SAMPLE_DIR "/fare01.csv")
const bool K_SIMFQT_DEFAULT_BUILT_IN_INPUT
const std::string K_SIMFQT_DEFAULT_LOG_FILENAME("simfqt_parseFareRules.log")
std::ostream & operator<<(std::ostream &os, const std::vector< T > &v)
int readConfiguration(int argc, char *argv[], bool &ioIsBuiltin, stdair::Filename_T &ioFareInputFilename, std::string &ioLogFilename)