#include "PvChart.h"
#include "TimeUtils.h"

///////////////////////////////////////////////////////////////////////////////////////////////////
/// === PvChartBar 

PvChartBar::PvChartBar(PARAM* p, int parentId, int x, int y, int w, int h)
    : PvObject(p)
{
    pvid_ = PvApp::label(p, parentId, x, y, w, h, "", "border: none; border-radius: 0px; background-color: transparent; color:white; font: normal 12px;");

    boxBar_.x = 40;
    boxBar_.y = 56;
    boxBar_.w = w - boxBar_.x * 2;
    boxBar_.h = h - boxBar_.y - 38;
    boxBar_.id = PvApp::label(p, pvid_, boxBar_.x, boxBar_.y, boxBar_.w+1, boxBar_.h+1, "", "border: none; background-color: transparent;");

    
    int hMargin = 5;
    {
        // 左侧X轴
        yAxisLeft_.widget = PvApp::label(p, pvid_, 0, 0, boxBar_.x, h, "", "");
        PvApp::label(p, yAxisLeft_.widget, boxBar_.x-1, boxBar_.y, 1, boxBar_.h, "", "border: 1px solid white;");
    }
    {
        yAxisRight_.widget = PvApp::label(p, pvid_, boxBar_.x + boxBar_.w, 0, boxBar_.x, h, "", "");
        PvApp::label(p, yAxisRight_.widget, 0, boxBar_.y, 1, boxBar_.h, "", "border: 1px solid white;");
    }

    yLabelLeft_ = PvApp::label(p, pvid_, 0, 0, boxBar_.x*2, boxBar_.y-10, "", "font: bold 14px; color: white;");
    pvSetAlignment(p, yLabelLeft_, AlignHCenter | AlignBottom);
    yLabelRight_ = PvApp::label(p, pvid_, boxBar_.w, 0, boxBar_.x*2, boxBar_.y-5, "", "font: bold 14px; color: white;");
    pvSetAlignment(p, yLabelRight_, AlignHCenter | AlignBottom);

    // Y轴分成5段
    setTickX(7);
    setTickY(5);
}

void PvChartBar::setTickX(int n)
{
    vecTickX_.resize(n);
    // 每一段的长度：
    int len = int(float(boxBar_.w)/float(n));
    int y = boxBar_.y + boxBar_.h;
    // X轴分成 n 段，共有 n 条刻度线
    for (int i = 0; i<n; ++i)
    {
        int x = boxBar_.x + float(boxBar_.w) * float(i)/float(n);
        PvApp::label(p, pvid_, x+len*0.5, y+5, 1, 10, "", "border: 1px solid white;");
        int id = PvApp::label(p, pvid_, x, y+12, len, 28, std::to_string(n-i+1), "font: normal 12px;");
        pvSetAlignment(p, id, AlignCenter);
        vecTickX_[i] = id;
    }
    PvApp::label(p, pvid_, boxBar_.x, y+5, boxBar_.w, 1, "", "border: 1px solid white;");
}

void PvChartBar::setTickY(int n)
{
    yAxisLeft_.vecTick_.resize(n+1);
    yAxisRight_.vecTick_.resize(n+1);

    // 每一段的长度：
    int len = int(float(boxBar_.h)/float(n));
    // 刻度文字label的高度
    int hLabel = 20;
    // 刻度线的长度
    int wLine = 8;
    // Y轴分成 n 段，共有 n+1 条刻度线
    for (int i = 0; i<=n; ++i)
    {
        // 刻度线的位置
        int y = boxBar_.y + float(boxBar_.h) * float(n-i)/float(n);
        {
            // 左侧刻度线
            PvApp::label(p, yAxisLeft_.widget, boxBar_.x-wLine, y, wLine, 1, "", "border: 1px solid white;");
            // 左侧刻度text
            int id = PvApp::label(p, yAxisLeft_.widget, 0, y-hLabel*0.5, boxBar_.x-wLine-3, hLabel, std::to_string(i), "");
            pvSetAlignment(p, id, AlignRight | AlignVCenter);
            yAxisLeft_.vecTick_[i] = id;
        }
        {
            // 右侧刻度线
            PvApp::label(p, yAxisRight_.widget, 0, y, wLine, 1, "", "border: 1px solid white;");
            // 右侧刻度text
            int id = PvApp::label(p, yAxisRight_.widget, 8+3, y-hLabel*0.5, boxBar_.x-wLine-3, hLabel, std::to_string(i), "");
            pvSetAlignment(p, id, AlignLeft | AlignVCenter);
            yAxisRight_.vecTick_[i] = id;
        }
        // Y轴的网格线
        PvApp::label(p, pvid_, boxBar_.x, y, boxBar_.w, 1, "", "border: none; border-top: 1px dashed white; background-color: rgb(80,80,80,0); color:white;");
    }
    setRangeY(0, n);
}

