// bdlt_calendarloader.h                                              -*-C++-*-
#ifndef INCLUDED_BDLT_CALENDARLOADER
#define INCLUDED_BDLT_CALENDARLOADER

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

//@PURPOSE: Provide a protocol (or pure interface) for loading calendars.
//
//@CLASSES:
//  bdlt::CalendarLoader: pure interface for loading calendars
//
//@SEE_ALSO: bdlt_calendarcache, bdlt_packedcalendar
//
//@DESCRIPTION: This component provides a protocol, `bdlt::CalendarLoader`, for
// loading calendars from a specific source.  Each repository of calendar
// information can be supported by a distinct implementation of the
// `CalendarLoader` protocol.  The protocol's primary method, `load`, loads a
// calendar into a `bdlt::PackedCalendar` object.  The calendar to load is
// identified by name, which is specified by a null-terminated C-style string
// (i.e., `const char *`).
//
///Thread Safety
///-------------
// Unless otherwise documented, a single calendar loader object is not safe for
// concurrent access by multiple threads.  Classes derived from
// `bdlt::CalendarLoader` that are specifically designed for concurrent access
// must be documented as such.  Unless specifically documented otherwise,
// separate objects of classes derived from `bdlt::CalendarLoader` may safely
// be used in separate threads.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Implementing the `bdlt::CalendarLoader` Protocol
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates an elided concrete implementation of the
// `bdlt::CalendarLoader` protocol that interprets calendar information
// contained in ASCII strings that are formatted using JSON.  Note that, in
// general, an implementation of `bdlt::CalendarLoader` must obtain calendar
// information from *some* data source.  Our elided implementation leaves it
// unspecified as to where the JSON strings are obtained (i.e., whether from a
// file system, a database, a local or remote service, etc.).
//
// First, we show the JSON format that our calendar loader accepts.  For
// simplicity, we omit support for holiday codes and weekend-days transitions:
// ```
// {
//     "firstDate":   "YYYY-MM-DD",
//     "lastDate":    "YYYY-MM-DD",
//     "weekendDays": [ wd, ... ],
//     "holidays":    [ "YYYY-MM-DD", ... ]
// }
// ```
// Note that "YYYY-MM-DD" is an ISO 8601 representation for the value of a
// `bdlt::Date` object and `wd` is an integer in the range `[1 .. 7]`.  The
// range used for specifying weekend days corresponds directly to the
// `bdlt::DayOfWeek::Enum` enumeration, `[e_SUN = 1 .. e_SAT]` (see
// `bdlt_dayofweek`).  We assume that the four JSON attributes, "firstDate",
// "lastDate", "weekendDays", and "holidays", must occur in the JSON string in
// the order in which they appear in the above display, but only "firstDate"
// and "lastDate" are *required* attributes.
//
// Then, we define the interface of our implementation:
// ```
// /// This class provides a concrete implementation of the
// /// `bdlt::CalendarLoader` protocol (an abstract interface) for loading
// /// a calendar.  This elided implementation obtains calendar information
// /// from ASCII strings formatted using JSON.  The source of the strings
// /// is unspecified.
// class MyCalendarLoader : public bdlt::CalendarLoader {
//
//   public:
//     // CREATORS
//
//     /// Create a `MyCalendarLoader` object.
//     MyCalendarLoader();
//
//     /// Destroy this object.
//     virtual ~MyCalendarLoader();
//
//     // MANIPULATORS
//
//     /// Load, into the specified `result`, the calendar identified by
//     /// the specified `calendarName`.  Return 0 on success, and a
//     /// non-zero value otherwise.  If the calendar corresponding to
//     /// `calendarName` is not found, 1 is returned with no effect on
//     /// `*result`.  If a non-zero value other than 1 is returned
//     /// (indicating a different error), `*result` is valid, but its
//     /// value is undefined.
//     virtual int load(bdlt::PackedCalendar *result,
//                      const char           *calendarName);
// };
// ```
// Next, we implement the creators, trivially, as `MyCalendarLoader` does not
// contain any instance data members:
// ```
// // CREATORS
// inline
// MyCalendarLoader::MyCalendarLoader()
// {
// }
//
// inline
// MyCalendarLoader::~MyCalendarLoader()
// {
// }
// ```
// Then, we implement the `load` function:
// ```
// // MANIPULATORS
// int MyCalendarLoader::load(bdlt::PackedCalendar *result,
//                            const char           *calendarName)
// {
// ```
// Next, we look up the calendar identified by `calendarName` and load the
// corresponding text into a `bsl::string` object, `json` (as stated earlier,
// we do not specify in this example from where the calendar information is
// obtained):
// ```
//     // Obtain the information for the calendar identified by 'calendarName'
//     // from an unspecified data source and load it into the 'json' string.
//
//     bsl::string json;
//
//     // Since a JSON parser is not available to 'bdlt', this example assumes
//     // that 'json' is populated with the following specific data:
//     //..
//     //  {
//     //      "firstDate":   "1990-01-01",
//     //      "lastDate":    "1990-12-31",
//     //      "weekendDays": [ 1, 7 ],
//     //      "holidays":    [ "1990-05-28", "1990-07-04", "1990-09-03" ]
//     //  }
//     //..
//     // Similarly, we hard-wire the value of a status flag, 'rc', to
//     // indicate that this string was successfully retrieved from the data
//     // source.
//
//     int rc = 0;  // success obtaining calendar information
//
//     if (rc != 0) {
//         return 1;                                                 // RETURN
//     }
// ```
// Note that the non-zero value 1 is returned only in the case where the
// calendar information corresponding to `calendarName` cannot be found (per
// the contract for the `load` method).
//
// Then, we parse the "firstDate" and "lastDate" attributes from the `json`
// string, loading the results into like-named variables:
// ```
//     // Parse the "firstDate" and "lastDate" JSON attributes and load the
//     // results into 'firstDate' and 'lastDate', respectively.  It is an
//     // error if either of the "firstDate" or "lastDate" attributes are
//     // missing, or if they are out of order.
//
//     bdlt::Date firstDate;
//     bdlt::Date lastDate;
//
//     // For the purposes of this Usage, we hard-wire the first and last
//     // dates that are hypothetically parsed from the 'json' string, and
//     // set the 'rc' status flag indicating that parsing succeeded.
//
//     firstDate.setYearMonthDay(1990,  1,  1);
//     lastDate.setYearMonthDay( 1990, 12, 31);
//     rc = 0;  // success parsing "firstDate" and "lastDate" attributes
//
//     if (rc != 0 || firstDate > lastDate) {
//         return 2;                                                 // RETURN
//     }
//
//     result->removeAll();
//
//     result->setValidRange(firstDate, lastDate);
// ```
// Next, we parse the "weekendDays" attribute from `json` and load the result
// into a `bdlt::DayOfWeekSet` object, `dayOfWeekSet`:
// ```
//     // For the purposes of this Usage, we hard-wire a boolean flag
//     // indicating that the "weekendDays" attribute was hypothetically
//     // detected in the 'json' string.
//
//     bool isWeekendDaysAttributePresent = true;
//
//     if (isWeekendDaysAttributePresent) {
//
//         // Parse the "weekendDays" JSON attribute and load 'dayOfWeekSet'
//         // with the result.
//
//         bdlt::DayOfWeekSet dayOfWeekSet;
//
//         // For the purposes of this Usage, we hard-wire the weekend days
//         // that are hypothetically parsed from the 'json' string, and set
//         // the 'rc' status flag indicating that parsing succeeded.
//
//         dayOfWeekSet.add(bdlt::DayOfWeek::e_SUN);
//         dayOfWeekSet.add(bdlt::DayOfWeek::e_SAT);
//         rc = 0;  // success parsing "weekendDays" attribute
//
//         if (rc != 0) {
//             return 3;                                             // RETURN
//         }
//
//         result->addWeekendDays(dayOfWeekSet);
//     }
// ```
// Now, we parse the "holidays" attribute from `json` and load the result into
// a `bsl::vector<bdlt::Date>` object, `holidays`:
// ```
//     // For the purposes of this Usage, we hard-wire a boolean flag
//     // indicating that the "holidays" attribute was hypothetically detected
//     // in the 'json' string.
//
//     bool isHolidaysAttributePresent = true;
//
//     if (isHolidaysAttributePresent) {
//
//         // Parse the "holidays" JSON attribute and load 'holidays' with the
//         // result.
//
//         bsl::vector<bdlt::Date> holidays;
//
//         // For the purposes of this Usage, we hard-wire the holidays that
//         // are hypothetically parsed from the 'json' string, and set the
//         // 'rc' status flag indicating that parsing succeeded.
//
//         holidays.push_back(bdlt::Date(1990,  5, 28));  // Memorial Day
//         holidays.push_back(bdlt::Date(1990,  7,  4));  // Independence Day
//         holidays.push_back(bdlt::Date(1990,  9,  3));  // Labor Day
//         rc = 0;  // success parsing "holidays" attribute
//
//         if (rc != 0) {
//             return 4;                                             // RETURN
//         }
//
//         bsl::vector<bdlt::Date>::const_iterator it = holidays.begin();
//
//         while (it != holidays.end()) {
//             const bdlt::Date& holiday = *it;
//
//             if (holiday < firstDate || holiday > lastDate) {
//                 return 5;                                         // RETURN
//             }
//
//             result->addHoliday(holiday);
//
//             ++it;
//         }
//     }
// ```
// Note that the `addHoliday` method can extend the range of the calendar.  Our
// calendar loader instead imposes the requirement that the dates specified in
// the "holidays" JSON attribute must be within the range
// `[firstDate .. lastDate]`.
//
// Finally, we return 0 indicating success:
// ```
//     return 0;
// }
// ```

#include <bdlscm_version.h>

namespace BloombergLP {
namespace bdlt {

class PackedCalendar;

                         // ====================
                         // class CalendarLoader
                         // ====================

/// This class defines a protocol used to load calendars from a specific
/// source.  Each repository of calendar information can be supported by a
/// distinct implementation of this protocol.
class CalendarLoader {

  public:
    // CREATORS

    /// Destroy this object.
    virtual ~CalendarLoader();

    // MANIPULATORS

    /// Load, into the specified `result`, the calendar identified by the
    /// specified `calendarName`.  Return 0 on success, and a non-zero value
    /// otherwise.  If the calendar corresponding to `calendarName` is not
    /// found, 1 is returned with no effect on `*result`.  If a non-zero
    /// value other than 1 is returned (indicating a different error),
    /// `*result` is valid, but its value is undefined.
    virtual int load(PackedCalendar *result, const char *calendarName) = 0;
};

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

#endif

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