Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method GenerateOptCampaignSubPeriods 
 | 
{ 
 | 
  Description: 'Generate campaign sub period objects for opt campaign unit' 
 | 
  TextBody: 
 | 
  [* 
 | 
    this.OptCampaignUnitSubPeriod( relflush ); 
 | 
     
 | 
    startpuzzle := this.OptCampaign().PuzzleStart(); 
 | 
    endpuzzle := this.OptCampaign().PuzzleEnd(); 
 | 
    tokenizer := OptCampaign::Tokenizer() 
 | 
     
 | 
    unit := Unit::FindUnitTypeIndex( this.UnitID() ); 
 | 
     
 | 
    //First: create ocusp for last period of frozen horizon 
 | 
    lastfrozenup := maxselect( unit,  
 | 
                            UnitPeriod,  
 | 
                            up,  
 | 
                            not up.IsFrozen() 
 | 
                            and up.IsPlanning()  
 | 
                            and up.Start() <= endpuzzle  
 | 
                            and up.End() > startpuzzle 
 | 
                            and Unit::GetIsPeriodFrozen( unit, up.Period_MP() ), 
 | 
                            up.Start() ) 
 | 
     
 | 
    firstcampaignvalue := ""; 
 | 
    firsttransitionvalue := "" 
 | 
     
 | 
    if( not isnull( lastfrozenup ) ) 
 | 
    { 
 | 
      lastfrozenperiod := lastfrozenup.Period_MP() 
 | 
      campaignonfrozenlimit := select( unit, Campaign_MP, c, c.Start() < lastfrozenperiod.End(), c.End() >= lastfrozenperiod.End() ) 
 | 
      transitiononfrozenlimit := select( unit, Transition_MP, t, t.Start() < lastfrozenperiod.End(), t.End() >= lastfrozenperiod.End() ) 
 | 
       
 | 
      if( not isnull( campaignonfrozenlimit ) ) 
 | 
      { 
 | 
        firstcampaignvalue := campaignonfrozenlimit.Start().Format( "YM2D2 H2:m:s" )  
 | 
                              + tokenizer + campaignonfrozenlimit.End().Format( "YM2D2 H2:m:s" )  
 | 
                              + tokenizer + OptCampaign::TypeCampaign()  
 | 
                              + tokenizer + [String]campaignonfrozenlimit.Start()  
 | 
                              + tokenizer + [String]lastfrozenperiod.End()  
 | 
                              + tokenizer + [String]campaignonfrozenlimit.Key() 
 | 
                                           
 | 
      } 
 | 
      else if( not isnull( transitiononfrozenlimit ) ) 
 | 
      { 
 | 
        firsttransitionvalue := transitiononfrozenlimit.Start().Format( "YM2D2 H2:m:s" )  
 | 
                                + tokenizer + transitiononfrozenlimit.End().Format( "YM2D2 H2:m:s" )  
 | 
                                + tokenizer + OptCampaign::TypeTransition()  
 | 
                                + tokenizer + [String]transitiononfrozenlimit.Start()  
 | 
                                + tokenizer + [String]minvalue(  transitiononfrozenlimit.End(), unit.EndOfFrozen() ) 
 | 
                                + tokenizer + [String]transitiononfrozenlimit.Key() 
 | 
                                           
 | 
      } 
 | 
    } 
 | 
    //Then, create other ocusps 
 | 
     
 | 
    endcampaignhorizon := unit.CampaignTypeRequirementHorizon(); 
 | 
    //set the endpuzzle to take campaign horizon into account. Need the - 1 days here due to difference in inclusive / exclusive 
 | 
    endpuzzle := minvalue( endpuzzle, endcampaignhorizon - Duration::Days( 1 ) ); 
 | 
     
 | 
    //the timeblock values will concatenated as follows: 
 | 
    //start time formatted to get correct sorting 
 | 
    //end time formatted to get correct sorting 
 | 
    //type of the timeblock (period, campaign or transition 
 | 
    //start time formatted as string that can be converted back to datetime using standard conversion 
 | 
    //end time formatted as string that can be converted back to datetime using standard conversion 
 | 
    //Reference key for fixed campaigns and transitions 
 | 
    periods := selectuniquevalues(  unit 
 | 
                                  , UnitPeriod 
 | 
                                  , up 
 | 
                                  , not up.IsFrozen() 
 | 
                                    and up.IsPlanning()  
 | 
                                    and up.Start() <= endpuzzle  
 | 
                                    and up.End() > startpuzzle 
 | 
                                    and not Unit::GetIsPeriodFrozen( unit, up.Period_MP() ) 
 | 
                                  , up.Start().Format( "YM2D2 H2:m:s" )  
 | 
                                    + tokenizer + up.End().Format( "YM2D2 H2:m:s" )  
 | 
                                    + tokenizer + OptCampaign::TypePeriod() 
 | 
                                    + tokenizer + [String]up.Start()  
 | 
                                    + tokenizer + [String]up.End()  
 | 
                                    + tokenizer + [String]up.Key() 
 | 
                                  ) 
 | 
     
 | 
    fixedcampaigns := selectuniquevalues( unit 
 | 
                                         , Campaign_MP 
 | 
                                         , campaign 
 | 
                                         , campaign.IsFrozen()     //this should be changed to campagins being fixed 
 | 
                                           and campaign.Start() <= endpuzzle  
 | 
                                           and campaign.End() > startpuzzle   
 | 
                                         , campaign.Start().Format( "YM2D2 H2:m:s" )  
 | 
                                           + tokenizer + campaign.End().Format( "YM2D2 H2:m:s" )  
 | 
                                           + tokenizer + OptCampaign::TypeCampaign()  
 | 
                                           + tokenizer + [String]campaign.Start()  
 | 
                                           + tokenizer + [String]campaign.End()  
 | 
                                           + tokenizer + [String]campaign.Key() 
 | 
                                         ) 
 | 
    fixedtransitions := selectuniquevalues( unit 
 | 
                                           , Transition_MP 
 | 
                                           , transition 
 | 
                                           , transition.IsFrozen()     //this should be changed to campagins being fixed 
 | 
                                             and transition.Start() <= endpuzzle   
 | 
                                             and transition.End() > startpuzzle 
 | 
                                           , transition.Start().Format( "YM2D2 H2:m:s" )  
 | 
                                             + tokenizer + transition.End().Format( "YM2D2 H2:m:s" )  
 | 
                                             + tokenizer + OptCampaign::TypeTransition()  
 | 
                                             + tokenizer + [String]transition.Start()  
 | 
                                             + tokenizer + [String]transition.End()  
 | 
                                             + tokenizer + [String]transition.Key() 
 | 
                                           ) 
 | 
     
 | 
    if( not firstcampaignvalue = "" ) 
 | 
    { 
 | 
      fixedcampaigns := fixedcampaigns.Union( firstcampaignvalue ) 
 | 
    } 
 | 
    if( not firsttransitionvalue = "" ) 
 | 
    { 
 | 
      fixedtransitions := fixedtransitions.Union( firsttransitionvalue ) 
 | 
    } 
 | 
     
 | 
    timeblocks := periods.Union( fixedcampaigns ).Union( fixedtransitions ); 
 | 
    timeblocks := timeblocks.Sort(); 
 | 
    //init variables 
 | 
    if(  timeblocks.Size() > 0 ) 
 | 
    { 
 | 
      //Get the values from the first element. This will prevent having to  
 | 
      timeblockelements := timeblocks.Element( 0 ).Tokenize( tokenizer ); 
 | 
      subperiodstart := [DateTime]timeblockelements.Element( 3 ); //get the start that can be converted 
 | 
      subperiodend := [DateTime]timeblockelements.Element( 4 ); //get the end that can be converted 
 | 
      subperiodtype := timeblockelements.Element( 2 ); 
 | 
      subperiodrefkey := [Key]timeblockelements.Element( 5 ); 
 | 
      subperiodisfixed := subperiodtype <> "Period";  
 | 
       
 | 
      subperiodend := minvalue( subperiodend, endcampaignhorizon ); 
 | 
       
 | 
      traverse( timeblocks, Elements, timeblock ) 
 | 
      { 
 | 
        timeblockelements := timeblock.Tokenize( tokenizer ); 
 | 
        timeblockstart := [DateTime]timeblockelements.Element( 3 );  
 | 
        timeblockend := [DateTime]timeblockelements.Element( 4 );  
 | 
        timeblocktype := timeblockelements.Element( 2 ); 
 | 
        timeblockrefkey := [Key]timeblockelements.Element( 5 ) 
 | 
        timeblockisfixed := timeblocktype <> "Period"; 
 | 
          
 | 
        //If the next period starts earlier than the previous ends and its a fixed period  
 | 
        //then keep creating fixed sub periods until the end of the fixed campaign/transition is reached 
 | 
        if( timeblockstart < subperiodend and subperiodisfixed ) 
 | 
        { 
 | 
          endsubperiodfixed := timeblockstart 
 | 
          //Close off the previous subperiod for the fixed block, but only if the subperiod has a duration 
 | 
          if( endsubperiodfixed > subperiodstart ) 
 | 
          { 
 | 
            OptCampaignUnitSubPeriod::Create( this, subperiodstart, endsubperiodfixed, subperiodtype, subperiodrefkey, subperiodisfixed );   
 | 
          } 
 | 
          //Set the start time to the end of subperiod that was just created 
 | 
          subperiodstart := endsubperiodfixed; 
 | 
          //if the fixed period ends in this subperiod create an additional block for the end part of the fixed block  
 | 
          if( subperiodend < timeblockend ) 
 | 
          { 
 | 
            OptCampaignUnitSubPeriod::Create( this, subperiodstart, subperiodend, subperiodtype, subperiodrefkey, subperiodisfixed );  
 | 
            //now set the variables for the next subperiod 
 | 
            subperiodstart := subperiodend 
 | 
            subperiodend := timeblockend; 
 | 
            subperiodtype := timeblocktype; 
 | 
            subperiodrefkey := timeblockrefkey; 
 | 
            subperiodisfixed := timeblockisfixed; 
 | 
          } 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
          //when we have a fixed supperiod then the end date is known, in other cases the enddate the previous period is the start of the next period 
 | 
          if( not subperiodisfixed ) 
 | 
          { 
 | 
            subperiodend := timeblockstart; 
 | 
          } 
 | 
          //Close off the previous timeblock, but only if the subperiod has a duration 
 | 
          if( subperiodend > subperiodstart ) 
 | 
          { 
 | 
            OptCampaignUnitSubPeriod::Create( this, subperiodstart, subperiodend, subperiodtype, subperiodrefkey, subperiodisfixed );   
 | 
          } 
 | 
          //Setup the next period 
 | 
          //the start is the start of the period or the end of the previous period which could be later if it was a fixed period 
 | 
          subperiodstart := timeblockstart 
 | 
          subperiodend := minvalue( timeblockend, endcampaignhorizon ); 
 | 
          subperiodtype := timeblocktype; 
 | 
          subperiodrefkey := timeblockrefkey; 
 | 
          subperiodisfixed := timeblockisfixed; 
 | 
        } 
 | 
      } 
 | 
      //Close the last timeblock 
 | 
      if( subperiodend > subperiodstart )  
 | 
      { 
 | 
        //Close off the previous timeblock 
 | 
        OptCampaignUnitSubPeriod::Create( this, subperiodstart, subperiodend, subperiodtype, subperiodrefkey, subperiodisfixed );   
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
} 
 |