void PvChartBar::setRangeY(double vmin, double vmax)
{
    int n = yAxisLeft_.vecTick_.size();
    int step = std::ceil((vmax - vmin)/double(n-1));
    yLeftMin = vmin;
    yLeftMax = vmin + step * (n-1);
    for (int i = 0; i<n; ++i)
    {
        pvSetText(p, yAxisLeft_.vecTick_[i], std::to_string(int(yLeftMin + i* step)).c_str());
    }
}

void PvChartBar::setLabelYLeft(std::string name)
{
    if (yLabelLeft_ != PV_ID_NUL) { pvSetText(p, yLabelLeft_, name.c_str()); }

}
void PvChartBar::setLabelYRight(std::string name)
{
    if (yLabelRight_ != PV_ID_NUL) { pvSetText(p, yLabelRight_, name.c_str()); }
}

static std::vector<std::string> vecSeriesColor =
{
    "rgb(84, 112, 198);", "rgb(169, 223, 150);", "rgb(246, 220, 125);", "rgb(84, 112, 198);", "rgb(169, 223, 150);", "rgb(246, 220, 125);"
};

void PvChartBar::insertItem(std::string text)
{
    int index = vecItems_.size();
    int nItem = index+1;

    // 根据 X 轴的分段数量创建 bar
    int n = vecTickX_.size();
    // 每一段的绘制区域的长度，左右保留间距 5px, 计算每一个柱体的宽度
    int wBar = (int(float(boxBar_.w)/float(n)) - margin) / nItem;

    // 如果不是第一个序列项，需要重新计算前面序列的宽度
    for (int i = 0; i<index; ++i)
    {
        auto& bar = vecItems_[i].bar_;
        for (int pos = 0; pos<bar.size(); ++pos)
        {
            int h = 0; // bar 初始高度设置为0
            int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*i;
            int y = boxBar_.y + boxBar_.h -h;
            pvSetGeometry(p, bar[pos], x, y, wBar-5, h);
        }
    }

    BarItem barItem;
    barItem.name = text;
    int labelWidth = text.size()*12*0.4 + 18;
    barItem.idItem = PvApp::label(p, pvid_, itemLabelPos, 10, labelWidth, 18, text, "border: none; font: normal 12px; border-left: 18px solid " + vecSeriesColor[index]);
    itemLabelPos += (labelWidth + 10);
    barItem.bar_.resize(n);
    for (int pos = 0; pos<n; ++pos)
    {
        int h = 0; // bar 初始高度设置为0
        int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*index;
        int y = boxBar_.y + boxBar_.h -h;
        barItem.bar_[pos] = PvApp::label(p, pvid_, x, y, wBar-5, h, "", "border:0px; background-color: " + vecSeriesColor[index]);
    }
    vecItems_.push_back(barItem);
}


