// bblb_schedulegenerationutil.h                                      -*-C++-*-
#ifndef INCLUDED_BBLB_SCHEDULEGENERATIONUTIL
#define INCLUDED_BBLB_SCHEDULEGENERATIONUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide functions for generating schedules of dates.
//
//@CLASSES:
//  bblb::ScheduleGenerationUtil: namespace for schedule generation functions
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component provides a 'struct',
// 'bblb::ScheduleGenerationUtil', that serves as a namespace for functions
// that generate a schedule; a set of dates limited to within a closed-interval
// date-range, represented by the specified 'earliest' and 'latest' dates.
// Typically, a schedule generation method can be defined by an algorithm
// specific to the method, an 'example' date, a closed-interval represented by
// an 'earliest' and a 'latest' date, and any other information required to
// determine the interval between successive dates in a schedule (for example,
// the number of days or months between successive dates).  The process of
// computing the dates within a schedule is exemplified using the following
// diagram:
//..
//  ___________|__________________|___________________|________
//         'example'          'earliest'          'latest'
//             .___.___.___.___.___|___|___|___|___|___.
//                                 ^   ^   ^   ^   ^
//  'interval':.___.               |   |   |   |   |
//  'schedule':                   [d0, d1, d2, d3, d4]
//..
// The schedule generated in the above diagram is '[d0, d1, d2, d3, d4]'.
// Notice that the 'example' date does not have to reside within the closed
// interval (the 'example' date is before the 'earliest' date in this diagram).
//
// More formally, the resulting 'schedule' is the subset of the infinite series
// of dates, defined by all dates separated by an integral multiple of
// intervals from the 'example' date, that reside within the closed-interval
// specified by 'earliest' and 'latest'.
//
// The following section provides a synopsis of the main functions provided in
// this component:
//..
//  'generateFromDayInterval'               Generate a schedule having an
//                                          interval of a fixed number of days.
//
//  'generateFromDayOfMonth'                Generate a schedule having an
//                                          interval of a fixed number of
//                                          months, with each date in the
//                                          schedule occuring on a specific day
//                                          of the month.
//
//  'generateFromBusinessDayOfMonth'        Generate a schedule having an
//                                          interval of a fixed number of
//                                          months, with each date in the
//                                          schedule occuring on a specific
//                                          business day of the month.
//
//  'generateFromDayOfWeekAfterDayOfMonth'  Generate a schedule having an
//                                          interval of a fixed number of
//                                          months, with each date in the
//                                          schedule occuring on a specific day
//                                          of the week on or after a specific
//                                          day of the month.
//
//  'generateFromDayOfWeekInMonth'          Generate a schedule having an
//                                          interval of a fixed number of
//                                          months, with each date in the
//                                          schedule occuring on a specific day
//                                          of the week in a specific week of
//                                          the month.
//..
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Generating a Schedule
///- - - - - - - - - - - - - - - -
// Suppose that we want to determine the sequence of dates that are:
//   * integral multiples of 9 months away from July 2007,
//   * on the 23rd day of the month,
//   * and within the closed interval '[02/01/2012, 02/28/2015]'.
//
// First, we define the inputs and output to the schedule generation function:
//..
//  bdlt::Date earliest(2012, 2,  1);
//  bdlt::Date   latest(2015, 2, 28);
//  bdlt::Date  example(2007, 7, 23);
//
//  bsl::vector<bdlt::Date> schedule;
//..
// Now, we invoke the 'generateFromDayOfMonth' routine to obtain the subset of
// dates:
//..
//  bblb::ScheduleGenerationUtil::generateFromDayOfMonth(
//                                                  &schedule,
//                                                  earliest,
//                                                  latest,
//                                                  example.year(),
//                                                  example.month(),
//                                                  9,    // 'intervalInMonths'
//                                                  23);  // 'targetDayOfMonth'
//..
// Finally, we assert that the generated schedule is what we expect:
//..
//  assert(4 == schedule.size());
//  assert(bdlt::Date(2012, 10, 23) == schedule[0]);
//  assert(bdlt::Date(2013,  7, 23) == schedule[1]);
//  assert(bdlt::Date(2014,  4, 23) == schedule[2]);
//  assert(bdlt::Date(2015,  1, 23) == schedule[3]);
//..

