// 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>

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

namespace BloombergLP {
namespace bblb {

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

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

    // CLASS METHODS

    /// 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 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 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 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
    /// `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 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 `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 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` 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`.
    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
};

}  // 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 ----------------------------------
