#pragma once

#include "chart_candle.hh"
#include <utility>
#include <vector>
#include <map>
#include <string>

/**
 * @brief Data structure for forex order
 *
 * Different members are used for different
 * purposes in different situations.
 */
struct Order {
public:
    Order();

    static Order send(
        const std::string& type, double lots, int slippage,
        int stopLossPt, int takeProfitPt);

    static Order modify(int ticket, int stopLossPt, int takeProfitPt);
    static Order close(int ticket, double lots, int slippage);

public:
    std::string command;
    std::string event;
    std::string error;
    int magic;
    int ticket;
    std::string type;
    double openPrice;
    double closePrice;
    double lots;
    int slippage;
    double stopLoss;
    double takeProfit;
    int stopLossPt;
    int takeProfitPt;
    double profit;
    QDateTime time;
    QDateTime openTime;
};

/// Vector of doubles
using Vector = std::vector<double>;

/// Pair of QDateTime and double
using TimeDouble = std::pair<QDateTime, double>;

/// Pair of QDateTime and vector of doubles
using TimeVector = std::pair<QDateTime, Vector>;

/// Map of vector of QDateTime and double pair with string key
using DoubleVectorMap = std::map<std::string, std::vector<TimeDouble>>;

/// Map of vector of QDateTime and double vector pair with string key
using DoubleTableMap = std::map<std::string, std::vector<TimeVector>>;

/// Vector of chart candles
using CandleVector = std::vector<ChartCandle>;

/// Vector of orders
using OrderVector = std::vector<Order>;

/// Vector of pairs of string and int
using StringIntVector = std::vector<std::pair<std::string, int>>;

/**
 * @brief Class for request of trading data
 *
 * Used by trading strategy to ask for required
 * data such as price data or indicator values.
 */
class DataRequest {
public:
    void append(const std::string& name, int count = 2);
    StringIntVector::const_iterator begin() const;
    StringIntVector::const_iterator end() const;
    const std::pair<std::string, int>& operator[](int index);
    int count() const;
    void clear();

private:
    StringIntVector data_;
};

/**
 * @brief Structure for trading data
 *
 * Used by trading strategy to make a decision and in client
 * interface to store data response before it is sent.
 */
class TradeData {
public:
    void addOrder(const Order& order);
    void addCandle(const ChartCandle& candle);

    void addValue(
        const std::string& name, const QDateTime& datetime, double value);

    void addVector(
        const std::string& name, const QDateTime& datetime,
        const Vector& vector);

    int orderCount() const;
    int candleCount() const;
    int valueCount(const std::string& name) const;
    int vectorCount(const std::string& name) const;

    DoubleVectorMap::const_iterator valuesBegin() const;
    DoubleVectorMap::const_iterator valuesEnd() const;
    DoubleTableMap::const_iterator vectorsBegin() const;
    DoubleTableMap::const_iterator vectorsEnd() const;

    bool hasOrder() const;
    bool hasCandle() const;
    bool hasValue(const std::string& name) const;
    bool hasVector(const std::string& name) const;

    const Order& order(int index) const;
    const ChartCandle& candle(int index) const;

    const TimeDouble& value(const std::string& name, int index) const;
    const TimeVector& vector(const std::string& name, int index) const;

    bool validate(const DataRequest& request);
    void clear();

private:
    OrderVector orders_;
    CandleVector candles_;
    DoubleVectorMap values_;
    DoubleTableMap vectors_;
};
