SimCRS Logo  1.00.0
C++ Simulated Travel-Oriented Distribution System Library
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
simcrs.cpp
Go to the documentation of this file.
1 // STL
2 #include <sstream>
3 #include <fstream>
4 #include <string>
5 // Boost (Extended STL)
6 #include <boost/program_options.hpp>
7 // StdAir
8 #include <stdair/stdair_basic_types.hpp>
9 #include <stdair/basic/BasLogParams.hpp>
10 #include <stdair/basic/BasDBParams.hpp>
11 #include <stdair/basic/BasFileMgr.hpp>
12 #include <stdair/bom/TravelSolutionStruct.hpp>
13 #include <stdair/bom/BookingRequestStruct.hpp>
14 #include <stdair/service/Logger.hpp>
15 // SimFQT
16 #include <simfqt/SIMFQT_Types.hpp>
17 // SimCRS
19 #include <simcrs/config/simcrs-paths.hpp>
20 
21 // //////// Constants //////
25 const std::string K_SIMCRS_DEFAULT_LOG_FILENAME ("simcrs.log");
26 
31  "/schedule01.csv");
32 
37  "/ond01.csv");
38 
43  "/frat5.csv");
48  "/ffDisutility.csv");
49 
54  "/yieldstore01.csv");
55 
60  "/fare01.csv");
61 
68 
72 const std::string K_SIMCRS_DEFAULT_DB_USER ("dsim");
73 const std::string K_SIMCRS_DEFAULT_DB_PASSWD ("dsim");
74 const std::string K_SIMCRS_DEFAULT_DB_DBNAME ("sim_dsim");
75 const std::string K_SIMCRS_DEFAULT_DB_HOST ("localhost");
76 const std::string K_SIMCRS_DEFAULT_DB_PORT ("3306");
77 
78 // ///////// Parsing of Options & Configuration /////////
79 // A helper function to simplify the main part.
80 template<class T> std::ostream& operator<< (std::ostream& os,
81  const std::vector<T>& v) {
82  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
83  return os;
84 }
85 
88 
90 int readConfiguration (int argc, char* argv[],
91  bool& ioIsBuiltin,
92  stdair::Filename_T& ioScheduleInputFilename,
93  stdair::Filename_T& ioOnDInputFilename,
94  stdair::Filename_T& ioFRAT5Filename,
95  stdair::Filename_T& ioFFDisutilityFilename,
96  stdair::Filename_T& ioYieldInputFilename,
97  stdair::Filename_T& ioFareInputFilename,
98  stdair::Filename_T& ioLogFilename,
99  std::string& ioDBUser, std::string& ioDBPasswd,
100  std::string& ioDBHost, std::string& ioDBPort,
101  std::string& ioDBDBName) {
102  // Default for the built-in input
103  ioIsBuiltin = K_SIMCRS_DEFAULT_BUILT_IN_INPUT;
104 
105  // Declare a group of options that will be allowed only on command line
106  boost::program_options::options_description generic ("Generic options");
107  generic.add_options()
108  ("prefix", "print installation prefix")
109  ("version,v", "print version string")
110  ("help,h", "produce help message");
111 
112  // Declare a group of options that will be allowed both on command
113  // line and in config file
114  boost::program_options::options_description config ("Configuration");
115  config.add_options()
116  ("builtin,b",
117  "The sample BOM tree can be either built-in or parsed from input files. In that latter case, the input files must be specified as well (e.g., -s/--schedule, -o/--ond, -f/--fare, -y/--yield)")
118  ("schedule,s",
119  boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_SIMCRS_DEFAULT_SCHEDULE_INPUT_FILENAME),
120  "(CVS) input file for the schedules")
121  ("ond,o",
122  boost::program_options::value< std::string >(&ioOnDInputFilename)->default_value(K_SIMCRS_DEFAULT_OND_INPUT_FILENAME),
123  "(CVS) input file for the O&D definitions")
124  ("frat5,F",
125  boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_SIMCRS_DEFAULT_FRAT5_INPUT_FILENAME),
126  "(CSV) input file for the FRAT5 Curve")
127  ("ff_disutility,D",
128  boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_SIMCRS_DEFAULT_FF_DISUTILITY_INPUT_FILENAME),
129  "(CSV) input file for the FF disutility Curve")
130  ("yield,y",
131  boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_SIMCRS_DEFAULT_YIELD_INPUT_FILENAME),
132  "(CVS) input file for the yields")
133  ("fare,f",
134  boost::program_options::value< std::string >(&ioFareInputFilename)->default_value(K_SIMCRS_DEFAULT_FARE_INPUT_FILENAME),
135  "(CVS) input file for the fares")
136  ("log,l",
137  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_SIMCRS_DEFAULT_LOG_FILENAME),
138  "Filepath for the logs")
139  ("user,u",
140  boost::program_options::value< std::string >(&ioDBUser)->default_value(K_SIMCRS_DEFAULT_DB_USER),
141  "SQL database username")
142  ("passwd,p",
143  boost::program_options::value< std::string >(&ioDBPasswd)->default_value(K_SIMCRS_DEFAULT_DB_PASSWD),
144  "SQL database password")
145  ("host,H",
146  boost::program_options::value< std::string >(&ioDBHost)->default_value(K_SIMCRS_DEFAULT_DB_HOST),
147  "SQL database hostname")
148  ("port,P",
149  boost::program_options::value< std::string >(&ioDBPort)->default_value(K_SIMCRS_DEFAULT_DB_PORT),
150  "SQL database port")
151  ("dbname,m",
152  boost::program_options::value< std::string >(&ioDBDBName)->default_value(K_SIMCRS_DEFAULT_DB_DBNAME),
153  "SQL database name")
154  ;
155 
156  // Hidden options, will be allowed both on command line and
157  // in config file, but will not be shown to the user.
158  boost::program_options::options_description hidden ("Hidden options");
159  hidden.add_options()
160  ("copyright",
161  boost::program_options::value< std::vector<std::string> >(),
162  "Show the copyright (license)");
163 
164  boost::program_options::options_description cmdline_options;
165  cmdline_options.add(generic).add(config).add(hidden);
166 
167  boost::program_options::options_description config_file_options;
168  config_file_options.add(config).add(hidden);
169 
170  boost::program_options::options_description visible ("Allowed options");
171  visible.add(generic).add(config);
172 
173  boost::program_options::positional_options_description p;
174  p.add ("copyright", -1);
175 
176  boost::program_options::variables_map vm;
177  boost::program_options::
178  store (boost::program_options::command_line_parser (argc, argv).
179  options (cmdline_options).positional(p).run(), vm);
180 
181  std::ifstream ifs ("simcrs.cfg");
182  boost::program_options::store (parse_config_file (ifs, config_file_options),
183  vm);
184  boost::program_options::notify (vm);
185 
186  if (vm.count ("help")) {
187  std::cout << visible << std::endl;
189  }
190 
191  if (vm.count ("version")) {
192  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
194  }
195 
196  if (vm.count ("prefix")) {
197  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
199  }
200 
201  if (vm.count ("builtin")) {
202  ioIsBuiltin = true;
203  }
204  const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
205  std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
206 
207  //
208  std::ostringstream oErrorMessageStr;
209  oErrorMessageStr << "Either the -b/--builtin option, or the combination of "
210  << "the -s/--schedule, -o/--ond, -f/--fare and -y/--yield "
211  << "options must be specified";
212 
213  if (ioIsBuiltin == false) {
214  if (vm.count ("schedule")) {
215  ioScheduleInputFilename = vm["schedule"].as< std::string >();
216  std::cout << "Schedule input filename is: " << ioScheduleInputFilename
217  << std::endl;
218 
219  } else {
220  // The built-in option is not selected. However, no schedule input file
221  // is specified
222  std::cerr << oErrorMessageStr.str() << std::endl;
223  }
224 
225  if (vm.count ("ond")) {
226  ioOnDInputFilename = vm["ond"].as< std::string >();
227  std::cout << "O&D input filename is: " << ioOnDInputFilename << std::endl;
228 
229  } else {
230  // The built-in option is not selected. However, no schedule input file
231  // is specified
232  std::cerr << oErrorMessageStr.str() << std::endl;
233  }
234 
235  if (vm.count ("frat5")) {
236  ioFRAT5Filename = vm["frat5"].as< std::string >();
237  std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl;
238 
239  } else {
240  // The built-in option is not selected. However, no frat5 input file
241  // is specified
242  std::cerr << oErrorMessageStr.str() << std::endl;
243  }
244 
245  if (vm.count ("ff_disutility")) {
246  ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >();
247  std::cout << "FF disutility input filename is: "
248  << ioFFDisutilityFilename << std::endl;
249 
250  } else {
251  // The built-in option is not selected. However, no ff
252  // disutility input file is specified
253  std::cerr << oErrorMessageStr.str() << std::endl;
254  }
255 
256  if (vm.count ("yield")) {
257  ioYieldInputFilename = vm["yield"].as< std::string >();
258  std::cout << "Yield input filename is: " << ioYieldInputFilename
259  << std::endl;
260 
261  } else {
262  // The built-in option is not selected. However, no schedule input file
263  // is specified
264  std::cerr << oErrorMessageStr.str() << std::endl;
265  }
266 
267  if (vm.count ("fare")) {
268  ioFareInputFilename = vm["fare"].as< std::string >();
269  std::cout << "Fare input filename is: " << ioFareInputFilename
270  << std::endl;
271 
272  } else {
273  // The built-in option is not selected. However, no schedule input file
274  // is specified
275  std::cerr << oErrorMessageStr.str() << std::endl;
276  }
277  }
278 
279  if (vm.count ("log")) {
280  ioLogFilename = vm["log"].as< std::string >();
281  std::cout << "Log filename is: " << ioLogFilename << std::endl;
282  }
283 
284  if (vm.count ("user")) {
285  ioDBUser = vm["user"].as< std::string >();
286  std::cout << "SQL database user name is: " << ioDBUser << std::endl;
287  }
288 
289  if (vm.count ("passwd")) {
290  ioDBPasswd = vm["passwd"].as< std::string >();
291  //std::cout << "SQL database user password is: " << ioDBPasswd << std::endl;
292  }
293 
294  if (vm.count ("host")) {
295  ioDBHost = vm["host"].as< std::string >();
296  std::cout << "SQL database host name is: " << ioDBHost << std::endl;
297  }
298 
299  if (vm.count ("port")) {
300  ioDBPort = vm["port"].as< std::string >();
301  std::cout << "SQL database port number is: " << ioDBPort << std::endl;
302  }
303 
304  if (vm.count ("dbname")) {
305  ioDBDBName = vm["dbname"].as< std::string >();
306  std::cout << "SQL database name is: " << ioDBDBName << std::endl;
307  }
308 
309  return 0;
310 }
311 
312 // ///////// M A I N ////////////
313 int main (int argc, char* argv[]) {
314 
315  // State whether the BOM tree should be built-in or parsed from an
316  // input file
317  bool isBuiltin;
318 
319  // Schedule input filename
320  stdair::Filename_T lScheduleInputFilename;
321 
322  // O&D input filename
323  stdair::Filename_T lOnDInputFilename;
324 
325  // FRAT5 input filename
326  std::string lFRAT5InputFilename;
327 
328  // FF disutility input filename
329  std::string lFFDisutilityInputFilename;
330 
331  // Yield input filename
332  stdair::Filename_T lYieldInputFilename;
333 
334  // Fare input filename
335  stdair::Filename_T lFareInputFilename;
336 
337  // Output log File
338  stdair::Filename_T lLogFilename;
339 
340  // SQL database parameters
341  std::string lDBUser;
342  std::string lDBPasswd;
343  std::string lDBHost;
344  std::string lDBPort;
345  std::string lDBDBName;
346 
347  // CRS code
348  const SIMCRS::CRSCode_T lCRSCode ("1P");
349 
350  // Call the command-line option parser
351  const int lOptionParserStatus =
352  readConfiguration (argc, argv, isBuiltin,
353  lScheduleInputFilename, lOnDInputFilename,
354  lFRAT5InputFilename, lFFDisutilityInputFilename,
355  lYieldInputFilename, lFareInputFilename, lLogFilename,
356  lDBUser, lDBPasswd, lDBHost, lDBPort, lDBDBName);
357 
358  if (lOptionParserStatus == K_SIMCRS_EARLY_RETURN_STATUS) {
359  return 0;
360  }
361 
362  // Set the database parameters
363  const stdair::BasDBParams lDBParams (lDBUser, lDBPasswd, lDBHost, lDBPort,
364  lDBDBName);
365 
366  // Set the log parameters
367  std::ofstream logOutputFile;
368  // Open and clean the log outputfile
369  logOutputFile.open (lLogFilename.c_str());
370  logOutputFile.clear();
371 
372  // Initialise the list of classes/buckets
373  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
374  SIMCRS::SIMCRS_Service simcrsService (lLogParams, lCRSCode);
375 
376  // Check wether or not (CSV) input files should be read
377  if (isBuiltin == true) {
378 
379  // Build the sample BOM tree
380  simcrsService.buildSampleBom();
381 
382  } else {
383  // Build the BOM tree from parsing input files
384  stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename);
385  stdair::ODFilePath lODFilePath (lOnDInputFilename);
386  stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename);
387  stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename);
388  const SIMFQT::FareFilePath lFareFilePath (lFareInputFilename);
389  const AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename);
390  simcrsService.parseAndLoad (lScheduleFilePath, lODFilePath,
391  lFRAT5FilePath, lFFDisutilityFilePath,
392  lYieldFilePath, lFareFilePath);
393  }
394 
395  // TODO (issue #37707): instead of building a sample, read the parameters
396  // from the command-line options, and build the corresponding
397  // booking request
398  const bool isForCRS = true;
399  const stdair::BookingRequestStruct& lBookingRequest =
400  simcrsService.buildSampleBookingRequest (isForCRS);
401 
402  // Calculate the travel solutions corresponding to the given booking request
403  stdair::TravelSolutionList_T lTravelSolutionList =
404  simcrsService.calculateSegmentPathList (lBookingRequest);
405 
406  // Check whether everything was fine
407  if (lTravelSolutionList.empty() == true) {
408  STDAIR_LOG_ERROR ("No travel solution has been found for: "
409  << lBookingRequest.display());
410  return -1;
411  }
412 
413  // Price the travel solution
414  simcrsService.fareQuote (lBookingRequest, lTravelSolutionList);
415 
416  // Choose a random travel solution: the first one.
417  stdair::TravelSolutionStruct& lChosenTravelSolution =
418  lTravelSolutionList.front();
419 
420  // Get the segment path of the travel solution.
421  const stdair::KeyList_T& lsegmentDateKeyList =
422  lChosenTravelSolution.getSegmentPath();
423 
424  const stdair::FareOptionList_T& lFareOptionList =
425  lChosenTravelSolution.getFareOptionList();
426 
427  // Check whether everything was fine
428  if (lFareOptionList.empty() == true) {
429  STDAIR_LOG_ERROR ("No fare option for the chosen travel solution: "
430  << lChosenTravelSolution.display());
431  return -1;
432  }
433 
434  //
435  const stdair::FareOptionStruct& lFareOption = lFareOptionList.front();
436  lChosenTravelSolution.setChosenFareOption (lFareOption);
437 
438  // DEBUG
439  const std::string& lSegmentDateKey = lsegmentDateKeyList.front();
440  STDAIR_LOG_DEBUG ("The chosen travel solution is: " << lSegmentDateKey
441  << ", the fare is: " << lFareOption.getFare() << " Euros.");
442 
443  // Make a booking (reminder: party size is 3)
444  const stdair::PartySize_T lPartySize (3);
445  const bool isSellSuccessful =
446  simcrsService.sell (lChosenTravelSolution, lPartySize);
447 
448  // DEBUG
449  STDAIR_LOG_DEBUG ("Sale ('" << lBookingRequest << "'): "
450  << " successful? " << isSellSuccessful);
451 
452  // DEBUG: Display the whole BOM tree
453  const std::string& lCSVDump = simcrsService.csvDisplay();
454  STDAIR_LOG_DEBUG (lCSVDump);
455 
456  // Close the Log outputFile
457  logOutputFile.close();
458 
459  /*
460  Note: as that program is not intended to be run on a server in
461  production, it is better not to catch the exceptions. When it
462  happens (that an exception is throwned), that way we get the
463  call stack.
464  */
465 
466  return 0;
467 }