AirSched Logo  0.1.4
C++ Simulated Airline Schedule Manager Library
SegmentPathPeriod.cpp
Go to the documentation of this file.
00001 // //////////////////////////////////////////////////////////////////////
00002 // Import section
00003 // //////////////////////////////////////////////////////////////////////
00004 // STL
00005 #include <cassert>
00006 #include <sstream>
00007 // Boost.Serialization
00008 #include <boost/archive/text_iarchive.hpp>
00009 #include <boost/archive/text_oarchive.hpp>
00010 #include <boost/serialization/access.hpp>
00011 // StdAir
00012 #include <stdair/basic/BasConst_General.hpp>
00013 #include <stdair/basic/BasConst_Inventory.hpp>
00014 #include <stdair/basic/BasConst_Period_BOM.hpp>
00015 #include <stdair/basic/BasConst_TravelSolution.hpp>
00016 #include <stdair/bom/Inventory.hpp>
00017 #include <stdair/bom/FlightPeriod.hpp>
00018 #include <stdair/bom/SegmentPeriod.hpp>
00019 #include <stdair/bom/BomManager.hpp>
00020 // AirSched
00021 #include <airsched/bom/SegmentPathPeriod.hpp>
00022 
00023 namespace AIRSCHED {
00024 
00025   // ////////////////////////////////////////////////////////////////////
00026   SegmentPathPeriod::SegmentPathPeriod()
00027     :  _key (stdair::PeriodStruct (stdair::BOOST_DEFAULT_DATE_PERIOD,
00028                                    stdair::DEFAULT_DOW_STRING),
00029              stdair::NULL_BOOST_TIME_DURATION, stdair::NULL_BOOST_TIME_DURATION,
00030              DateOffsetList_T(),
00031              stdair::DEFAULT_NBOFAIRLINES),
00032        _parent (NULL) {
00033     assert (false);
00034   }
00035 
00036   // ////////////////////////////////////////////////////////////////////
00037   SegmentPathPeriod::SegmentPathPeriod (const SegmentPathPeriod& iSPP)
00038     :  _key (iSPP._key), _parent (NULL) {
00039     assert (false);
00040   }
00041   
00042   // ////////////////////////////////////////////////////////////////////
00043   SegmentPathPeriod::SegmentPathPeriod (const Key_T& iKey)
00044     :  _key (iKey), _parent (NULL) {
00045   }
00046   
00047   // ////////////////////////////////////////////////////////////////////
00048   SegmentPathPeriod::~SegmentPathPeriod() {
00049   }
00050 
00051   // ////////////////////////////////////////////////////////////////////
00052   std::string SegmentPathPeriod::toString() const {
00053     std::ostringstream oStr;
00054     oStr << _key.toString();
00055     return oStr.str();
00056   }
00057 
00058   // ////////////////////////////////////////////////////////////////////
00059   void SegmentPathPeriod::serialisationImplementationExport() const {
00060     std::ostringstream oStr;
00061     boost::archive::text_oarchive oa (oStr);
00062     oa << *this;
00063   }
00064 
00065   // ////////////////////////////////////////////////////////////////////
00066   void SegmentPathPeriod::serialisationImplementationImport() {
00067     std::istringstream iStr;
00068     boost::archive::text_iarchive ia (iStr);
00069     ia >> *this;
00070   }
00071 
00072   // ////////////////////////////////////////////////////////////////////
00073   template<class Archive>
00074   void SegmentPathPeriod::serialize (Archive& ioArchive,
00075                                      const unsigned int iFileVersion) {
00076     ioArchive & _key;
00077   }
00078 
00079   // ////////////////////////////////////////////////////////////////////
00080   // Explicit template instantiation
00081   namespace ba = boost::archive;
00082   template
00083   void SegmentPathPeriod::serialize<ba::text_oarchive> (ba::text_oarchive&,
00084                                                         unsigned int);
00085   template
00086   void SegmentPathPeriod::serialize<ba::text_iarchive> (ba::text_iarchive&,
00087                                                         unsigned int);
00088   // ////////////////////////////////////////////////////////////////////
00089 
00090   // ////////////////////////////////////////////////////////////////////
00091   stdair::SegmentPeriod* SegmentPathPeriod::getLastSegmentPeriod () const {
00092     // Retrieve the last segment of the list
00093     const stdair::SegmentPeriodList_T& lSegmentPeriodList =
00094       stdair::BomManager::getList<stdair::SegmentPeriod> (*this);
00095     stdair::SegmentPeriodList_T::const_reverse_iterator itLastSegment =
00096       lSegmentPeriodList.rbegin();
00097 
00098     if (itLastSegment == lSegmentPeriodList.rend()) {
00099       return NULL;
00100     }
00101     
00102     stdair::SegmentPeriod* oSegment_ptr = *itLastSegment;
00103     assert (oSegment_ptr != NULL);
00104 
00105     return oSegment_ptr;
00106   }
00107 
00108   // ////////////////////////////////////////////////////////////////////
00109   stdair::SegmentPeriod* SegmentPathPeriod::getFirstSegmentPeriod () const{
00110     // Retrieve the first segment of the list
00111     const stdair::SegmentPeriodList_T& lSegmentPeriodList =
00112       stdair::BomManager::getList<stdair::SegmentPeriod> (*this);
00113     stdair::SegmentPeriodList_T::const_iterator itFirstSegment = 
00114       lSegmentPeriodList.begin();
00115 
00116     if (itFirstSegment == lSegmentPeriodList.end()) {
00117       return NULL;
00118     }
00119     
00120     stdair::SegmentPeriod* oSegment_ptr = *itFirstSegment;
00121     assert (oSegment_ptr != NULL);
00122 
00123     return oSegment_ptr;
00124   }
00125 
00126   // ////////////////////////////////////////////////////////////////////
00127   const stdair::AirportCode_T& SegmentPathPeriod::getDestination () const {
00128     const stdair::SegmentPeriod* lLastSegment_ptr = getLastSegmentPeriod();
00129     assert (lLastSegment_ptr != NULL);
00130     return lLastSegment_ptr->getOffPoint();
00131   }  
00132 
00133   // ////////////////////////////////////////////////////////////////////
00134   bool SegmentPathPeriod::
00135   isAirlineFlown (const stdair::AirlineCode_T& iAirlineCode) const {
00136     bool oAirlineFlown = false;
00137 
00138     const stdair::SegmentPeriodList_T& lSegmentPeriodList = 
00139       stdair::BomManager::getList<stdair::SegmentPeriod> (*this);
00140     for (stdair::SegmentPeriodList_T::const_iterator itSegmentPeriod =
00141            lSegmentPeriodList.begin();
00142          itSegmentPeriod != lSegmentPeriodList.end(); ++itSegmentPeriod) {
00143       const stdair::SegmentPeriod* lSegmentPeriod_ptr = *itSegmentPeriod;
00144       assert (lSegmentPeriod_ptr != NULL);
00145 
00146       const stdair::FlightPeriod& lFlightPeriod =
00147         stdair::BomManager::getParent<stdair::FlightPeriod>(*lSegmentPeriod_ptr);
00148       const stdair::Inventory& lInventory =
00149         stdair::BomManager::getParent<stdair::Inventory> (lFlightPeriod);
00150       const stdair::AirlineCode_T& lSegmentAirlineCode =
00151         lInventory.getAirlineCode ();
00152       if (lSegmentAirlineCode == iAirlineCode) {
00153         oAirlineFlown = true;
00154         break;
00155       }
00156     }
00157 
00158     return oAirlineFlown;
00159   }
00160 
00161   // ////////////////////////////////////////////////////////////////////
00162   SegmentPathPeriodKey SegmentPathPeriod::
00163   connectWithAnotherSegment(const SegmentPathPeriod& iSingleSegmentPath) const {
00164     SegmentPathPeriodKey oSegmentPathPeriodKey;
00165 
00166     // Retrieve the (only) segment period of the single segment path.
00167     const stdair::SegmentPeriod* lNextSegmentPeriod_ptr =
00168       iSingleSegmentPath.getFirstSegmentPeriod();
00169     assert (lNextSegmentPeriod_ptr != NULL);
00170 
00171     // Retrive the last segment period of the current segment path and check
00172     // if the combination of the last segment and the next segment that we
00173     // want to add to the current segment path will create a new segment
00174     // (i.e., the two segment period belongs to the same flight number).
00175     const stdair::SegmentPeriod* lLastSegmentPeriod_ptr = getLastSegmentPeriod ();
00176     assert (lLastSegmentPeriod_ptr != NULL);
00177     const stdair::FlightPeriod& lLastFlightPeriod = stdair::BomManager::
00178       getParent<stdair::FlightPeriod> (*lLastSegmentPeriod_ptr);
00179     const stdair::Inventory& lLastInventory =
00180       stdair::BomManager::getParent<stdair::Inventory> (lLastFlightPeriod);
00181     
00182     const stdair::FlightPeriod& lNextFlightPeriod = stdair::BomManager::
00183       getParent<stdair::FlightPeriod> (*lNextSegmentPeriod_ptr);
00184     const stdair::Inventory& lNextInventory =
00185       stdair::BomManager::getParent<stdair::Inventory> (lNextFlightPeriod);
00186     
00187     if (lLastFlightPeriod.getFlightNumber()==lNextFlightPeriod.getFlightNumber()
00188         && lLastInventory.getAirlineCode() == lNextInventory.getAirlineCode()) {
00189       return oSegmentPathPeriodKey;
00190     }
00191     
00192     // Check if the new segment period will create a circle.
00193     const stdair::AirportCode_T& lDestination =
00194       lNextSegmentPeriod_ptr->getOffPoint();
00195     if (checkCircle (lDestination) == true) {
00196       return oSegmentPathPeriodKey;
00197     }
00198 
00199     // Check if a passenger can connect from the last segment of the
00200     // current segment path to the first segment of the to-be-added
00201     // segment path. If yes, build a new departure period for the new
00202     // segment path.
00203     DateOffsetList_T lBoardingDateOffsetList = 
00204       getBoardingDateOffsetList();
00205     const stdair::PeriodStruct& lCurrentDeparturePeriod = getDeparturePeriod();
00206     const stdair::PeriodStruct& lNextDeparturePeriod =
00207       iSingleSegmentPath.getDeparturePeriod();
00208     const stdair::Duration_T& lLastOffTime =
00209       lLastSegmentPeriod_ptr->getOffTime();
00210     const stdair::Duration_T& lNextBoardingTime =
00211       lNextSegmentPeriod_ptr->getBoardingTime();
00212     // If the next boarding time is later than the last off time, check if
00213     // the passengers will have enough time for the transfer. If the next
00214     // boarding time is earlier than the last off time, check if the passengers
00215     // can connect to a flight in the next day.
00216     if (lNextBoardingTime >= lLastOffTime) {
00217       const stdair::Duration_T lStopTime = lNextBoardingTime - lLastOffTime;
00218       if (lStopTime < stdair::DEFAULT_MINIMAL_CONNECTION_TIME) {
00219         return oSegmentPathPeriodKey;
00220       } else {
00221         // Calulcate the date offset of the next segment compare to
00222         // the first one. In this case, this value is equal to the offset
00223         // of the off date of the last segment compare to the boarding date
00224         // of the first segment.
00225         const stdair::DateOffset_T& lLastBoardingDateOffset =
00226           lBoardingDateOffsetList.at (getNbOfSegments() - 1);
00227         const stdair::DateOffset_T lNextBoardingDateOffset =
00228           lLastBoardingDateOffset + lLastSegmentPeriod_ptr->getOffDateOffset()
00229           - lLastSegmentPeriod_ptr->getBoardingDateOffset();
00230         const stdair::DateOffset_T lNegativeNextBoardingDateOffset =
00231           stdair::DateOffset_T (0) - lNextBoardingDateOffset;
00232 
00233         // Compute the adjusted departure period of the next segment by
00234         // substracting the origin one with the boarding date offset.
00235         const stdair::PeriodStruct lAdjustedNextDeparturePeriod =
00236           lNextDeparturePeriod.addDateOffset (lNegativeNextBoardingDateOffset);
00237 
00238         // Build the intersection of the two periods.
00239         const stdair::PeriodStruct lNewDeparturePeriod =
00240           lCurrentDeparturePeriod.intersection (lAdjustedNextDeparturePeriod);
00241         stdair::Duration_T lNewElapsed = getElapsedTime() + lStopTime +
00242           lNextSegmentPeriod_ptr->getElapsedTime();
00243         lBoardingDateOffsetList.push_back (lNextBoardingDateOffset);
00244         oSegmentPathPeriodKey.setPeriod (lNewDeparturePeriod);
00245         oSegmentPathPeriodKey.setElapsedTime (lNewElapsed);
00246       }
00247     } else {
00248       const stdair::Duration_T lStopTime = 
00249         lNextBoardingTime - lLastOffTime + stdair::Duration_T (24, 0, 0);
00250       if (lStopTime < stdair::DEFAULT_MINIMAL_CONNECTION_TIME) {
00251         return oSegmentPathPeriodKey;
00252       } else {
00253         // Calulcate the date offset of the next segment compare to
00254         // the first one.
00255         const stdair::DateOffset_T& lLastBoardingDateOffset =
00256           lBoardingDateOffsetList.at (getNbOfSegments() - 1);
00257         const stdair::DateOffset_T lNextBoardingDateOffset =
00258           lLastBoardingDateOffset + lLastSegmentPeriod_ptr->getOffDateOffset()
00259           - lLastSegmentPeriod_ptr->getBoardingDateOffset() +
00260           stdair::DateOffset_T (1);
00261         const stdair::DateOffset_T lNegativeNextBoardingDateOffset =
00262           stdair::DateOffset_T (0) - lNextBoardingDateOffset;
00263 
00264         // Compute the adjusted departure period of the next segment by
00265         // substracting the origin one with the boarding date offset.
00266         const stdair::PeriodStruct lAdjustedNextDeparturePeriod =
00267           lNextDeparturePeriod.addDateOffset (lNegativeNextBoardingDateOffset);
00268 
00269         // Build the intersection of the two periods.
00270         const stdair::PeriodStruct lNewDeparturePeriod =
00271           lCurrentDeparturePeriod.intersection (lAdjustedNextDeparturePeriod);
00272         stdair::Duration_T lNewElapsed = getElapsedTime() + lStopTime +
00273           lNextSegmentPeriod_ptr->getElapsedTime();
00274         lBoardingDateOffsetList.push_back (lNextBoardingDateOffset);
00275         oSegmentPathPeriodKey.setPeriod (lNewDeparturePeriod);
00276         oSegmentPathPeriodKey.setElapsedTime (lNewElapsed);
00277       }
00278     }
00279     
00280     const stdair::Duration_T& lBoardingTime = getBoardingTime();
00281     oSegmentPathPeriodKey.setBoardingTime (lBoardingTime);
00282     oSegmentPathPeriodKey.setBoardingDateOffsetList (lBoardingDateOffsetList);
00283     
00284     return oSegmentPathPeriodKey;
00285   }
00286 
00287   // ////////////////////////////////////////////////////////////////////
00288   bool SegmentPathPeriod::
00289   checkCircle (const stdair::AirlineCode_T& iDestination) const {
00290     const stdair::SegmentPeriodList_T& lSegmentPeriodList =
00291       stdair::BomManager::getList<stdair::SegmentPeriod> (*this);
00292     for (stdair::SegmentPeriodList_T::const_iterator itSegment =
00293            lSegmentPeriodList.begin();
00294          itSegment != lSegmentPeriodList.end(); ++itSegment) {
00295       const stdair::SegmentPeriod* lCurrentSegment_ptr = *itSegment;
00296       assert (lCurrentSegment_ptr != NULL);
00297       const stdair::AirlineCode_T& lCurrentBoardingPoint =
00298         lCurrentSegment_ptr->getBoardingPoint();
00299       if (lCurrentBoardingPoint == iDestination) {
00300         return true;
00301       }
00302     }
00303     return false;
00304   }
00305 
00306   // ////////////////////////////////////////////////////////////////////
00307   bool SegmentPathPeriod::
00308   isDepartureDateValid (const stdair::Date_T& iDepartureDate) const {
00309     const stdair::PeriodStruct& lPeriod = getDeparturePeriod ();
00310 
00311     // Check if the departure date is within the date range.
00312     const stdair::DatePeriod_T& lDeparturePeriod = lPeriod.getDateRange ();
00313     if (lDeparturePeriod.contains (iDepartureDate) == false) {
00314       return false;
00315     }
00316 
00317     // Check if the departure date is valid within the DOW.
00318     // 0 = Sunday, 1 = Monday, etc.
00319     const short lDay = iDepartureDate.day_of_week ();
00320     const stdair::DoWStruct& lDoW = lPeriod.getDoW ();
00321     if (lDoW.getStandardDayOfWeek (lDay) == false) {
00322       return false;
00323     }
00324 
00325     return true;
00326   }
00327 
00328 }