void PvChartBar::updateItem(int index, std::vector<std::pair<std::string, double>> vd)
{
    int nItems = vecItems_.size();
    if (index >= nItems)
    {
        return;
    }

    double vmax = yLeftMax;
    // 计算Y轴的范围， 获取数据中的最大值 （先不考虑最小值，最小值使用0）
    for (int i = 0; i<vd.size(); ++i)
    {
        auto& val = vd[i].second;
        if (val > vmax) { vmax = val; }
    }
    setRangeY(0, vmax);

    // 计算和重绘 bar 
    // Y轴差值
    double delta = double(yLeftMax - yLeftMin);
    auto& bar = vecItems_[index].bar_;

    // 根据 X 轴的分段数量创建 bar
    int n = vecTickX_.size();
    // 每一段的绘制区域的长度，左右保留间距 5px, 计算每一个柱体的宽度
    int wBar = (int(float(boxBar_.w)/float(n)) - margin) / vecItems_.size();

    for (int pos = 0; pos<bar.size(); ++pos)
    {
        if (pos < vd.size())
        {
            double v = vd[pos].second;
            int h = double(boxBar_.h)*v/delta;
            int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*index;
            int y = boxBar_.y + boxBar_.h -h;
            pvSetGeometry(p, bar[pos], x, y, wBar-5, h);
            // 设置X轴
            pvSetText(p, vecTickX_[pos], vd[pos].first.c_str());
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// === PvChartCurve
PvChartCurve::PvChartCurve(PARAM* p, int parent, int x, int y, int w, int h) : PvObject(p)
{
    rect.set(x, y, w, h);
    pvid_ = PvApp::label(p, parent, x, y, w, h, "", "border: none; border-radius: 0px; background-color: transparent;");
    plotId_ = PvApp::pvid(p);
    pvQwtPlotWidget(p, plotId_, pvid_, 100, 100);
    pvSetGeometry(p, plotId_, 10, 50, w - 20, h - 58);
    pvSetFont(p, plotId_, "微软雅黑", 16, 0, 0, 0, 0);

    // 设置标题
    //qpwSetTitle(p,id_,"30日曲线");
    // 设置背景色
    qpwSetCanvasBackground(p, plotId_, 64, 102, 124);
    // 设置横轴网格线 // NoPen, SolidLine, DashLine, DotLine, DashDotLine, DashDotDotLine, MPenStyle
    qpwSetGridMajPen(p, plotId_, 175, 196, 211, DotLine);

    qpwEnableOutline(p, plotId_, 1);
    qpwSetOutlinePen(p, plotId_, 255, 0, 0);

    // 设置坐标轴位置：左侧，底部  // yLeft,yRight,xBottom,xTop,axisCnt
    //qpwEnableAxis(p, plot_id_, yLeft);
    //qpwSetAxisTitle(p, plot_id_, yLeft, "Y轴说明");
    //qpwEnableAxis(p, plot_id_, yRight);
    //qpwSetAxisTitle(p, plot_id_, yRight, "Y轴说明");
    qpwEnableAxis(p, plotId_, xBottom);
    //qpwSetAxisTitle(p, id_, xBottom, "X轴说明");
    // 
    qpwSetAxisScale(p, plotId_, xBottom, 0, 15 * 60 * 7, 15 * 60);
    qpwSetAxisScale(p, plotId_, yLeft, 0, 100, 20);

    // 不知道效果
    qpwSetAxisOptions(p, plotId_, xBottom, Inverted); // pvNone = 0,IncludeRef = 1,Symmetric = 2,Floating = 4,Logarithmic = 8,InvertedInverted = 16

    //this->mark(p, 0, 10, 100);
    //this->mark(p, 1, 11, 100);

    yLabelLeft = PvApp::label(p, pvid_, 10, 24, 100, 20, "", "border:none;color:white;font-size:14px;font-weight:bold;");
    pvSetAlignment(p, yLabelLeft, AlignLeft);
    yLabelRight = PvApp::label(p, pvid_, rect.w - 100 - 10, 24, 100, 20, "", "border:none;color:white;font-size:14px;font-weight:bold;");
    pvSetAlignment(p, yLabelRight, AlignRight);
}

void PvChartCurve::setBackground(PARAM* p, int r, int g, int b)
{
    qpwSetCanvasBackground(p, plotId_, r, g, b);
    std::string QSS = "border: none; border-radius: 0px; background-color: " + PvColor(r, g, b).rgb() + ";";
    pvSetStyleSheet(p, pvid_, QSS.c_str());
}

void PvChartCurve::setLabelYLeft(std::string title, float min, float max, float step)
{
    yLeftMin_ = min;
    yLeftMax_ = max;
    yLeftStep_ = step;
    qpwSetAxisScale(p, plotId_, yLeft, min, max, step);
    qpwEnableAxis(p, plotId_, yLeft);
    //qpwSetAxisTitle(p, id_, yLeft, "Y轴说明");
    pvSetText(p, yLabelLeft, title.c_str());
}

void PvChartCurve::setLabelYRight(std::string title, float min, float max, float step)
{
    yRightMin_ = min;
    yRightMax_ = max;
    yRightStep_ = step;
    qpwSetAxisScale(p, plotId_, yRight, min, max, step);
    qpwEnableAxis(p, plotId_, yRight);
    //qpwSetAxisTitle(p, id_, yRight, "Y轴说明");
    
    pvSetText(p, yLabelRight, title.c_str());
}

void PvChartCurve::setXBottom(float min, float max, float step)
{
    qpwSetAxisScale(p, plotId_, xBottom, min, max, step);
    qpwReplot(p, plotId_);
}
void PvChartCurve::setXBottomFormat(std::string fmt)
{
    // 设置时间轴 "yyyy-MM-dd hh:mm:ss"
    qpwSetAxisScaleDraw(p, plotId_, xBottom, fmt.c_str());
}

static std::vector<PvColor> g_mapSeriesColor =
{
    PvColor(84, 112, 198), PvColor(169, 223, 150), PvColor(246, 220, 125), PvColor(84, 112, 198), PvColor(169, 223, 150), PvColor(246, 220, 125)
};

int PvChartCurve::insertItem(int pos, std::string name, int x, int y, int w)
{
    int index = vecItems_.size();

    auto& color = g_mapSeriesColor[index];
    PvApp::label(p, pvid_, x, y + 3, 14, 14, "", "background-color:" + color.rgb() + ";border-radius:7px;");
    PvApp::label(p, pvid_, x + 16, y, w - 16, 18, name, "color:white;font:normal 12px;border:0px solid #ff0000;");

    // 添加数据曲线
    qpwInsertCurve(p, plotId_, index, name.c_str());
    // 设置曲线颜色和类型 // NoPen,SolidLine,DashLine,DotLine,DashDotLine,DashDotDotLine,MPenStyle = 0x0f
    qpwSetCurvePen(p, plotId_, index, color.r, color.g, color.b, 2, SolidLine);
    //qpwSetCurveSymbol(p_, plot_id_, index, MarkerNone, col.r, col.g, col.b, WHITE, 4, 4);

    // 设置数据对应的Y轴（LEFT或RIGHT）
    qpwSetCurveYAxis(p, plotId_, index, (pos == 0) ? yLeft : yRight);

    CurveItem item;
    item.name = name;
    item.pos = pos;
    vecItems_.push_back(item);
    return index;
}

void PvChartCurve::updateItem(int index, const std::vector<std::pair<double, double>>& data)
{
    if (index >= vecItems_.size())
    {
        return;
    }
    auto& item = vecItems_[index];

    int64_t tCurrent = TimeUtils::now();
    int yMax = 0;
    int size = (int)data.size();
    std::vector<double> vx(size, 0);
    std::vector<double> vy(size, 0);
    for (size_t i = 0; i < size; ++i)
    {
        vx[i] = data[i].first;
        vy[i] = data[i].second;
        if (yMax < data[i].second) { yMax = data[i].second; }
    }
    this->reviseYMax(item.pos, yMax);
    qpwSetCurveData(p, plotId_, index, size, &vx[0], &vy[0]);
    qpwReplot(p, plotId_);
}


int64_t PvChartCurve::set_range_x_days(int n)
{
    this->setXBottomFormat("MM/dd");
    int step = 3600 * 24;
    auto t_end = TimeUtils::datetime2ts(TimeUtils::now_date() + " 08:00:00");
    auto t_start = t_end - step * (n - 1);
    this->setXBottom(t_start, t_end, step);
    return t_start;
}

int64_t PvChartCurve::set_range_x_day_by_hour(int n)
{
    this->setXBottomFormat("hh:mm");
    auto t_start = TimeUtils::datetime2ts(TimeUtils::now_date() + " 00:00:00");
    auto t_end = t_start + 86400;
    this->setXBottom(t_start, t_end, 86400 / n);
    return t_start;
}


void PvChartCurve::reviseYMax(int pos, double v)
{
    bool isLeft = (pos == 0);

    int min = (isLeft ? yLeftMin_ : yRightMin_);
    int max = (isLeft ? yLeftMax_ : yRightMax_);
    int step = (isLeft ? yLeftStep_ : yRightStep_);

    while (v > max)
    {
        max += (max-min);
        step *= 2;
    }
    qpwSetAxisScale(p, plotId_, yLeft, min, max, step);
    qpwSetAxisScale(p, plotId_, yRight, min, max, step);
}

void PvChartCurve::update_days_test(int n)
{
    int step = 3600*24/n;
    auto t_start = TimeUtils::datetime2ts(TimeUtils::now_date() + " 00:00:00");
    auto t_end = t_start+3600*24;

    std::vector<std::pair<double, double>> vd(n);
    double v = 100;
    for (int index = 0; index < vecItems_.size(); ++index)
    {
        for (int i = 0; i < n; ++i)
        {
            vd[i].first = static_cast<double>(t_start + i * step);
            vd[i].second = v += 2;// (v += (Utils::random(0, 10)-5));
        };
        this->updateItem(index, vd);
    }

}

void PvChartCurve::mark(PARAM* p, int index, float x, float y, std::string text)
{
    qpwInsertMarker(p, plotId_, 0);
    qpwSetMarkerPos(p, plotId_, index, x, y);
    //MarkerNone,MarkerEllipse,MarkerRect,MarkerDiamond,MarkerTriangle,MarkerDTriangle,MarkerUTriangle,MarkerLTriangle,MarkerRTriangle,MarkerCross,MarkerXCross,MarkerStyleCnt
    qpwSetMarkerSymbol(p, plotId_, 0, MarkerEllipse, RED, GREEN, 10, 10);
    qpwSetMarkerFont(p, plotId_, 0, "微软雅黑", 14, 1);
    qpwSetMarkerLabel(p, plotId_, 0, text.c_str());
}