#include <bblscm_version.h>

#include <bdlt_calendar.h>
#include <bdlt_date.h>
#include <bdlt_dayofweek.h>

#include <bsls_libraryfeatures.h>

#include <bsl_vector.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
# include <memory_resource>
#endif

#include <vector>                   // 'std::vector', 'std::pmr::vector'

namespace BloombergLP {
namespace bblb {

                      // =============================
                      // struct ScheduleGenerationUtil
                      // =============================

struct ScheduleGenerationUtil {
    // This 'struct' provides a namespace for utility functions that generate
    // schedules.

    // CLASS METHODS
    static void generateFromDayInterval(
                                 bsl::vector<bdlt::Date>      *schedule,
                                 const bdlt::Date&             earliest,
                                 const bdlt::Date&             latest,
                                 const bdlt::Date&             example,
                                 int                           intervalInDays);
    static void generateFromDayInterval(
                                 std::vector<bdlt::Date>      *schedule,
                                 const bdlt::Date&             earliest,
                                 const bdlt::Date&             latest,
                                 const bdlt::Date&             example,
                                 int                           intervalInDays);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static void generateFromDayInterval(
                                 std::pmr::vector<bdlt::Date> *schedule,
                                 const bdlt::Date&             earliest,
                                 const bdlt::Date&             latest,
                                 const bdlt::Date&             example,
                                 int                           intervalInDays);
#endif
        // Load, into the specified 'schedule', the chronologically increasing
        // sequence of unique dates that are integral multiples of the
        // specified 'intervalInDays' away from the specified 'example' date,
        // and within the specified closed-interval '[earliest, latest]'.  The
        // behavior is undefined unless 'earliest <= latest' and
        // '1 <= intervalInDays'.

    static void generateFromDayOfMonth(
                             bsl::vector<bdlt::Date>      *schedule,
                             const bdlt::Date&             earliest,
                             const bdlt::Date&             latest,
                             int                           exampleYear,
                             int                           exampleMonth,
                             int                           intervalInMonths,
                             int                           targetDayOfMonth,
                             int                           targetDayOfFeb = 0);
    static void generateFromDayOfMonth(
                             std::vector<bdlt::Date>      *schedule,
                             const bdlt::Date&             earliest,
                             const bdlt::Date&             latest,
                             int                           exampleYear,
                             int                           exampleMonth,
                             int                           intervalInMonths,
                             int                           targetDayOfMonth,
                             int                           targetDayOfFeb = 0);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static void generateFromDayOfMonth(
                             std::pmr::vector<bdlt::Date> *schedule,
                             const bdlt::Date&             earliest,
                             const bdlt::Date&             latest,
                             int                           exampleYear,
                             int                           exampleMonth,
                             int                           intervalInMonths,
                             int                           targetDayOfMonth,
                             int                           targetDayOfFeb = 0);
#endif
        // Load, into the specified 'schedule', the chronologically increasing
        // sequence of unique dates that are on the specified
        // 'targetDayOfMonth' (or the last day of the month if
        // 'targetDayOfMonth' would be past the end of the month), integral
        // multiples of the specified 'intervalInMonths' away from the
        // specified 'exampleYear' and 'exampleMonth', and within the specified
        // closed-interval '[earliest, latest]'.  Optionally specify
        // 'targetDayOfFeb' to replace 'targetDayOfMonth' whenever the month of
        // a 'schedule' entry is February.  The behavior is undefined unless
        // 'earliest <= latest', '1 <= exampleYear <= 9999',
        // '1 <= exampleMonth <= 12', '1 <= intervalInMonths',
        // '1 <= targetDayOfMonth <= 31', and '0 <= targetDayOfFeb <= 29'.

