/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009-2014 Alan Wright. All rights reserved.
// Distributable under the terms of either the Apache License (Version 2.0)
// or the GNU Lesser General Public License.
/////////////////////////////////////////////////////////////////////////////

#ifndef DATETOOLS_H
#define DATETOOLS_H

#include "LuceneObject.h"

namespace Lucene {

/// Provides support for converting dates to strings and vice-versa.  The strings are structured so that
/// lexicographic sorting orders them by date, which makes them suitable for use as field values and search
/// terms.
///
/// This class also helps you to limit the resolution of your dates.  Do not save dates with a finer resolution
/// than you really need, as then RangeQuery and PrefixQuery will require more memory and become slower.
///
/// Compared to {@link DateField} the strings generated by the methods in this class take slightly more space,
/// unless your selected resolution is set to Resolution.DAY or lower.
///
/// Another approach is {@link NumericUtils}, which provides a sortable binary representation (prefix encoded)
/// of numeric values, which date/time are.  For indexing a {@link Date} or {@link Calendar}, just get the unix
/// timestamp as long using {@link Date#getTime} or {@link Calendar#getTimeInMillis} and index this as a numeric
/// value with {@link NumericField} and use {@link NumericRangeQuery} to query it.
class LPPAPI DateTools : public LuceneObject {
public:
    virtual ~DateTools();

    LUCENE_CLASS(DateTools);

public:
    enum Resolution {
        RESOLUTION_NULL,
        RESOLUTION_YEAR,
        RESOLUTION_MONTH,
        RESOLUTION_DAY,
        RESOLUTION_HOUR,
        RESOLUTION_MINUTE,
        RESOLUTION_SECOND,
        RESOLUTION_MILLISECOND
    };

    enum DateOrder {
        DATEORDER_LOCALE,
        DATEORDER_YMD,
        DATEORDER_DMY,
        DATEORDER_MDY
    };

protected:
    static DateOrder dateOrder;

public:
    /// Converts a Date to a string suitable for indexing.
    /// @param date the date to be converted
    /// @param resolution the desired resolution
    /// @return a string in format yyyyMMddHHmmssSSS or shorter, depending on resolution; using GMT as timezone
    static String dateToString(const boost::posix_time::ptime& date, Resolution resolution);

    /// Converts a millisecond time to a string suitable for indexing.
    /// @param time the date expressed as milliseconds since January 1, 1970, 00:00:00 GMT
    /// @param resolution the desired resolution
    /// @return a string in format yyyyMMddHHmmssSSS or shorter, depending on resolution; using GMT as timezone
    static String timeToString(int64_t time, Resolution resolution);

    /// Converts a string produced by timeToString or dateToString back to a time, represented as the number of
    /// milliseconds since January 1, 1970, 00:00:00 GMT.
    /// @param dateString the date string to be converted
    /// @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
    static int64_t stringToTime(const String& dateString);

    /// Converts a string produced by timeToString or dateToString back to a time, represented as a ptime object.
    /// @param dateString the date string to be converted
    /// @return the parsed time as a ptime object
    static boost::posix_time::ptime stringToDate(const String& dateString);

    /// Limit a date's resolution. For example, the date 2004-09-21 13:50:11 will be changed to 2004-09-01 00:00:00
    /// when using Resolution.MONTH.
    /// @param resolution The desired resolution of the date to be returned
    /// @return the date with all values more precise than resolution set to 0 or 1
    static boost::posix_time::ptime round(const boost::posix_time::ptime& date, Resolution resolution);

    /// Limit a date's resolution. For example, the date 1095767411000 (which represents 2004-09-21 13:50:11) will
    /// be changed to 1093989600000 (2004-09-01 00:00:00) when using Resolution.MONTH.
    /// @param resolution The desired resolution of the date to be returned
    /// @return the date with all values more precise than resolution set to 0 or 1, expressed as milliseconds
    /// since January 1, 1970, 00:00:00 GMT
    static int64_t round(int64_t time, Resolution resolution);

    /// Allow overriding of date ordering.
    static void setDateOrder(DateTools::DateOrder order);

    /// Return date ordering based on given locale (or overridden in {@link #setDateOrder(DateTools::DateOrder)}).
    static DateTools::DateOrder getDateOrder(std::locale locale = std::locale());

    /// Parse a given date using locale date format
    /// @param dateString the date string to be converted
    /// @param locale the locale to use for parsing
    /// @return the parsed time as a ptime object
    static boost::posix_time::ptime parseDate(const String& dateString, std::locale locale = std::locale());
};

}

#endif
