AirSched Logo  0.1.4
C++ Simulated Airline Schedule Manager Library
SegmentPathGenerator.cpp
Go to the documentation of this file.
00001 // //////////////////////////////////////////////////////////////////////
00002 // Import section
00003 // //////////////////////////////////////////////////////////////////////
00004 // STL
00005 #include <cassert>
00006 #include <vector>
00007 // StdAir
00008 #include <stdair/basic/BasConst_Inventory.hpp>
00009 #include <stdair/bom/BomManager.hpp>
00010 #include <stdair/bom/BomRoot.hpp>
00011 #include <stdair/bom/Inventory.hpp>
00012 #include <stdair/bom/FlightPeriod.hpp>
00013 #include <stdair/bom/SegmentPeriod.hpp>
00014 #include <stdair/factory/FacBomManager.hpp>
00015 #include <stdair/service/Logger.hpp>
00016 // AirSched
00017 #include <airsched/bom/ReachableUniverse.hpp>
00018 #include <airsched/bom/OriginDestinationSet.hpp>
00019 #include <airsched/bom/SegmentPathPeriod.hpp>
00020 #include <airsched/command/SegmentPathGenerator.hpp>
00021 
00022 namespace AIRSCHED {
00023 
00024   // ////////////////////////////////////////////////////////////////////
00025   void SegmentPathGenerator::
00026   createSegmentPathNetwork (const stdair::BomRoot& iBomRoot) {
00027 
00028     // Build the list of single-segment segment path objects.
00029     const stdair::InventoryList_T& lInventoryList =
00030       stdair::BomManager::getList<stdair::Inventory> (iBomRoot);
00031     for (stdair::InventoryList_T::const_iterator itInv = lInventoryList.begin();
00032          itInv != lInventoryList.end(); ++itInv) {
00033       const stdair::Inventory* lCurrentInventory_ptr = *itInv;
00034       assert (lCurrentInventory_ptr != NULL);
00035 
00036       //
00037       createSinglePaths (*lCurrentInventory_ptr);
00038     }
00039 
00040     // Build the list of i-fixed-length segment path objects. In other words,
00041     // build the whole segment path network.
00042     for (stdair::NbOfSegments_T i = 2;
00043          i <= stdair::MAXIMAL_NUMBER_OF_SEGMENTS_IN_OND; ++i) {
00044       buildSegmentPathNetwork (iBomRoot, i);
00045     }
00046   }
00047   
00048   // ////////////////////////////////////////////////////////////////////
00049   void SegmentPathGenerator::
00050   createSinglePaths (const stdair::Inventory& iInventory) {
00051 
00052     const stdair::FlightPeriodList_T& lFlightPeriodList =
00053       stdair::BomManager::getList<stdair::FlightPeriod> (iInventory);
00054     for (stdair::FlightPeriodList_T::const_iterator itFlightPeriod =
00055            lFlightPeriodList.begin();
00056          itFlightPeriod != lFlightPeriodList.end(); ++itFlightPeriod) {
00057       const stdair::FlightPeriod* lCurrentFlightPeriod_ptr = *itFlightPeriod;
00058       assert (lCurrentFlightPeriod_ptr != NULL);
00059 
00060       //
00061       createSinglePaths (*lCurrentFlightPeriod_ptr);
00062     }
00063   }
00064 
00065   // ////////////////////////////////////////////////////////////////////
00066   void SegmentPathGenerator::
00067   createSinglePaths (const stdair::FlightPeriod& iFlightPeriod) {
00068 
00069     const stdair::SegmentPeriodList_T& lSegmentPeriodList =
00070       stdair::BomManager::getList<stdair::SegmentPeriod> (iFlightPeriod);
00071     for (stdair::SegmentPeriodList_T::const_iterator itSegmentPeriod =
00072            lSegmentPeriodList.begin();
00073          itSegmentPeriod != lSegmentPeriodList.end(); ++itSegmentPeriod) {
00074       stdair::SegmentPeriod* lCurrentSegmentPeriod_ptr = *itSegmentPeriod;
00075       assert (lCurrentSegmentPeriod_ptr != NULL);
00076 
00077       //
00078       createSinglePath (*lCurrentSegmentPeriod_ptr);
00079     }
00080   }
00081 
00082   // ////////////////////////////////////////////////////////////////////
00083   void SegmentPathGenerator::
00084   createSinglePath (stdair::SegmentPeriod& ioSegmentPeriod) {
00085 
00086     // Retrieve the BOM tree root
00087     const stdair::AirportCode_T& lOrigin = ioSegmentPeriod.getBoardingPoint();
00088     const stdair::FlightPeriod& lFlightPeriod =
00089       stdair::BomManager::getParent<stdair::FlightPeriod> (ioSegmentPeriod);
00090     const stdair::Inventory& lInventory =
00091       stdair::BomManager::getParent<stdair::Inventory> (lFlightPeriod);
00092     stdair::BomRoot& lBomRoot =
00093       stdair::BomManager::getParent<stdair::BomRoot> (lInventory);      
00094 
00095     // Retrieve the ReachableUniverse (if existing) which corresponds
00096     // to the origin. If it does not exist, then create one.
00097     ReachableUniverse* lReachableUniverse_ptr =
00098       stdair::BomManager::getObjectPtr<ReachableUniverse> (lBomRoot, lOrigin);
00099     if (lReachableUniverse_ptr == NULL) {
00100       ReachableUniverseKey lKey (lOrigin);
00101       lReachableUniverse_ptr =
00102         &stdair::FacBom<ReachableUniverse>::instance().create (lKey);
00103       stdair::FacBomManager::addToListAndMap (lBomRoot, *lReachableUniverse_ptr);
00104       stdair::FacBomManager::linkWithParent (lBomRoot, *lReachableUniverse_ptr);
00105     }
00106     assert (lReachableUniverse_ptr != NULL);
00107 
00108     //
00109     createSinglePath (*lReachableUniverse_ptr, ioSegmentPeriod);
00110   }
00111 
00112   // ////////////////////////////////////////////////////////////////////
00113   void SegmentPathGenerator::
00114   createSinglePath (ReachableUniverse& ioReachableUniverse,
00115                     stdair::SegmentPeriod& ioSegmentPeriod) {
00116 
00117     const stdair::AirportCode_T& lDestination = ioSegmentPeriod.getOffPoint();
00118 
00119     // Retrieve the origin-destination set (if existing) which corresponds
00120     // to the destination. If it does not exist, then create one.
00121     OriginDestinationSet* lOriginDestinationSet_ptr =
00122       stdair::BomManager::getObjectPtr<OriginDestinationSet>(ioReachableUniverse,
00123                                                              lDestination);
00124     if (lOriginDestinationSet_ptr == NULL) {
00125       OriginDestinationSetKey lKey (lDestination);
00126 
00127       lOriginDestinationSet_ptr =
00128         &stdair::FacBom<OriginDestinationSet>::instance().create (lKey);
00129       stdair::FacBomManager::addToListAndMap (ioReachableUniverse,
00130                                               *lOriginDestinationSet_ptr);
00131       stdair::FacBomManager::linkWithParent (ioReachableUniverse,
00132                                              *lOriginDestinationSet_ptr);
00133     }
00134     assert (lOriginDestinationSet_ptr != NULL);
00135     
00136     // Create a segment path period and add it to the corresponding
00137     // origin-destination set and reachable-universe.
00138     const stdair::FlightPeriod& lFlightPeriod =
00139       stdair::BomManager::getParent<stdair::FlightPeriod> (ioSegmentPeriod);
00140     const stdair::PeriodStruct& lPeriodOfFlight = lFlightPeriod.getPeriod();
00141 
00142     // The departure period of the segment is the departure period of
00143     // the flight plus the boarding date offset of the segment.
00144     const stdair::DateOffset_T& lBoardingDateOffset = 
00145       ioSegmentPeriod.getBoardingDateOffset();
00146 
00147     const stdair::PeriodStruct lPeriodOfSegment =
00148       lPeriodOfFlight.addDateOffset (lBoardingDateOffset);
00149 
00150     const stdair::Duration_T& lBoardingTime = ioSegmentPeriod.getBoardingTime();
00151     const stdair::Duration_T& lElapsed = ioSegmentPeriod.getElapsedTime();
00152 
00153     DateOffsetList_T lDateOffsetList;
00154     const stdair::DateOffset_T lFirstDateOffset (0);
00155     lDateOffsetList.push_back (lFirstDateOffset);
00156 
00157     const SegmentPathPeriodKey lSegmentPathKey (lPeriodOfSegment,
00158                                                 lBoardingTime, lElapsed,
00159                                                 lDateOffsetList, 1);
00160 
00161     SegmentPathPeriod& lSegmentPathPeriod =
00162       stdair::FacBom<SegmentPathPeriod>::instance().create (lSegmentPathKey);
00163 
00170     addSegmentPathPeriod (ioReachableUniverse, lSegmentPathPeriod);
00171     
00172     // Link the SegmentPathPeriod object with its parent, namely
00173     // OriginDestinationSet
00174     stdair::FacBomManager::addToList (*lOriginDestinationSet_ptr,
00175                                       lSegmentPathPeriod);
00176     stdair::FacBomManager::linkWithParent (*lOriginDestinationSet_ptr,
00177                                            lSegmentPathPeriod);
00178 
00179     // Link the SegmentPathPeriod and SegmentPeriod objects. Note that
00180     // the SegmentPeriod object has already a parent, namely FlightPeriod.
00181     stdair::FacBomManager::addToList (lSegmentPathPeriod,
00182                                       ioSegmentPeriod);
00183   }
00184 
00185   // ////////////////////////////////////////////////////////////////////
00186   void SegmentPathGenerator::
00187   addSegmentPathPeriod (ReachableUniverse& ioReachableUniverse,
00188                         const SegmentPathPeriod& iSegmentPathPeriod) {
00189 
00190     const stdair::NbOfSegments_T& lNbOfSegments =
00191       iSegmentPathPeriod.getNbOfSegments();
00192 
00193     assert (lNbOfSegments > 0
00194             && lNbOfSegments <= stdair::MAXIMAL_NUMBER_OF_SEGMENTS_IN_OND);
00195 
00196     // If needed, initialise the list of lists with empty fixed-length
00197     // segment path period lists.
00198     
00199     SegmentPathPeriodListList_T& lSegmentPathPeriodListList =
00200       ioReachableUniverse._segmentPathPeriodListList;
00201     while (lSegmentPathPeriodListList.size() < lNbOfSegments) {
00202       SegmentPathPeriodLightList_T lSegmentPathPeriodList;
00203       lSegmentPathPeriodListList.push_back (lSegmentPathPeriodList);
00204     }
00205 
00206     // Retrieve the i-fixed-length segment path period list (i = number of
00207     // segments).
00208     SegmentPathPeriodLightList_T& lSegmentPathPeriodList =
00209       lSegmentPathPeriodListList.at (lNbOfSegments-1);
00210 
00211     // Add the SegmentPathPeriod to that fixed-length-path list.
00212     lSegmentPathPeriodList.push_back (&iSegmentPathPeriod);
00213   }
00214   
00215   // ////////////////////////////////////////////////////////////////////
00216   void SegmentPathGenerator::
00217   buildSegmentPathNetwork (const stdair::BomRoot& iBomRoot,
00218                            const stdair::NbOfSegments_T& lNbOfSegments) {
00219 
00225     const ReachableUniverseList_T& lReachableUniverseList =
00226       stdair::BomManager::getList<ReachableUniverse> (iBomRoot);
00227     for (ReachableUniverseList_T::const_iterator itReachableUniverse =
00228            lReachableUniverseList.begin();
00229          itReachableUniverse != lReachableUniverseList.end();
00230          ++itReachableUniverse) {
00231       ReachableUniverse* lReachableUniverse_ptr = *itReachableUniverse;
00232       assert (lReachableUniverse_ptr != NULL);
00233 
00234       //
00235       buildSegmentPathNetwork (*lReachableUniverse_ptr, lNbOfSegments);
00236     }
00237   }
00238 
00239   // ////////////////////////////////////////////////////////////////////
00240   void SegmentPathGenerator::
00241   buildSegmentPathNetwork (ReachableUniverse& ioReachableUniverse,
00242                            const stdair::NbOfSegments_T& iNbOfSegments) {
00243     
00244     // The goal of that method is to build the i-fixed-length
00245     // segment path period objects, knowing that all the
00246     // lower-fixed-length segment path period objects have already been
00247     // built during the previous steps. Once an i-fixed-length
00248     // segment path period object is created, it is added to the list of
00249     // the (fixed-length segment path period object) lists.
00250     
00251     // Hence, at that iteration, by construction, the list of the
00252     // (fixed-length segment path period object) lists should already get
00253     // a size of i-1, if there were such possibilities (in terms of
00254     // segment path period). In that case, at the end of the method, its
00255     // size should be of i.
00256     
00257     // If the size of the list of the (fixed-length segment path period
00258     // object) lists is (strictly) less than i-1, it means that that
00259     // reachable universe has no more possibilities of destinations. We
00260     // are thus done at that stage.
00261     const SegmentPathPeriodListList_T& lSegmentPathPeriodListList =
00262       ioReachableUniverse.getSegmentPathPeriodListList();
00263     const unsigned short lNbOfSegments_m1 = iNbOfSegments - 1;
00264     assert (lNbOfSegments_m1 >= 0);
00265     if (lSegmentPathPeriodListList.size() < lNbOfSegments_m1) {
00266       return;
00267     }
00268       
00269     // Retrieve the (i-1)-fixed-length segment path period list (i = number of
00270     // segments).
00271     
00272     // Note that a STL vector starts at 0, whereas the number of segments
00273     // starts at 1. Hence, (i-1) for the length (in number of segments)
00274     // corresponds to [iNbOfSegments-2] for the STL vector.
00275     
00276     // As the lSegmentPathPeriodListList may change during the next loop
00277     // iterations (as some SegmentPathPeriod objects are created and linked to
00278     // ReachableUniverse), we need to take the initial copy of that list.
00279     const SegmentPathPeriodLightList_T lSegmentPathPeriodLightList_im1 =
00280       lSegmentPathPeriodListList.at (iNbOfSegments-2);
00281 
00282     // Iterate on the (i-1)-fixed-length segment path period objects, in order
00283     // to build a i-fixed-length segment path period objects. 
00284     // There are two steps:
00285     // 1. Retrieve the airport-dates at a (i-1) length (in number of segments)
00286     //    of the origin airport-date.
00287     // 2. From each of such (i-1) airport-date, add the single-segment pathes
00288     //    to the (i-1)-length pathes, so as to make i-length pathes.
00289     for (SegmentPathPeriodLightList_T::const_iterator itSegmentPathPeriodList =
00290            lSegmentPathPeriodLightList_im1.begin();
00291          itSegmentPathPeriodList != lSegmentPathPeriodLightList_im1.end();
00292          ++itSegmentPathPeriodList) {
00293       const SegmentPathPeriod* lSegmentPathPeriod_im1_ptr = 
00294         *itSegmentPathPeriodList;
00295       assert (lSegmentPathPeriod_im1_ptr != NULL);
00296 
00297       // Get the reachable-universe departing from the destination of
00298       // the current segment path period.
00299       const stdair::AirportCode_T& lDestination_im1 =
00300         lSegmentPathPeriod_im1_ptr->getDestination();
00301       const stdair::BomRoot& lBomRoot =
00302         stdair::BomManager::getParent<stdair::BomRoot> (ioReachableUniverse);
00303       const ReachableUniverse* lReachableUniverseFromDestination_im1_ptr =
00304         stdair::BomManager::getObjectPtr<ReachableUniverse> (lBomRoot,
00305                                                             lDestination_im1);
00306 
00307       // If there is no ReachableUniverse corresponding to the destination (off
00308       // point of the last SegmentDate), it means that the destination is
00309       // an end point (no other SegmentDate is starting from there).
00310       // Hence, there is nothing else to do for now for that (final)
00311       // destination, and we can process the next (i-1)-segment path period.
00312       if (lReachableUniverseFromDestination_im1_ptr == NULL) {
00313         continue;
00314       }
00315       assert (lReachableUniverseFromDestination_im1_ptr != NULL);
00316         
00317       // Retrieve the single-segment segment path period list,
00318       // so as to make a i-length SegmentPathPeriod.
00319       const SegmentPathPeriodListList_T& 
00320         lSegmentPathPeriodListListFromDestination_im1 = 
00321         lReachableUniverseFromDestination_im1_ptr->
00322         getSegmentPathPeriodListList();
00323       assert (lSegmentPathPeriodListListFromDestination_im1.size() >= 1);
00324 
00325       // As the lSegmentPathPeriodListListFromDestination_im1 may change during
00326       // the next loop iterations (as some SegmentPathPeriod objects are
00327       // created and linked to ReachableUniverse), we need to take the initial
00328       // copy of that list.
00329       const SegmentPathPeriodLightList_T lSingleSegmentPathPeriodLightListFromDestination_im1 =
00330         lSegmentPathPeriodListListFromDestination_im1.at (0);
00331 
00332       for (SegmentPathPeriodLightList_T::const_iterator
00333              itSegmentPathPeriodFromDestination_im1 =
00334              lSingleSegmentPathPeriodLightListFromDestination_im1.begin();
00335            itSegmentPathPeriodFromDestination_im1
00336              != lSingleSegmentPathPeriodLightListFromDestination_im1.end();
00337            ++itSegmentPathPeriodFromDestination_im1) {
00338         const SegmentPathPeriod* lSingleSegmentPathPeriodFromDestination_im1_ptr=
00339           *itSegmentPathPeriodFromDestination_im1;
00340         assert (lSingleSegmentPathPeriodFromDestination_im1_ptr != NULL);
00341 
00342         // Check if the (i-1)-length segment path period can be fused with the
00343         // single segment segment path period in order to create an i-length
00344         // segment path period. The function will return a valid or non-valid
00345         // segment path period key.
00346 
00347         // The two segment path period above can be fused (and will produce a
00348         // valid new segment path period key) if:
00349         // 1. A passenger can connect from the last segment of the
00350         // first segment path and the first segment of the next segment path.
00351         // These two segments should not create another segment.
00352         // 2. There is no circle within the new segment path.
00353         // 3. The intersection of the two periods is non-empty.
00354         SegmentPathPeriodKey lSegmentPathPeriodKey_i =
00355           lSegmentPathPeriod_im1_ptr->connectWithAnotherSegment (*lSingleSegmentPathPeriodFromDestination_im1_ptr);
00356 
00357         if (lSegmentPathPeriodKey_i.isValid () == false) {
00358           continue;
00359         }
00360           
00361         // Get the off point of the single-segment SegmentPathPeriod
00362         // attached to the intermediate destination (im1). That off point is
00363         // at a length i of the initial ReachableUniverse: (i-1) + 1.
00364         const stdair::AirportCode_T& lDestination_i =
00365           lSingleSegmentPathPeriodFromDestination_im1_ptr->getDestination();
00366 
00367         // Build the i-length SegmentPathPeriod
00368         // Get the parameters of the last segment
00369         stdair::SegmentPeriod* lSegmentPeriod_1_ptr =
00370           lSingleSegmentPathPeriodFromDestination_im1_ptr->getFirstSegmentPeriod();
00371         assert (lSegmentPeriod_1_ptr != NULL);
00372           
00373         // Calculate the number of airlines flown by the i-length
00374         // segment path period
00375         const stdair::FlightPeriod& lFlightPeriod = stdair::BomManager::
00376           getParent<stdair::FlightPeriod> (*lSegmentPeriod_1_ptr);
00377         const stdair::Inventory& lInventory =
00378           stdair::BomManager::getParent<stdair::Inventory> (lFlightPeriod);
00379         const stdair::AirlineCode_T& lAirlineCode_1 =lInventory.getAirlineCode();
00380         stdair::NbOfAirlines_T lNbOfAirlines_i =
00381           lSegmentPathPeriod_im1_ptr->getNbOfAirlines();
00382         if (lSegmentPathPeriod_im1_ptr->isAirlineFlown(lAirlineCode_1) == false){
00383           ++lNbOfAirlines_i;
00384         }
00385         lSegmentPathPeriodKey_i.setNbOfAirlines (lNbOfAirlines_i);
00386 
00387         // Create the new segment path and add it to the dedicated lists.
00388         OriginDestinationSet* lOriginDestinationSet_ptr = stdair::BomManager::
00389           getObjectPtr<OriginDestinationSet>(ioReachableUniverse,lDestination_i);
00390         if (lOriginDestinationSet_ptr == NULL) {
00391           OriginDestinationSetKey lKey (lDestination_i);
00392           lOriginDestinationSet_ptr = 
00393             &stdair::FacBom<OriginDestinationSet>::instance().create (lKey);
00394           stdair::FacBomManager::addToListAndMap (ioReachableUniverse,
00395                                                   *lOriginDestinationSet_ptr);
00396           stdair::FacBomManager::linkWithParent (ioReachableUniverse,
00397                                                  *lOriginDestinationSet_ptr);
00398         }
00399         assert (lOriginDestinationSet_ptr != NULL);
00400         
00401         
00402         SegmentPathPeriod& lSegmentPathPeriod_i = stdair::
00403           FacBom<SegmentPathPeriod>::instance().create (lSegmentPathPeriodKey_i);
00404         stdair::FacBomManager::addToList (*lOriginDestinationSet_ptr,
00405                                                      lSegmentPathPeriod_i);
00406         stdair::FacBomManager::linkWithParent (*lOriginDestinationSet_ptr,
00407                                                lSegmentPathPeriod_i);
00408 
00409         // Clone the list of SegmentPeriod references of the given
00410         // SegmentPathPeriod object (passed as the second parameter).
00411         stdair::FacBomManager::
00412           cloneHolder<stdair::SegmentPeriod> (lSegmentPathPeriod_i,
00413                                               *lSegmentPathPeriod_im1_ptr);
00414        
00415         
00416         // Add the SegmentPeriod reference to the dedicated list within
00417         // the SegmentPathPeriod. Note that this must be done before
00418         // the link between the SegmentPathPeriod and
00419         // ReachableUniverse, as that latter method uses the number of
00420         // segments within the SegmentPathPeriod object.
00421         stdair::FacBomManager::addToList (lSegmentPathPeriod_i,
00422                                           *lSegmentPeriod_1_ptr);
00423         
00431         addSegmentPathPeriod (ioReachableUniverse, lSegmentPathPeriod_i);
00432       }
00433      }
00434   }
00435 }