AirSched Logo  0.1.4
C++ Simulated Airline Schedule Manager Library
OnDParserHelper.cpp
Go to the documentation of this file.
00001 // //////////////////////////////////////////////////////////////////////
00002 // Import section
00003 // //////////////////////////////////////////////////////////////////////
00004 // STL
00005 #include <cassert>
00006 // StdAir
00007 #include <stdair/basic/BasFileMgr.hpp>
00008 #include <stdair/bom/BomRoot.hpp>
00009 #include <stdair/service/Logger.hpp>
00010 // AIRSCHED
00011 #include <airsched/command/OnDParserHelper.hpp>
00012 #include <airsched/command/OnDPeriodGenerator.hpp>
00013 
00014 namespace AIRSCHED {
00015 
00016   namespace OnDParserHelper {
00017 
00018     // //////////////////////////////////////////////////////////////////////
00019     //
00020     //  Semantic actions
00021     //
00022     // //////////////////////////////////////////////////////////////////////
00023       
00024     ParserSemanticAction::
00025     ParserSemanticAction (OnDPeriodStruct& ioOnDPeriod)
00026       : _onDPeriod (ioOnDPeriod) {
00027     }
00028 
00029     // //////////////////////////////////////////////////////////////////////
00030     storeOrigin::storeOrigin (OnDPeriodStruct& ioOnDPeriod)
00031       : ParserSemanticAction (ioOnDPeriod) {
00032     }
00033 
00034     // //////////////////////////////////////////////////////////////////////
00035     void storeOrigin::operator() (iterator_t iStr,
00036                                   iterator_t iStrEnd) const {
00037       std::string lOrigin (iStr, iStrEnd);
00038       //STDAIR_LOG_DEBUG ( "Origin: " << lOrigin << std::endl);
00039 
00040       // Set the origin
00041       _onDPeriod._origin = lOrigin;
00042       _onDPeriod._nbOfAirlines = 0;
00043       _onDPeriod._airlineCode = "";
00044       _onDPeriod._classCode = "";
00045       _onDPeriod._airlineCodeList.clear();
00046       _onDPeriod._classCodeList.clear(); 
00047     }
00048 
00049     // //////////////////////////////////////////////////////////////////////
00050     storeDestination::storeDestination (OnDPeriodStruct& ioOnDPeriod)
00051       : ParserSemanticAction (ioOnDPeriod) {
00052     }
00053 
00054     // //////////////////////////////////////////////////////////////////////
00055     void storeDestination::operator() (iterator_t iStr,
00056                                        iterator_t iStrEnd) const {
00057       std::string lDestination (iStr, iStrEnd);
00058       //STDAIR_LOG_DEBUG ("Destination: " << lDestination << std::endl);
00059 
00060       // Set the destination
00061       _onDPeriod._destination = lDestination;
00062     }
00063 
00064     // //////////////////////////////////////////////////////////////////////
00065     storeDateRangeStart::
00066     storeDateRangeStart (OnDPeriodStruct& ioOnDPeriod)
00067       : ParserSemanticAction (ioOnDPeriod) {
00068     }
00069     
00070     // //////////////////////////////////////////////////////////////////////
00071     void storeDateRangeStart::operator() (iterator_t iStr,
00072                                           iterator_t iStrEnd) const {
00073       _onDPeriod._dateRangeStart = _onDPeriod.getDate();
00074       /*STDAIR_LOG_DEBUG ("Date Range Start: "
00075         << _onDPeriod._dateRangeStart << std::endl);*/
00076         
00077       // Reset the number of seconds
00078       _onDPeriod._itSeconds = 0;
00079     }
00080       
00081     // //////////////////////////////////////////////////////////////////////
00082     storeDateRangeEnd::
00083     storeDateRangeEnd (OnDPeriodStruct& ioOnDPeriod)
00084       : ParserSemanticAction (ioOnDPeriod) {
00085     }
00086     
00087     // //////////////////////////////////////////////////////////////////////
00088     void storeDateRangeEnd::operator() (iterator_t iStr,
00089                                         iterator_t iStrEnd) const {
00090       // As a Boost date period (COM::DatePeriod_T) defines the last day of
00091       // the period to be end-date - one day, we have to add one day to that
00092       // end date before.
00093       const stdair::DateOffset_T oneDay (1);
00094       _onDPeriod._dateRangeEnd = _onDPeriod.getDate() + oneDay;
00095       /*STDAIR_LOG_DEBUG ( "Date Range End: "
00096         << _onDPeriod._dateRangeEnd << std::endl);*/
00097 
00098       // Transform the date pair (i.e., the date range) into a date period
00099       _onDPeriod._datePeriod =
00100         stdair::DatePeriod_T (_onDPeriod._dateRangeStart,
00101                               _onDPeriod._dateRangeEnd);
00102         
00103       // Reset the number of seconds
00104       _onDPeriod._itSeconds = 0;
00105     }
00106 
00107     // //////////////////////////////////////////////////////////////////////
00108     storeStartRangeTime::
00109     storeStartRangeTime (OnDPeriodStruct& ioOnDPeriod)
00110       : ParserSemanticAction (ioOnDPeriod) {
00111     }
00112     
00113     // //////////////////////////////////////////////////////////////////////
00114     void storeStartRangeTime::operator() (iterator_t iStr,
00115                                           iterator_t iStrEnd) const {
00116       _onDPeriod._timeRangeStart = _onDPeriod.getTime();
00117         
00118       // Reset the number of seconds
00119       _onDPeriod._itSeconds = 0;
00120     }
00121 
00122     // //////////////////////////////////////////////////////////////////////
00123     storeEndRangeTime::
00124     storeEndRangeTime (OnDPeriodStruct& ioOnDPeriod)
00125       : ParserSemanticAction (ioOnDPeriod) {
00126     }
00127 
00128     // //////////////////////////////////////////////////////////////////////
00129     void storeEndRangeTime::operator() (iterator_t iStr,
00130                                         iterator_t iStrEnd) const {
00131       _onDPeriod._timeRangeEnd = _onDPeriod.getTime();
00132         
00133       // Reset the number of seconds
00134       _onDPeriod._itSeconds = 0;
00135     }
00136 
00137     // //////////////////////////////////////////////////////////////////////
00138     storeAirlineCode::
00139     storeAirlineCode (OnDPeriodStruct& ioOnDPeriod)
00140       : ParserSemanticAction (ioOnDPeriod) {
00141     }
00142     
00143     // //////////////////////////////////////////////////////////////////////
00144     void storeAirlineCode::operator() (iterator_t iStr,
00145                                        iterator_t iStrEnd) const { 
00146       const std::string lAirlineCodeStr (iStr, iStrEnd);
00147       const stdair::AirlineCode_T lAirlineCode(lAirlineCodeStr);
00148       // Test if the OnD Period Struct stands for interline products
00149       if (_onDPeriod._airlineCodeList.size() > 0) {
00150         // update the airline code
00151         std::ostringstream ostr;
00152         ostr << _onDPeriod._airlineCode << lAirlineCode;
00153         _onDPeriod._airlineCode = ostr.str();
00154         // Update the number of airlines if necessary
00155         const stdair::AirlineCode_T lPreviousAirlineCode =
00156           _onDPeriod._airlineCodeList.back();
00157         if (lPreviousAirlineCode != lAirlineCode) {
00158           _onDPeriod._nbOfAirlines = _onDPeriod._nbOfAirlines + 1;
00159         }
00160       }
00161       else {
00162         _onDPeriod._airlineCode = lAirlineCode; 
00163         _onDPeriod._nbOfAirlines = 1;
00164       }
00165       _onDPeriod._airlineCodeList.push_back (lAirlineCode);
00166         
00167       //STDAIR_LOG_DEBUG ( "Airline code: " << lAirlineCode << std::endl);
00168     }
00169 
00170     // //////////////////////////////////////////////////////////////////////
00171     storeClassCode::
00172     storeClassCode (OnDPeriodStruct& ioOnDPeriod)
00173       : ParserSemanticAction (ioOnDPeriod) {
00174     }
00175     
00176     // //////////////////////////////////////////////////////////////////////
00177     void storeClassCode::operator() (char iChar) const {
00178       std::ostringstream ostr;
00179       ostr << iChar;
00180       std::string classCodeStr = ostr.str();
00181       const stdair::ClassCode_T lClassCode (classCodeStr);
00182       _onDPeriod._classCodeList.push_back(lClassCode);
00183       /*STDAIR_LOG_DEBUG ("Class Code: "
00184         << lClassCode << std::endl);*/
00185       // Insertion of this class Code in the whole classCode name
00186       std::ostringstream ostrr;
00187       ostrr << _onDPeriod._classCode << classCodeStr;
00188       _onDPeriod._classCode = ostrr.str();
00189         
00190     }
00191       
00192     // //////////////////////////////////////////////////////////////////////
00193     doEndOnD::doEndOnD (stdair::BomRoot& ioBomRoot, OnDPeriodStruct& ioOnDPeriod)
00194       : ParserSemanticAction (ioOnDPeriod),
00195         _bomRoot (ioBomRoot) {
00196     }
00197     
00198     // //////////////////////////////////////////////////////////////////////
00199     void doEndOnD::operator() (iterator_t iStr, iterator_t iStrEnd) const {
00200 
00201       // DEBUG: Display the result
00202       // STDAIR_LOG_DEBUG ("FareRule " << _onDPeriod.describe());
00203 
00204       // Generation of the O&D-Period object.
00205       OnDPeriodGenerator::createOnDPeriod (_bomRoot, _onDPeriod);
00206     }
00207       
00208     // ///////////////////////////////////////////////////////////////////////
00209     //
00210     //  Utility Parsers
00211     //
00212     // ///////////////////////////////////////////////////////////////////////
00213       
00215     uint2_p_t uint2_p;
00216     
00218     uint4_p_t uint4_p;
00219     
00221     uint1_4_p_t uint1_4_p;
00222 
00224     chset_t alpha_cap_set_p ("A-Z");
00225             
00227     repeat_p_t airport_p (chset_t("0-9A-Z").derived(), 3, 3);
00228       
00230     repeat_p_t airline_code_p (alpha_cap_set_p.derived(), 2, 3);
00231       
00233     bounded4_p_t year_p (uint4_p.derived(), 2000u, 2099u);
00234       
00236     bounded2_p_t month_p (uint2_p.derived(), 1u, 12u);
00237 
00239     bounded2_p_t day_p (uint2_p.derived(), 1u, 31u);
00240       
00242     bounded2_p_t hours_p (uint2_p.derived(), 0u, 23u);
00243 
00245     bounded2_p_t minutes_p (uint2_p.derived(), 0u, 59u);
00246 
00248     bounded2_p_t seconds_p (uint2_p.derived(), 0u, 59u);
00249 
00251     chset_t class_code_p ("A-Z");
00252 
00254     //
00255     //  (Boost Spirit) Grammar Definition
00256     //
00258 
00259     // //////////////////////////////////////////////////////////////////////
00260     OnDParser::
00261     OnDParser (stdair::BomRoot& ioBomRoot, OnDPeriodStruct& ioOnDPeriod) 
00262       : _bomRoot (ioBomRoot), _onDPeriod (ioOnDPeriod) {
00263     }
00264 
00265     // //////////////////////////////////////////////////////////////////////
00266     template<typename ScannerT>
00267     OnDParser::definition<ScannerT>::definition (OnDParser const& self) {
00268 
00269       ond_list = *( boost::spirit::classic::comment_p("//")
00270                     | boost::spirit::classic::comment_p("/*", "*/")
00271                     | ond )
00272         ;
00273 
00274       ond = ond_key
00275         >> +( ';' >> segment )
00276         >> ond_end[doEndOnD(self._bomRoot, self._onDPeriod)]
00277         ;
00278 
00279       ond_end = boost::spirit::classic::ch_p(';')
00280         ;
00281 
00282       ond_key = (airport_p)[storeOrigin(self._onDPeriod)]
00283         >> ';' >> (airport_p)[storeDestination(self._onDPeriod)]
00284         >> ';' >> date[storeDateRangeStart(self._onDPeriod)]
00285         >> ';' >> date[storeDateRangeEnd(self._onDPeriod)]
00286         >> ';' >> time[storeStartRangeTime(self._onDPeriod)]
00287         >> ';' >> time[storeEndRangeTime(self._onDPeriod)]
00288         ;
00289         
00290       date = boost::spirit::classic::
00291         lexeme_d[(year_p)[boost::spirit::classic::
00292                           assign_a(self._onDPeriod._itYear)]
00293                  >> '-'
00294                  >> (month_p)[boost::spirit::classic::
00295                               assign_a(self._onDPeriod._itMonth)]
00296                  >> '-'
00297                  >> (day_p)[boost::spirit::classic::
00298                             assign_a(self._onDPeriod._itDay)]]
00299         ;
00300            
00301       time = boost::spirit::classic::
00302         lexeme_d[(hours_p)[boost::spirit::classic::
00303                            assign_a(self._onDPeriod._itHours)]
00304                  >> ':'
00305                  >> (minutes_p)[boost::spirit::classic::
00306                                 assign_a(self._onDPeriod._itMinutes)]
00307                  >> !(':' >> (seconds_p)[boost::spirit::classic::
00308                                          assign_a(self._onDPeriod._itSeconds)])]
00309         ;
00310 
00311       segment = boost::spirit::classic::
00312         lexeme_d[(airline_code_p)[storeAirlineCode(self._onDPeriod)]]
00313         >> ';' >> (class_code_p)[storeClassCode(self._onDPeriod)]
00314         ;
00315 
00316       //BOOST_SPIRIT_DEBUG_NODE (OnDParser);
00317       BOOST_SPIRIT_DEBUG_NODE (ond_list);
00318       BOOST_SPIRIT_DEBUG_NODE (ond);
00319       BOOST_SPIRIT_DEBUG_NODE (segment);
00320       BOOST_SPIRIT_DEBUG_NODE (ond_key);
00321       BOOST_SPIRIT_DEBUG_NODE (ond_end);
00322       BOOST_SPIRIT_DEBUG_NODE (date);
00323       BOOST_SPIRIT_DEBUG_NODE (time);
00324 
00325     }
00326 
00327     // //////////////////////////////////////////////////////////////////////
00328     template<typename ScannerT>
00329     boost::spirit::classic::rule<ScannerT> const&
00330     OnDParser::definition<ScannerT>::start() const {
00331       return ond_list;
00332     }
00333   }
00334     
00336   //
00337   //  Entry class for the file parser
00338   //
00340 
00341   // //////////////////////////////////////////////////////////////////////
00342   OnDPeriodFileParser::OnDPeriodFileParser (const stdair::Filename_T& iFilename,
00343                                             stdair::BomRoot& ioBomRoot)
00344     : _filename (iFilename), _bomRoot (ioBomRoot) {
00345     init();
00346   }
00347     
00348   // //////////////////////////////////////////////////////////////////////
00349   void OnDPeriodFileParser::init() {
00350     // Check that the file exists and is readable
00351     const bool doesExistAndIsReadable =
00352       stdair::BasFileMgr::doesExistAndIsReadable (_filename);
00353 
00354     if (doesExistAndIsReadable == false) {
00355       STDAIR_LOG_ERROR ("The O&D file " << _filename
00356                         << " does not exist or can not be read.");
00357       
00358       throw OnDInputFileNotFoundException ("The O&D file " + _filename
00359                                            + " does not exist or can not be read");
00360     }
00361     
00362     // Open the file
00363     _startIterator = iterator_t (_filename);
00364 
00365     // Check that the filename exists and can be open
00366     if (!_startIterator) {
00367       STDAIR_LOG_DEBUG ("The O&D file " << _filename << " can not be open."
00368                         << std::endl);
00369       throw OnDInputFileNotFoundException ("The file " + _filename
00370                                            + " does not exist or can not be read");
00371     }
00372       
00373     // Create an EOF iterator
00374     _endIterator = _startIterator.make_end();
00375   }
00376     
00377   // //////////////////////////////////////////////////////////////////////
00378   bool OnDPeriodFileParser::generateOnDPeriods () {
00379     bool oResult = false;
00380       
00381     STDAIR_LOG_DEBUG ("Parsing O&D input file: " << _filename);
00382 
00383     // Initialise the parser (grammar) with the helper/staging structure.
00384     OnDParserHelper::OnDParser lODParser (_bomRoot, _onDPeriod);
00385       
00386     // Launch the parsing of the file and, thanks to the doEndOnD
00387     // call-back structure, filling the worldSchedule (Fares)
00388     boost::spirit::classic::parse_info<iterator_t> info =
00389       boost::spirit::classic::parse (_startIterator, _endIterator, lODParser, 
00390                                      boost::spirit::classic::space_p);
00391 
00392     // Retrieves whether or not the parsing was successful
00393     oResult = info.hit;
00394       
00395     const std::string hasBeenFullyReadStr = (info.full == true)?"":"not ";
00396     if (oResult == true) {
00397       STDAIR_LOG_DEBUG ("Parsing of O&D input file: " << _filename
00398                        << " succeeded: read " << info.length
00399                        << " characters. The input file has "
00400                        << hasBeenFullyReadStr
00401                        << "been fully read. Stop point: " << info.stop);
00402         
00403     } else {
00404       // TODO: decide whether to throw an exception
00405       STDAIR_LOG_ERROR ("Parsing of O&D input file: " << _filename
00406                        << " failed: read " << info.length
00407                        << " characters. The input file has "
00408                        << hasBeenFullyReadStr
00409                        << "been fully read. Stop point: " << info.stop);
00410     }
00411 
00412     return oResult;
00413   }
00414 }