    static void generateFromBusinessDayOfMonth(
                       bsl::vector<bdlt::Date>      *schedule,
                       const bdlt::Date&             earliest,
                       const bdlt::Date&             latest,
                       int                           exampleYear,
                       int                           exampleMonth,
                       int                           intervalInMonths,
                       const bdlt::Calendar&         calendar,
                       int                           targetBusinessDayOfMonth);
    static void generateFromBusinessDayOfMonth(
                       std::vector<bdlt::Date>      *schedule,
                       const bdlt::Date&             earliest,
                       const bdlt::Date&             latest,
                       int                           exampleYear,
                       int                           exampleMonth,
                       int                           intervalInMonths,
                       const bdlt::Calendar&         calendar,
                       int                           targetBusinessDayOfMonth);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static void generateFromBusinessDayOfMonth(
                       std::pmr::vector<bdlt::Date> *schedule,
                       const bdlt::Date&             earliest,
                       const bdlt::Date&             latest,
                       int                           exampleYear,
                       int                           exampleMonth,
                       int                           intervalInMonths,
                       const bdlt::Calendar&         calendar,
                       int                           targetBusinessDayOfMonth);
#endif
        // Load, into the specified 'schedule', the chronologically increasing
        // sequence of unique dates that are on the specified
        // 'targetBusinessDayOfMonth' (or the highest count possible in the
        // resulting month), integral multiples of the specified
        // 'intervalInMonths' away from the specified 'exampleYear' and
        // 'exampleMonth', and within the specified closed-interval
        // '[earliest, latest]'.  Business days, as per the specified
        // 'calendar', are counted, if 'targetBusinessDayOfMonth' is positive,
        // from and including the chronologically earliest business day to
        // chronologically later business days, and if
        // 'targetBusinessDayOfMonth' is negative, from and including the
        // chronologically latest business day to chronologically earlier
        // business days.  If any of the months required for the schedule do
        // not have a business day, return an empty 'schedule'.  The behavior
        // is undefined unless 'earliest <= latest',
        // '1 <= exampleYear <= 9999', '1 <= exampleMonth <= 12',
        // '1 <= intervalInMonths', and
        // '1 <= abs(targetBusinessDayOfMonth) <= 31'.

    static void generateFromDayOfWeekAfterDayOfMonth(
                                bsl::vector<bdlt::Date>      *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           dayOfMonth);
    static void generateFromDayOfWeekAfterDayOfMonth(
                                std::vector<bdlt::Date>      *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           dayOfMonth);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static void generateFromDayOfWeekAfterDayOfMonth(
                                std::pmr::vector<bdlt::Date> *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           dayOfMonth);
#endif
        // Load, into the specified 'schedule', the chronologically increasing
        // sequence of unique dates that are on the specified 'dayOfWeek' on or
        // after the specified 'dayOfMonth', integral multiples of the
        // specified 'intervalInMonths' away from the specified 'exampleYear'
        // and 'exampleMonth', and within the specified closed-interval
        // '[earliest, latest]'.  If any of the months required for the
        // schedule have fewer than 'dayOfMonth' days, return an empty
        // 'schedule'.  The behavior is undefined unless 'earliest <= latest',
        // '1 <= exampleYear <= 9999', '1 <= exampleMonth <= 12',
        // '1 <= intervalInMonths', and '1 <= dayOfMonth <= 31'.

    static void generateFromDayOfWeekInMonth(
                                bsl::vector<bdlt::Date>      *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           occurrenceWeek);
    static void generateFromDayOfWeekInMonth(
                                std::vector<bdlt::Date>      *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           occurrenceWeek);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static void generateFromDayOfWeekInMonth(
                                std::pmr::vector<bdlt::Date> *schedule,
                                const bdlt::Date&             earliest,
                                const bdlt::Date&             latest,
                                int                           exampleYear,
                                int                           exampleMonth,
                                int                           intervalInMonths,
                                bdlt::DayOfWeek::Enum         dayOfWeek,
                                int                           occurrenceWeek);
#endif
        // Load, into the specified 'schedule', the chronologically increasing
        // sequence of unique dates that are on the specified 'dayOfWeek' of
        // the specified 'occurrenceWeek' of the month, integral multiples of
        // the specified 'intervalInMonths' away from the specified
        // 'exampleYear' and 'exampleMonth', and within the specified
        // closed-interval '[earliest, latest]'.  The behavior is undefined
        // unless 'earliest <= latest', '1 <= exampleYear <= 9999',
        // '1 <= exampleMonth <= 12', '1 <= intervalInMonths', and
        // '1 <= occurrenceWeek <= 4'.
};

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------