| Quintiq file version 2.0 | 
| #parent: #root | 
| Method GenerateOccurrences ( | 
|   Date dateOfFirstRecurrence_i, | 
|   Date endDate_i, | 
|   Date startOverlap_i, | 
|   Date endOverlap_i, | 
|   Boolean preserveOccurrences_i | 
| ) | 
| { | 
|   Description: 'Generate TimeIntervals for the occurrences of an Event, given the RecurrencePattern of the Event and the RecurrencePeriod of the Participation.' | 
|   TextBody: | 
|   [* | 
|     calendar := this.Calendar(); | 
|     pattern  := this.RecurrencePattern(); | 
|     timezone := this.Calendar().GetTimeZone(); | 
|      | 
|     // For debugging | 
|     //showInfo := this.Event().Subject() = "TEST"; | 
|     //showInfo := true; | 
|     //mask     := "dd D-M-Y H:m"; | 
|     //convOps  := ConversionOptions::ISO(); | 
|      | 
|     // Get the date of the first occurrence to be generated. | 
|     dateOfRecurrence := dateOfFirstRecurrence_i; | 
|     date             := pattern.GetDateOfNextOccurrence( dateOfRecurrence, dateOfRecurrence ); | 
|      | 
|     // Remember the first existing occurrence for a check later on. | 
|     firstOccurrence := minselect( this, ExplicitTimeInterval, eti, true, eti.Start() ); | 
|      | 
|     //if( showInfo ){ info( ">>> Generate from", date, "to", endDate_i, "| preserve =", preserveOccurrences_i ) }; | 
|     //if( showInfo ){ info( ">>> startOverlap =", startOverlap_i.Format( mask ), "endOverlap =", endOverlap_i.Format( mask ) ) }; | 
|     //if( showInfo ){ info( ">>> startOfWindowMovedForward =", calendar.StartDate() > calendar.PreviousStartDate() ); } | 
|     //if( showInfo ){ info( ">>> startOfWindowMovedBackward =", calendar.StartDate() < calendar.PreviousStartDate() ); } | 
|      | 
|     // Generate the TimeIntervals. | 
|     while( date <= endDate_i ) | 
|     { | 
|       // Calculate start and end, taking timezone and DSL into account. | 
|       start := LibCal_Util::CalculateStartTime( timezone, date, this.Event().StartTimeOfDay() ); | 
|       end   := LibCal_Util::CalculateEndTime(   timezone, date, this.Event().StartTimeOfDay(), this.Event().Duration() ); | 
|        | 
|       //if( showInfo ){ info( ">>>", start.Format( mask, convOps ), "-", end.Format( mask, convOps ), "preserve =", preserveOccurrences_i ); } | 
|      | 
|       // If end is at midnight, one day should be subtracted in order to not take the next day into account. | 
|       startDate := start.Date( timezone ); | 
|       endDate   := end.Date( timezone ) - ifexpr( end = end.StartOfDay( timezone ), 1, 0 ); | 
|        | 
|       // Ignore TimeIntervals outside of the CalendarWindow. | 
|       isInCalendarWindow := end   > calendar.Start() and | 
|                             start < calendar.End();   | 
|       if( isInCalendarWindow ) | 
|       { | 
|         // See if the TimeInterval already exists. | 
|         // NOTE: if the times of an occurrence were changed it is not found here anymore, | 
|         //       as a result of which it will be removed...! | 
|         // ToDo: see how this can be solved. | 
|         timeInterval := select( this, ExplicitTimeInterval, eti, true, | 
|                                 eti.Start() = start and | 
|                                 eti.End()   = end ); | 
|      | 
|         // When occurrences must be preserved, TimeIntervals that were already part of the existing window should be ignored; | 
|         // they must be used 'as-is' and not be re-generated. This concerns the TimeIntervals that are part of the overlap between the old and the new window. | 
|         // Note that a TimeInterval is considered to be part of the overlap when its *StartDate* is part of the overlapping period. | 
|         isPartOfOverlap := startDate >= startOverlap_i and | 
|                            startDate <= endOverlap_i; | 
|                             | 
|         //if( showInfo ){ info( ">>> isPartOfOverlap =", isPartOfOverlap ); } | 
|      | 
|         if( not preserveOccurrences_i or | 
|             ( calendar.Window() > 0 and | 
|               not isPartOfOverlap ) ) | 
|         { | 
|           //if( showInfo ){ info( "startDate < startOverlap_i : ", startDate.Format( mask ), "<", startOverlap_i.Format( mask ), "-->", startDate < startOverlap_i ); } | 
|           //if( showInfo ){ info( "endDate   > endOverlap_i   : ", endDate.  Format( mask ), ">", endOverlap_i.  Format( mask ), "-->", endDate   > endOverlap_i   ); } | 
|            | 
|           // Reuse the TimeInterval if it already exists, otherwise create a new one. | 
|           if( not isnull( timeInterval ) ) | 
|           { | 
|             timeInterval.IsSoftDeleted( false ); | 
|           } | 
|           else | 
|           { | 
|             if( this.DoGenerateOccurrence( start, end, firstOccurrence ) ) | 
|             { | 
|               leadingETI := this.CreateTimeInterval( start, end, this.Event().Capacity() ); | 
|                | 
|               if( not isnull( leadingETI ) ) | 
|               { | 
|                 // Also generate a new occurrence for the Subscripions. | 
|                 // Take the CalendarWindow of the subscribing Calendar and, if applicable,  | 
|                 // the specific RecurrencePeriod of the Subscription into account. | 
|                 traverse( this, Subscription, subscription, | 
|                           startDate <= subscription.Calendar().EndDate()   and | 
|                           endDate   >= subscription.Calendar().StartDate() and | 
|                           ( isnull( subscription.RecurrencePeriod() ) or | 
|                             ( startDate <= subscription.RecurrencePeriod().EndDate() and | 
|                               endDate   >= subscription.RecurrencePeriod().StartDate() ) ) ) | 
|                 { | 
|                   subscribingETI := subscription.CreateTimeInterval( start, end, this.Event().Capacity() ); | 
|                    | 
|                   if( not isnull( subscribingETI ) ) | 
|                   { | 
|                     // Register the occurrence (i.e. the ExplicitTimeInterval) as SubscribingETI of the LeadingETI. | 
|                     subscribingETI.LeadingETI( relset, leadingETI ); | 
|                   } | 
|                 } | 
|               } | 
|             } | 
|           } | 
|         } | 
|       } | 
|      | 
|       // Get the date of the next occurrence. | 
|       // When there are no more occurrences within the current recurrence, dateOfRecurrence is updated to the next recurrence. | 
|       date := pattern.GetDateOfNextOccurrence( dateOfRecurrence, date + 1 ); | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |