/*
* Copyright (C) 2003, International Business Machines Corporation and others. All Rights Reserved.
********************************************************************************
*
* File BUDDHCAL.H
*
* Modification History:
*
*   Date        Name        Description
*   05/13/2003  srl          copied from gregocal.h
********************************************************************************
*/

#ifndef BUDDHCAL_H
#define BUDDHCAL_H

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include "unicode/calendar.h"
#include "unicode/gregocal.h"

U_NAMESPACE_BEGIN

/**
 * Concrete class which provides the Buddhist calendar.
 * <P>
 * <code>BuddhistCalendar</code> is a subclass of <code>GregorianCalendar</code>
 * that numbers years since the birth of the Buddha.  This is the civil calendar
 * in some predominantly Buddhist countries such as Thailand, and it is used for
 * religious purposes elsewhere.
 * <p>
 * The Buddhist calendar is identical to the Gregorian calendar in all respects
 * except for the year and era.  Years are numbered since the birth of the
 * Buddha in 543 BC (Gregorian), so that 1 AD (Gregorian) is equivalent to 544
 * BE (Buddhist Era) and 1998 AD is 2541 BE.
 * <p>
 * The Buddhist Calendar has only one allowable era: <code>BE</code>.  If the
 * calendar is not in lenient mode (see <code>setLenient</code>), dates before
 * 1/1/1 BE are rejected as an illegal argument.
 * <p>
 * @internal
 */
class U_I18N_API BuddhistCalendar : public GregorianCalendar {
public:

    /**
     * Useful constants for BuddhistCalendar.  Only one Era.
     * @internal
     */
    enum EEras {
       BE
    };

    /**
     * Constructs a BuddhistCalendar based on the current time in the default time zone
     * with the given locale.
     *
     * @param aLocale  The given locale.
     * @param success  Indicates the status of BuddhistCalendar object construction.
     *                 Returns U_ZERO_ERROR if constructed successfully.
     * @internal
     */
    BuddhistCalendar(const Locale& aLocale, UErrorCode& success);


    /**
     * Destructor
     * @internal
     */
    virtual ~BuddhistCalendar();

    /**
     * Copy constructor
     * @param source    the object to be copied.
     * @internal
     */
    BuddhistCalendar(const BuddhistCalendar& source);

    /**
     * Default assignment operator
     * @param right    the object to be copied.
     * @internal
     */
    BuddhistCalendar& operator=(const BuddhistCalendar& right);

    /**
     * Create and return a polymorphic copy of this calendar.
     * @return    return a polymorphic copy of this calendar.
     * @internal
     */
    virtual Calendar* clone(void) const;

public:
    /**
     * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
     * override. This method is to implement a simple version of RTTI, since not all C++
     * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
     * this method.
     *
     * @return   The class ID for this object. All objects of a given class have the
     *           same class ID. Objects of other classes have different class IDs.
     * @internal
     */
    virtual UClassID getDynamicClassID(void) const;

    /**
     * Return the class ID for this class. This is useful only for comparing to a return
     * value from getDynamicClassID(). For example:
     *
     *      Base* polymorphic_pointer = createPolymorphicObject();
     *      if (polymorphic_pointer->getDynamicClassID() ==
     *          Derived::getStaticClassID()) ...
     *
     * @return   The class ID for all objects of this class.
     * @internal
     */
    static inline UClassID getStaticClassID(void);

    /**
     * return the calendar type, "buddhist".
     *
     * @return calendar type
     * @internal
     */
    virtual const char * getType() const;

    /**
     * (Overrides Calendar) UDate Arithmetic function. Adds the specified (signed) amount
     * of time to the given time field, based on the calendar's rules.  For more
     * information, see the documentation for Calendar::add().
     *
     * @param field   The time field.
     * @param amount  The amount of date or time to be added to the field.
     * @param status  Output param set to success/failure code on exit. If any value
     *                previously set in the time field is invalid, this will be set to
     *                an error status.
     * @draft ICU 2.6
     */
    virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode& status);

    /**
     * Gets the maximum value for the given time field. e.g. for DAY_OF_MONTH,
     * 31.
     *
     * @param field  The given time field.
     * @return       The maximum value for the given time field.
     * @draft ICU 2.6
     */
    int32_t getMaximum(UCalendarDateFields field) const;

    /**
     * Gets the lowest maximum value for the given field if varies. Otherwise same as
     * getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
     *
     * @param field  The given time field.
     * @return       The lowest maximum value for the given time field.
     * @draft ICU 2.6
     */
    int32_t getLeastMaximum(UCalendarDateFields field) const;

    /**
     * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
     */
    inline virtual int32_t getMaximum(EDateFields field) const { return getMaximum((UCalendarDateFields)field); }
    /**
     * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
     */
    inline virtual int32_t getLeastMaximum(EDateFields field) const { return getLeastMaximum((UCalendarDateFields)field); }
    /**
     * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
     */
    inline virtual void add(EDateFields field, int32_t amount, UErrorCode& status) { add((UCalendarDateFields)field, amount, status); }

private:
    BuddhistCalendar(); // default constructor not implemented

    static const char fgClassID;

 protected:
    /**
     * Return the extended year defined by the current fields.  This will
     * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
     * as UCAL_ERA) specific to the calendar system, depending on which set of
     * fields is newer.
     * @return the extended year
     * @internal
     */
    virtual int32_t handleGetExtendedYear();
    /**
     * Subclasses may override this method to compute several fields
     * specific to each calendar system.  
     * @internal
     */
    virtual void handleComputeFields(int32_t julianDay, UErrorCode& status);
    /**
     * Subclass API for defining limits of different types.
     * @param field one of the field numbers
     * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
     * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
     * @internal
     */
    virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
        /**
     * Return the Julian day number of day before the first day of the
     * given month in the given extended year.  Subclasses should override
     * this method to implement their calendar system.
     * @param eyear the extended year
     * @param month the zero-based month, or 0 if useMonth is false
     * @param useMonth if false, compute the day before the first day of
     * the given year, otherwise, compute the day before the first day of
     * the given month
     * @param return the Julian day number of the day before the first
     * day of the given month and year
     * @internal
     */
    virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
                                            UBool useMonth) const;

    /**
     * month length of current month
     * @internal
     */
    virtual int32_t monthLength(int32_t month) const; 
    /**
     * month length of month
     * @internal
     */
    virtual int32_t monthLength(int32_t month, int32_t year) const; 

    /**
     * month length of current month
     * @internal
     */
    int32_t getGregorianYear(UErrorCode& status) const;

    /** 
     * Calculate the era for internal computation
     * @internal
     */
    virtual int32_t internalGetEra() const;

    /**
     * Returns TRUE because the Buddhist Calendar does have a default century
     * @internal
     */
    virtual UBool haveDefaultCentury() const;

    /**
     * Returns the date of the start of the default century
     * @return start of century - in milliseconds since epoch, 1970
     * @internal
     */
    virtual UDate defaultCenturyStart() const;

    /**
     * Returns the year in which the default century begins
     * @internal
     */
    virtual int32_t defaultCenturyStartYear() const;

 private: // default century stuff.
    /**
     * The system maintains a static default century start date.  This is initialized
     * the first time it is used.  Before then, it is set to SYSTEM_DEFAULT_CENTURY to
     * indicate an uninitialized state.  Once the system default century date and year
     * are set, they do not change.
     */
    static UDate         fgSystemDefaultCenturyStart;

    /**
     * See documentation for systemDefaultCenturyStart.
     */
    static int32_t          fgSystemDefaultCenturyStartYear;

    /**
     * Default value that indicates the defaultCenturyStartYear is unitialized
     */
    static const int32_t    fgSystemDefaultCenturyYear;

    /**
     * start of default century, as a date
     */
    static const UDate        fgSystemDefaultCentury;

    /**
     * Returns the beginning date of the 100-year window that dates 
     * with 2-digit years are considered to fall within.
     */
    UDate         internalGetDefaultCenturyStart(void) const;

    /**
     * Returns the first year of the 100-year window that dates with 
     * 2-digit years are considered to fall within.
     */
    int32_t          internalGetDefaultCenturyStartYear(void) const;

    /**
     * Initializes the 100-year window that dates with 2-digit years
     * are considered to fall within so that its start date is 80 years
     * before the current time.
     */
    static void  initializeSystemDefaultCentury(void);
};

inline UClassID
BuddhistCalendar::getStaticClassID(void)
{ return (UClassID)&fgClassID; }

inline UClassID
BuddhistCalendar::getDynamicClassID(void) const
{ return BuddhistCalendar::getStaticClassID(); }


U_NAMESPACE_END

#endif /* #if !UCONFIG_NO_FORMATTING */

#endif // _GREGOCAL
//eof

