#include "TimeHelper.h"
#include "Cres.h"
#include "AggreGateException.h"

TimeHelper::TimeHelper(void)
{
    MILLISECOND_UNIT = new TimeUnit(MILLISECOND(), 1, Cres::get()->getString("tuMilliseconds"), CALENDAR_MILLISECOND, false);
    SECOND_UNIT      = new TimeUnit(SECOND(), SECOND_IN_MS(), Cres::get()->getString("tuSeconds"), CALENDAR_SECOND, false);
    MINUTE_UNIT      = new TimeUnit(MINUTE(), MINUTE_IN_MS(), Cres::get()->getString("tuMinutes"), CALENDAR_MINUTE, false);
    HOUR_UNIT        = new TimeUnit(HOUR(), HOUR_IN_MS(), Cres::get()->getString("tuHours"), CALENDAR_HOUR, false);
    DAY_UNIT         = new TimeUnit(DAY(), DAY_IN_MS(), Cres::get()->getString("tuDays"), CALENDAR_DAY_OF_MONTH, false);
    WEEK_UNIT        = new TimeUnit(WEEK(), WEEK_IN_MS(), Cres::get()->getString("tuWeeks"), CALENDAR_WEEK_OF_YEAR, true);
    MONTH_UNIT       = new TimeUnit(MONTH(), MONTH_IN_MS(), Cres::get()->getString("tuMonths"), CALENDAR_MONTH, false);
    QUARTER_UNIT     = new TimeUnit(QUARTER(), QUARTER_IN_MS(), Cres::get()->getString("tuQuarters"), CALENDAR_NULL, true);
    YEAR_UNIT        = new TimeUnit(YEAR(), YEAR_IN_MS(), Cres::get()->getString("tuYears"), CALENDAR_YEAR, false);

    SELECTION_VALUES.insert(std::make_pair(MILLISECOND(), Cres::get()->getString("tuMilliseconds")));
    SELECTION_VALUES.insert(std::make_pair(SECOND(), Cres::get()->getString("tuSeconds")));
    SELECTION_VALUES.insert(std::make_pair(MINUTE(), Cres::get()->getString("tuMinutes")));
    SELECTION_VALUES.insert(std::make_pair(HOUR(), Cres::get()->getString("tuHours")));
    SELECTION_VALUES.insert(std::make_pair(DAY(), Cres::get()->getString("tuDays")));
    SELECTION_VALUES.insert(std::make_pair(WEEK(), Cres::get()->getString("tuWeeks")));
    SELECTION_VALUES.insert(std::make_pair(MONTH(), Cres::get()->getString("tuMonths")));
    SELECTION_VALUES.insert(std::make_pair(QUARTER(), Cres::get()->getString("tuQuarters")));
    SELECTION_VALUES.insert(std::make_pair(YEAR(), Cres::get()->getString("tuYears")));

    UNITS.push_back(MILLISECOND_UNIT);
    UNITS.push_back(SECOND_UNIT);
    UNITS.push_back(MINUTE_UNIT);
    UNITS.push_back(HOUR_UNIT);
    UNITS.push_back(DAY_UNIT);
    UNITS.push_back(WEEK_UNIT);
    UNITS.push_back(MONTH_UNIT);
    UNITS.push_back(QUARTER_UNIT);
    UNITS.push_back(YEAR_UNIT);

    NAMED_UNITS.insert(std::make_pair(NAME_MILLISECOND(), MILLISECOND_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_MS(), MILLISECOND_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_SECOND(), SECOND_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_SEC(), SECOND_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_S(), SECOND_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_MINUTE(), MINUTE_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_MIN(), MINUTE_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_M(), MINUTE_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_HOUR(), HOUR_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_HR(), HOUR_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_H(), HOUR_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_DAY(), DAY_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_D(), DAY_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_WEEK(), WEEK_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_W(), WEEK_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_MONTH(), MONTH_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_YEAR(), YEAR_UNIT));
    NAMED_UNITS.insert(std::make_pair(NAME_Y(), YEAR_UNIT));

    facet = new boost::posix_time::time_facet();
    facet->format("%Y-%m-%d %H:%M:%S.%f");
    stream.imbue(std::locale(std::locale::classic(), facet));
}

TimeHelper::~TimeHelper()
{
    delete MILLISECOND_UNIT;
    delete SECOND_UNIT;
    delete MINUTE_UNIT;
    delete HOUR_UNIT;
    delete DAY_UNIT;
    delete WEEK_UNIT;
    delete MONTH_UNIT;
    delete QUARTER_UNIT;
    delete YEAR_UNIT;
}


std::map<int,AgString> TimeHelper::getSelectionValues()
{
    return SELECTION_VALUES;
}

std::list<TimeUnit*> TimeHelper::getUnits()
{
    return UNITS;
}

AgString TimeHelper::getUnitDescription(int unit)
{
    std::map<int, AgString>::iterator it = SELECTION_VALUES.find(unit);
    if (it == SELECTION_VALUES.end())
    {
        throw AggreGateException("Incorrect unit (TimeHelper::getUnitDescription)");
    }
    else
    {
        return SELECTION_VALUES[unit];
    }
}

AgString TimeHelper::getUnitDescriptionPlural(int unit)
{
    std::map<int, AgString>::iterator it = SELECTION_VALUES.find(unit);
    if (it == SELECTION_VALUES.end())
    {
        throw AggreGateException("Incorrect unit  (TimeHelper::getUnitDescriptionPlural)");
    }
    else
    {
        return getTimeUnit(unit)->getDescription();
    }
}

TimeUnit* TimeHelper::getTimeUnit(int unit)
{
    for (std::list<TimeUnit*>::iterator it = UNITS.begin(); it != UNITS.end(); ++it)
    {
        if ((*it)->getUnit() == unit)
        {
            return *it;
        }
    }

    throw AggreGateException("Incorrect unit description (TimeHelper::getUnitDescriptionPlural)");
    return 0;
}

uint64_t TimeHelper::convertToMillis(uint64_t period, int unit)
{
    switch (unit)
    {
        case 0:
            return period;
        case 1:
            return period * SECOND_IN_MS();
        case 2:
            return period * MINUTE_IN_MS();
        case 3:
            return period * HOUR_IN_MS();
        case 4:
            return period * DAY_IN_MS();
        case 5:
            return period * WEEK_IN_MS();
        case 6:
            return period * MONTH_IN_MS();
        case 7:
            return period * QUARTER_IN_MS();
        case 8:
            return period * YEAR_IN_MS();
        default:
            throw AggreGateException("Unknown time unit (TimeHelper::convertToMillis)");
    }
    return 0;
}

std::string TimeHelper::convertTimestampToString(boost::posix_time::ptime time)
{
    stream << time;
    std::string res = stream.str();
    stream.str(std::string());
    return res.substr(0, res.length() - 3);
}


