#pragma once

#include "util/TimeUnit.h"
#include "util/AgObject.h"
#include <map>
#include <list>
#include <string>
#include <stdint.h>
#include <boost/date_time/posix_time/posix_time.hpp>

class TimeHelper
{

private:
    TimeHelper();
    TimeHelper(TimeHelper const&);
    void operator=(TimeHelper const&);
    virtual ~TimeHelper();

    TimeUnit* MILLISECOND_UNIT;
    TimeUnit* SECOND_UNIT;
    TimeUnit* MINUTE_UNIT;
    TimeUnit* HOUR_UNIT;
    TimeUnit* DAY_UNIT;
    TimeUnit* WEEK_UNIT;
    TimeUnit* MONTH_UNIT;
    TimeUnit* QUARTER_UNIT;
    TimeUnit* YEAR_UNIT;

    std::map<int, AgString> SELECTION_VALUES;
    std::list<TimeUnit*> UNITS;
    std::map<AgString, TimeUnit*>  NAMED_UNITS;

    boost::posix_time::time_facet* facet;
    std::stringstream stream;

public:

    static uint64_t SECOND_IN_MS() { return 1000; }
    static uint64_t MINUTE_IN_MS() { return SECOND_IN_MS() * 60; }
    static uint64_t HOUR_IN_MS() { return MINUTE_IN_MS() * 60; }
    static uint64_t DAY_IN_MS() { return HOUR_IN_MS() * 24; }
    static uint64_t WEEK_IN_MS() { return DAY_IN_MS() * 7; }
    static uint64_t MONTH_IN_MS() { return DAY_IN_MS() * 30; }
    static uint64_t QUARTER_IN_MS() { return DAY_IN_MS() * 91; }
    static uint64_t YEAR_IN_MS() { return DAY_IN_MS() * 365; }
    static uint64_t MINUTE_IN_SECONDS() { return 60; }
    static uint64_t HOUR_IN_SECONDS() { return MINUTE_IN_SECONDS() * 60; }
    static uint64_t DAY_IN_SECONDS() { return HOUR_IN_SECONDS() * 24; }
    static uint64_t WEEK_IN_SECONDS() { return DAY_IN_SECONDS() * 7; }
    static uint64_t MONTH_IN_SECONDS() { return DAY_IN_SECONDS() * 30; }
    static uint64_t QUARTER_IN_SECONDS() { return DAY_IN_SECONDS() * 91; }
    static uint64_t YEAR_IN_SECONDS() { return DAY_IN_SECONDS() * 365; }
    static int MILLISECOND() { return 0; }
    static int SECOND() { return 1; }
    static int MINUTE() { return 2; }
    static int HOUR() { return 3; }
    static int DAY() { return 4; }
    static int WEEK() { return 5; }
    static int MONTH() { return 6; }
    static int QUARTER() { return 7; }
    static int YEAR() { return 8; }

    static AgString NAME_MILLISECOND() { return "millisecond"; }
    static AgString NAME_MS() { return "ms"; }
    static AgString NAME_SECOND() { return "second"; }
    static AgString NAME_SEC() { return "sec"; }
    static AgString NAME_S() { return "s"; }
    static AgString NAME_MINUTE() { return "minute"; }
    static AgString NAME_MIN() { return "min"; }
    static AgString NAME_M() { return "m"; }
    static AgString NAME_HOUR() { return "hour"; }
    static AgString NAME_HR() { return "hr"; }
    static AgString NAME_H() { return "h"; }
    static AgString NAME_DAY() { return "day"; }
    static AgString NAME_D() { return "d"; }
    static AgString NAME_WEEK() { return "week"; }
    static AgString NAME_W() { return "w"; }
    static AgString NAME_MONTH() { return "month"; }
    static AgString NAME_YEAR() { return "year"; }
    static AgString NAME_Y() { return "y"; }

    enum { CALENDAR_NULL, CALENDAR_MILLISECOND, CALENDAR_SECOND, CALENDAR_MINUTE, CALENDAR_HOUR,
           CALENDAR_DAY_OF_MONTH, CALENDAR_WEEK_OF_YEAR, CALENDAR_MONTH, CALENDAR_YEAR };

    static TimeHelper& getInstance()
    {
        static TimeHelper instance;
        return instance;
    }

    std::map<int, AgString> getSelectionValues();
    std::list<TimeUnit*> getUnits();

    AgString getUnitDescription(int unit);
    AgString getUnitDescriptionPlural(int unit);
    TimeUnit* getTimeUnit(int unit);
    uint64_t convertToMillis(uint64_t period, int unit);
    std::string convertTimestampToString(boost::posix_time::ptime  time);
};
