SimFQT Logo  1.00.4
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 //////
44 const std::string K_SIMFQT_DEFAULT_LOG_FILENAME ("simfqt.log");
45 
49 const std::string K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME (STDAIR_SAMPLE_DIR
50  "/fare01.csv");
51 
56 const bool K_SIMFQT_DEFAULT_BUILT_IN_INPUT = false;
57 
61 const int K_SIMFQT_EARLY_RETURN_STATUS = 99;
62 
67 typedef std::vector<std::string> TokenList_T;
68 
72 struct 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.
86 template<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 
95 int readConfiguration (int argc, char* argv[], bool& ioIsBuiltin,
96  stdair::Filename_T& ioFareInputFilename,
97  std::string& ioLogFilename) {
98 
99  // Default for the built-in input
100  ioIsBuiltin = K_SIMFQT_DEFAULT_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 // //////////////////////////////////////////////////////////////////
198 void 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 // //////////////////////////////////////////////////////////////////
218 Command_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.
258 bool 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.
362 bool 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.
403 const 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.
646 void 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 // /////////////////////////////////////////////////////////
706 std::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 // /////////////////////////////////////////////////////////
723 TokenList_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.
760 TokenList_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.
807 TokenList_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 ////////////
834 int 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 }
main
int main(int argc, char *argv[])
Definition: simfqt_parseFareRules.cpp:154
SIMFQT::FareFilePath
Definition: SIMFQT_Types.hpp:130
K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME
const std::string K_SIMFQT_DEFAULT_FARE_INPUT_FILENAME(STDAIR_SAMPLE_DIR "/fare01.csv")
operator<<
std::ostream & operator<<(std::ostream &os, const std::vector< T > &v)
Definition: simfqt_parseFareRules.cpp:44
SIMFQT::SIMFQT_Service
Interface for the SIMFQT Services.
Definition: SIMFQT_Service.hpp:32
K_SIMFQT_DEFAULT_LOG_FILENAME
const std::string K_SIMFQT_DEFAULT_LOG_FILENAME("simfqt_parseFareRules.log")
readConfiguration
int readConfiguration(int argc, char *argv[], bool &ioIsBuiltin, stdair::Filename_T &ioFareInputFilename, std::string &ioLogFilename)
Definition: simfqt_parseFareRules.cpp:51
SIMFQT_Service.hpp
K_SIMFQT_DEFAULT_BUILT_IN_INPUT
const bool K_SIMFQT_DEFAULT_BUILT_IN_INPUT
Definition: simfqt_parseFareRules.cpp:37
K_SIMFQT_EARLY_RETURN_STATUS
const int K_SIMFQT_EARLY_RETURN_STATUS
Definition: simfqt_parseFareRules.cpp:40