#ifndef CALCULATE_PRICE_H
#define CALCULATE_PRICE_H

#include <time.h>
#include <inttypes.h>

#include <QString>

#ifdef WIN32
#ifdef CALCULATE_LIBRARY_EXPORTS
#define CALCULATE_LIBRARY_API __declspec(dllexport)
#else
#define CALCULATE_LIBRARY_API __declspec(dllimport)
#endif
#else
#define CALCULATE_LIBRARY_API
#endif

class Configuration;

typedef Configuration parking_tariff_t;

#ifdef __cplusplus
extern "C" {
#endif

struct CALCULATE_LIBRARY_API price_t {
    uint32_t units;
    double netto;
    double brutto;
    double vat_percentage;
    double vat;
};

struct CALCULATE_LIBRARY_API CalcState {
    enum class State : uint8_t {
        SUCCESS,
        ERROR_PARSING_ZONE_NR,
        ERROR_LOADING_TARIFF,
        ERROR_PARSING_TARIFF,
        NEGATIVE_PARING_TIME,
        INVALID_START_DATE,
        WRONG_PARAM_VALUES,
        ABOVE_MAX_PARKING_TIME,
        BELOW_MIN_PARKING_TIME,
        BELOW_MIN_PARKING_PRICE,
        OVERPAID
    };

    State m_status;
    QString m_desc;

    explicit CalcState() : m_status(State::SUCCESS), m_desc("") {}

    explicit operator bool() const noexcept {
        return (m_status == State::SUCCESS);
    }

    explicit operator QString () const noexcept {
        QString s;
        switch (m_status) {
        case State::SUCCESS:
            s = "SUCCESS";
            break;
        case State::ERROR_PARSING_ZONE_NR:
            s = "ERROR_PARSING_ZONE_NR";
            break;
        case State::ERROR_LOADING_TARIFF:
            s = "ERROR_LOADING_TARIFF";
            break;
        case State::ERROR_PARSING_TARIFF:
            s = "ERROR_PARSING_TARIFF";
            break;
        case State::NEGATIVE_PARING_TIME:
            s = "NEGATIVE_PARKING_TIME";
            break;
        case State::ABOVE_MAX_PARKING_TIME:
            s = "ABOVE_MAX_PARKING_TIME";
            break;
        case State::WRONG_PARAM_VALUES:
            s = "WRONG_PARAM_VALUES";
            break;
        case State::BELOW_MIN_PARKING_TIME:
            s = "BELOW_MIN_PARKING_TIME";
            break;
        case State::BELOW_MIN_PARKING_PRICE:
            s = "BELOW_MIN_PARKING_PRICE";
            break;
        case State::OVERPAID:
            s = "OVERPAID";
            break;
        case State::INVALID_START_DATE:
            s = "INVALID_START_DATE";
            break;
        }
        return s + ":" + m_desc;
    }

    CalcState &set(State s) { m_status = s; return *this; }
    CalcState &setDesc(QString s) { m_desc = s; return *this; }
};

CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
                                            char const *config_file);
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
int CALCULATE_LIBRARY_API get_zone_nr();

CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
                                            parking_tariff_t *tariff,
                                            time_t start_parking_time,
                                            time_t end_parking_time,
                                            struct price_t *price);

CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
                                            parking_tariff_t *tariff,
                                            time_t start_parking_time,
                                            double cost,
                                            QString &duration);
#ifdef __cplusplus
} // extern "C"
#endif

#endif // CALCULATE_PRICE_H