#include "chart_candle.hh"
#include <fstream>
#include <QStringList>
#include <QDebug>

namespace {

constexpr char dateFormat[] = "dd.MM.yyyy hh:mm";
constexpr char numberFormat = 'f';
constexpr int numberPrecision = 6;

inline void falseIfFalse(const bool input, bool &output)
{
   output = !input ? false : output;
}

} // namespace

ChartCandle::ChartCandle() :
    dateTime_(QDateTime()),
    open_(0),
    high_(0),
    low_(0),
    close_(0),
    volume_(0),
    valid_(true)
{}

void ChartCandle::dateTime(QDateTime time)
{
    dateTime_ = time;
}

QDateTime ChartCandle::dateTime() const
{
    return dateTime_;
}

long ChartCandle::volume() const
{
    return volume_;
}

void ChartCandle::volume(long volumeVal)
{
    volume_ = volumeVal;
}

void ChartCandle::set(
    double openVal, double highVal, double lowVal,
    double closeVal, long volumeVal)
{
    open_ = openVal;
    high_ = highVal;
    low_ = lowVal;
    close_ = closeVal;
    volume_ = volumeVal;
}

double ChartCandle::open() const
{
    return open_;
}

double ChartCandle::high() const
{
    return high_;
}

double ChartCandle::low() const
{
    return low_;
}

double ChartCandle::close() const
{
    return close_;
}

double ChartCandle::typical() const
{
    return (high_ + low_ + close_) / 3.0;
}

void ChartCandle::open(double openVal)
{
    open_ = openVal;
}

void ChartCandle::high(double highVal)
{
    high_ = highVal;
}

void ChartCandle::low(double lowVal)
{
    low_ = lowVal;
}

void ChartCandle::close(double closeVal)
{
    close_ = closeVal;
}

bool ChartCandle::isValid() const
{
    return valid_;
}

bool ChartCandle::isEmpty() const
{
    return !valid_ || (dateTime_ == QDateTime());
}

bool ChartCandle::operator==(const ChartCandle &candle)
{
    return dateTime_ == candle.dateTime_ && open_ == candle.open_ &&
           high_ == candle.high_ && low_ == candle.low_ &&
           close_ == candle.close_ && volume_ == candle.volume_ &&
           valid_ == candle.valid_;
}

ChartCandle ChartCandle::fromString(const QString &str)
{
    ChartCandle candle;

    if (str.isEmpty())
        return candle;

    QStringList column = str.split(',');

    if (column.length() != 6) {
        candle.valid_ = false;
        return candle;
    }

    bool ok = false;
    candle.valid_ = true;

    candle.dateTime_ = QDateTime::fromString(column[0], dateFormat);
    falseIfFalse(candle.dateTime_.isValid(), candle.valid_);

    candle.open_ = column[1].toDouble(&ok);
    falseIfFalse(ok, candle.valid_);

    candle.high_ = column[2].toDouble(&ok);
    falseIfFalse(ok, candle.valid_);

    candle.low_ = column[3].toDouble(&ok);
    falseIfFalse(ok, candle.valid_);

    candle.close_ = column[4].toDouble(&ok);
    falseIfFalse(ok, candle.valid_);

    candle.volume_ = column[5].toInt(&ok);
    falseIfFalse(ok, candle.valid_);

    return candle;
}

QString ChartCandle::toString() const
{
    QString str;

    if (!isValid() || isEmpty())
        return str;

    str = dateTime_.toString(dateFormat) + ", ";
    str += QString::number(open_, numberFormat, numberPrecision) + ", ";
    str += QString::number(high_, numberFormat, numberPrecision) + ", ";
    str += QString::number(low_, numberFormat, numberPrecision) + ", ";
    str += QString::number(close_, numberFormat, numberPrecision) + ", ";
    str += QString::number(volume_);

    return str;
}

bool load(const std::string& filename, std::vector<ChartCandle>& candles)
{
    candles.clear();
    std::ifstream stream(filename);

    if (!stream.is_open())
        return false;

    while (!stream.eof()) {
        std::string line;
        std::getline(stream, line);

        if (line.empty())
            continue;

        auto candle = ChartCandle::fromString(
            QString::fromStdString(line));

        if (candle.isValid())
            candles.push_back(candle);
        else
            return false;
    }

    return true;
}
