#include "timeLineItem.h"
#include <QPainter>

namespace TimeLine
{

class TimeLineItemPrivate
{
public:
    TimeLineItemPrivate();

    QRect        m_rect;
    QRect        m_titleRect;
    QColor       m_lineColor;
    TimeUnit     m_curTimeUnit;
    QDateTime    m_curTime;
    QDateTime    m_rightTime; //当前时间右边第一个需要输出展示的时间点
    int          m_curTimePos; //当前时间所在的位置(x值)，默认在中间(=0)
    int          m_rightTimePos;
    int          m_scaleSize; //时间刻度大小，单位为像素
    int          m_scaleFactor; //缩放倍数

    bool         m_leftMouseIsDown; //鼠标左键是否按下
    QPointF      m_mouseDownPoint; //鼠标左键按下的坐标
    QDateTime    m_mouseDownTime; //鼠标左键是按下坐标对应的时间

    DateTimeWidgetState m_curState;
};
TimeLineItemPrivate::TimeLineItemPrivate()
{
    m_lineColor = Qt::white;
    m_curTimeUnit = TU_Minute_1;
    m_curTime = QDateTime::currentDateTime();/*QDateTime::fromString("2024-12-10 20:15:00", "yyyy-MM-dd hh:mm:ss");*/
    m_rightTime = m_curTime;
    m_curTimePos = 0;
    m_rightTimePos = 0;
    m_curState = realTime;
    m_scaleSize = 100;
    m_scaleFactor = (int)m_curTimeUnit;
}

TimeLineItem::TimeLineItem() :
    d_ptr(new TimeLine::TimeLineItemPrivate)
{

}

TimeLineItem::~TimeLineItem()
{
    delete d_ptr;
}

QRectF TimeLineItem::boundingRect() const
{
    //return QRectF(-d_ptr->m_rect.width() / 2, -d_ptr->m_rect.height() / 2, d_ptr->m_rect.width(), d_ptr->m_rect.height());
    return d_ptr->m_rect;
}
void TimeLineItem::updateBoundingRect(const QRect& r)
{
    d_ptr->m_rect = QRect(-r.width() / 2, -r.height() / 2, r.width(), r.height());
    d_ptr->m_titleRect = QRect(-r.width() / 2, -r.height() / 2, r.width(), 35);
    d_ptr->m_curTimePos = d_ptr->m_rect.right() - 80;
}

void TimeLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(widget);
    //QRect rect = boundingRect().toRect();
    QPen pen = painter->pen();
    QBrush brush = painter->brush();
    QFont font = painter->font();
    QString strCurState = "";
    //绘制title，包含当前日期显示、状态显示，不同状态对应不同颜色
    if(d_ptr->m_curState == realTime)
    {
        brush.setColor(QColor(39, 102, 59));
        brush.setStyle(Qt::SolidPattern);
        strCurState = QString::fromWCharArray(L"实时数据");
    }
    else
    {
        brush.setColor(QColor(46, 53, 63));
        brush.setStyle(Qt::SolidPattern);
        strCurState = QString::fromWCharArray(L"历史数据");
    }
    QRect titleRect = d_ptr->m_titleRect;
    painter->setBrush(brush);
    painter->drawRect(titleRect);
    //tiltle中的当前日期
    pen.setColor(d_ptr->m_lineColor);
    font.setFamily(QString::fromWCharArray(L"微软雅黑"));
    font.setPointSize(10);
    font.setBold(true);
    painter->setPen(pen);
    painter->setFont(font);
    QFontMetrics metrics(font);
    QString strCurTime = d_ptr->m_curTime.toString("yyyy-MM-dd");
    QRect textRect = metrics.boundingRect(strCurTime);
    painter->drawText(titleRect.x() + 10, titleRect.y() + (titleRect.height() - textRect.height()) * 0.5 + textRect.height() - 5, strCurTime);
    //tiltle中的当前状态
    textRect = metrics.boundingRect(strCurState);
    painter->drawText(titleRect.x() + (titleRect.width() - textRect.width()) * 0.5, titleRect.y() + (titleRect.height() - textRect.height()) * 0.5 + textRect.height() - 5, strCurState);
    //刻度线
    drawScaleLine(painter);
    //当前时间
    painter->drawLine(d_ptr->m_curTimePos, d_ptr->m_titleRect.bottom() + 2, d_ptr->m_curTimePos, boundingRect().bottom());
}

void TimeLineItem::drawScaleLine(QPainter* p)
{
    QPen pen = p->pen();
    pen.setWidth(2);
    p->setPen(pen);

    QRect rect = boundingRect().toRect();
    d_ptr->m_rightTime = calculateRightTime();
    d_ptr->m_rightTimePos = calculateRightTimePos();

    int x_Right = d_ptr->m_rightTimePos;
    int x_Left = x_Right - d_ptr->m_scaleSize;
    while(1)
    {
        if(x_Right > rect.width() / 2 + d_ptr->m_scaleSize * 2)
            break;

        p->drawLine(x_Right, d_ptr->m_titleRect.bottom(), x_Right, d_ptr->m_titleRect.bottom() - 5);
        drawTimeText(p, x_Right);
        x_Right += d_ptr->m_scaleSize;
    }
    while(1)
    {
        if(x_Left < -rect.width() / 2 - d_ptr->m_scaleSize * 2)
            break;

        p->drawLine(x_Left, d_ptr->m_titleRect.bottom(), x_Left, d_ptr->m_titleRect.bottom() - 5);
        drawTimeText(p, x_Left);
        x_Left -= d_ptr->m_scaleSize;
    }
}
void TimeLineItem::drawTimeText(QPainter* p, int x)
{
    QDateTime time = getTime(x);
    QString text = "";
    QString text1 = "";
    switch(d_ptr->m_curTimeUnit)
    {
    case TU_Year:
    {
        text = time.toString("yyyy");
        break;
    }
    case TU_Month:
    {
        int month = time.date().month();
        if (month == 1)
            text1 = time.toString("yyyy");
        text = time.toString("MM");
        break;
    }
    case TU_Day:
    {
        int day = time.date().day();
        if (day == 1)
            text1 = time.toString("yyyy/MM");
        text = time.toString("MM/dd");
        break;
    }
    case TU_Hour:
    {
        int hour = time.time().hour();
        if (hour == 0)
            text1 = time.toString("MM/dd");
        text = time.toString("hh:mm");
        break;
    }
    case TU_Minute_30:
    case TU_Minute_20:
    case TU_Minute_15:
    case TU_Minute_10:
    case TU_Minute_5:
    case TU_Minute_3:
    case TU_Minute_1:
    {
        int hour = time.time().hour();
        if (hour == 0)
            text1 = time.toString("MM/dd");
        text = time.toString("hh:mm");
        break;
    }
    case TU_Second_30:
    case TU_Second_10:
    case TU_Second_1:
    {
        // int minute = time.time().minute();
        // if(minute == 0)
        //     text1 = time.toString("MM-dd hh:mm");
        text = time.toString("hh:mm:ss");
        break;
    }
    case TU_MSecond_500:
    case TU_MSecond_100:
    case TU_MSecond_50:
    case TU_MSecond_10:
    {
        // int minute = time.time().minute();
        // if(minute == 0)
        //     text1 = time.toString("MM-dd hh:mm");
        text = time.toString("hh:mm:ss.zzz");
        break;
    }
    default:
        break;
    }

    QFont font = p->font();
    // font.setFamily(QString::fromWCharArray(L"微软雅黑"));
    // font.setPointSize(10);
    // font.setBold(true);
    // p->setFont(font);
    QFontMetrics metrics(font);
     if(!text.isEmpty())
    {
        QRect textRect = metrics.boundingRect(text);
        p->drawText(x - textRect.width() * 0.5, d_ptr->m_titleRect.bottom() + textRect.height(), text);
    }
    if(!text1.isEmpty())
    {
        QRect textRect = metrics.boundingRect(text1);
        p->drawText(x - textRect.width() * 0.5, d_ptr->m_titleRect.bottom() + textRect.height() * 2, text1);
    }
}

QDateTime TimeLineItem::calculateRightTime()
{
    //必须保证时间点在整点时刻上，例如20mRange，时刻点为20:00、20:20、20:40、21:00，3mRange，时刻点为20:00，20:03、20:06...20:57、21:00。
    //所以时间区间一定可以被所在但愿整除，比如不能出现7m的时间单元
    QDateTime dateTime;
    QString strDateTime = d_ptr->m_curTime.toString("yyyyMMddhhmmsszzz");;
    switch(d_ptr->m_curTimeUnit)
    {
    case TU_Year:
    {
        strDateTime = d_ptr->m_curTime.addYears(1).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(4) + "0101000000000";
        break;
    }
    case TU_Month:
    {
        strDateTime = d_ptr->m_curTime.addMonths(1).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(6) + "01000000000";
        break;
    }
    case TU_Day:
    {
        strDateTime = d_ptr->m_curTime.addDays(1).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(8) + "000000000";
        break;
    }
    case TU_Hour:
    {
        strDateTime = d_ptr->m_curTime.addSecs(60 * 60).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(10) + "0000000";
        break;
    }
    case TU_Minute_30:
    {
        strDateTime = d_ptr->m_curTime.addSecs(30 * 60).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(10) + "0000000";
        break;
    }
    case TU_Minute_20:
    {
        QString strBeginTime = strDateTime.left(10) + "0000000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(20 * 60);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
    }
    case TU_Minute_15:
    {
        QString strBeginTime = strDateTime.left(10) + "0000000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(15 * 60);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
        break;
    }
    case TU_Minute_10:
    {
        QString strBeginTime = strDateTime.left(10) + "0000000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(10 * 60);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
    }
    case TU_Minute_5:
    {
        QString strBeginTime = strDateTime.left(10) + "0000000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(5 * 60);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
    }
    case TU_Minute_3:
    {
        QString strBeginTime = strDateTime.left(10) + "0000000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(3 * 60);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
    }
    case TU_Minute_1:
    {
        strDateTime = d_ptr->m_curTime.addSecs(1 * 60).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(12) + "00000";
        break;
    }
    case TU_Second_30:
    {
        strDateTime = d_ptr->m_curTime.addSecs(30).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(12) + "00000";
        break;
    }
    case TU_Second_10:
    {
        QString strBeginTime = strDateTime.left(12) + "00000";
        dateTime = QDateTime::fromString(strBeginTime, "yyyyMMddhhmmsszzz");
        while(1)
        {
            dateTime = dateTime.addSecs(10);
            if(dateTime >= d_ptr->m_curTime)
                return dateTime;
        }
        break;
    }
    case TU_Second_1:
    {
        strDateTime = d_ptr->m_curTime.addSecs(1).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(14) + "000";
        break;
    }
    case TU_MSecond_500:
    {
        strDateTime = d_ptr->m_curTime.addMSecs(500).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(14) + "000";
        break;
    }
    case TU_MSecond_100:
    {
        strDateTime = d_ptr->m_curTime.addMSecs(100).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(15) + "00";
        break;
    }
    case TU_MSecond_50:
    {
        strDateTime = d_ptr->m_curTime.addMSecs(50).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(15) + "00";
        break;
    }
    case TU_MSecond_10:
    {
        strDateTime = d_ptr->m_curTime.addMSecs(10).toString("yyyyMMddhhmmsszzz");
        strDateTime = strDateTime.left(16) + "0";
        break;
    }
    default:
        break;
    }

    dateTime = QDateTime::fromString(strDateTime, "yyyyMMddhhmmsszzz");
    return dateTime;
}
int TimeLineItem::calculateRightTimePos()
{
    qint64 timeRange = d_ptr->m_rightTime.msecsTo(d_ptr->m_curTime); //右时刻晚于当前时刻，返回负值
    timeRange = -timeRange;
    qint64 scaleRange = 0;
    switch(d_ptr->m_curTimeUnit)
    {
    case TU_Year:
        scaleRange = d_ptr->m_curTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000;
        break;
    case TU_Month:
        scaleRange = d_ptr->m_curTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000;
        break;
    case TU_Day:
        scaleRange = 24 * 60 * 60 * 1000;
        break;
    case TU_Hour:
        scaleRange = 60 * 60 *1000;
        break;
    case TU_Minute_30:
        scaleRange = 30 * 60 *1000;
        break;
    case TU_Minute_20:
        scaleRange = 20 * 60 *1000;
        break;
    case TU_Minute_15:
        scaleRange = 15 * 60 *1000;
        break;
    case TU_Minute_10:
        scaleRange = 10 * 60 *1000;
        break;
    case TU_Minute_5:
        scaleRange = 5 * 60 *1000;
        break;
    case TU_Minute_3:
        scaleRange = 3 * 60 *1000;
        break;
    case TU_Minute_1:
        scaleRange = 60 * 1000;
        break;
    case TU_Second_30:
        scaleRange = 30 * 1000;
        break;
    case TU_Second_10:
        scaleRange = 10 * 1000;
        break;
    case TU_Second_1:
        scaleRange = 1 * 1000;
        break;
    case TU_MSecond_500:
        scaleRange = 500;
        break;
    case TU_MSecond_100:
        scaleRange = 100;
        break;
    case TU_MSecond_50:
        scaleRange = 50;
        break;
    case TU_MSecond_10:
        scaleRange = 10;
        break;
    default:
        break;
    }
    //qDebug() << timeRange << ", " << scaleRange;
    double dRatio = (double)timeRange / (double)scaleRange;
    //qDebug() <<  "leftTime:" << d_ptr->m_rightTime.toString("yyyy/MM/dd hh:mm:ss");
    return d_ptr->m_curTimePos + (d_ptr->m_scaleSize * dRatio);
}

QDateTime TimeLineItem::calculateTime(double dUnit)
{
    QDateTime dateTime;
    switch(d_ptr->m_curTimeUnit)
    {
    case TU_Year:
    {
        dateTime = d_ptr->m_rightTime.addYears((int)dUnit);//先计算年份
        dateTime = dateTime.addMSecs(dateTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000 * (dUnit - (int)dUnit)); //再计算时间
        break;
    }
    case TU_Month:
    {
        dateTime = d_ptr->m_rightTime.addMonths((int)dUnit);//先计算月份
        dateTime = dateTime.addMSecs(dateTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000 * (dUnit - (int)dUnit)); //再计算时间
        break;
    }
    case TU_Day:
        dateTime = d_ptr->m_rightTime.addMSecs(24 * 60 * 60 * 1000 * dUnit);
        break;
    case TU_Hour:
        dateTime = d_ptr->m_rightTime.addMSecs(60 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_30:
        dateTime = d_ptr->m_rightTime.addMSecs(30 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_20:
        dateTime = d_ptr->m_rightTime.addMSecs(20 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_15:
        dateTime = d_ptr->m_rightTime.addMSecs(15 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_10:
        dateTime = d_ptr->m_rightTime.addMSecs(10 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_5:
        dateTime = d_ptr->m_rightTime.addMSecs(5 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_3:
        dateTime = d_ptr->m_rightTime.addMSecs(3 * 60 * 1000 * dUnit);
        break;
    case TU_Minute_1:
        dateTime = d_ptr->m_rightTime.addMSecs(60 * 1000 * dUnit);
        break;
    case TU_Second_30:
        dateTime = d_ptr->m_rightTime.addMSecs(30 * 1000 * dUnit);
        break;
    case TU_Second_10:
        dateTime = d_ptr->m_rightTime.addMSecs(10 * 1000 * dUnit);
        break;
    case TU_Second_1:
        dateTime = d_ptr->m_rightTime.addMSecs(1000 * dUnit);
        break;
    case TU_MSecond_500:
        dateTime = d_ptr->m_rightTime.addMSecs(500 * dUnit);
        break;
    case TU_MSecond_100:
        dateTime = d_ptr->m_rightTime.addMSecs(100 * dUnit);
        break;
    case TU_MSecond_50:
        dateTime = d_ptr->m_rightTime.addMSecs(50 * dUnit);
        break;
    case TU_MSecond_10:
        dateTime = d_ptr->m_rightTime.addMSecs(10 * dUnit);
        break;
    default:
        break;
    }

    return dateTime;
}

QDateTime TimeLineItem::getTime(int x)
{
    double dUnit = (double)(x - d_ptr->m_rightTimePos) / (double)d_ptr->m_scaleSize;
    return calculateTime(dUnit);
}

qint64 TimeLineItem::getOffsetTimeValue(int x)
{
    double dUnit = (double)(x) / (double)d_ptr->m_scaleSize;
    //在极小的时间刻度下做一定的倍数放大，从而让拖拽更平滑
    switch(d_ptr->m_curTimeUnit)
    {
    case TU_MSecond_100:
        dUnit = dUnit * 2;
        break;
    case TU_MSecond_50:
        dUnit = dUnit * 5;
        break;
    case TU_MSecond_10:
    {
        if(dUnit < 0)
            dUnit = -0.1;
        else if(dUnit > 0)
            dUnit = 0.1;
        //dUnit = dUnit * 10;
    }
        break;
    default:
        break;
    }

    QDateTime dateTime = calculateTime(dUnit);
    //qDebug() << dUnit << " " << dateTime.toString("hh:mm:ss.zzz");
    qint64 value = d_ptr->m_rightTime.msecsTo(dateTime);
    return value;
}

void TimeLineItem::setLineColor(QColor color)
{
    d_ptr->m_lineColor = color;
}

void TimeLineItem::setScaleSize(int size)
{
    d_ptr->m_scaleSize = size;
}

void TimeLineItem::setState(DateTimeWidgetState state)
{
    d_ptr->m_curState = state;
}

void TimeLineItem::setTime(const QDateTime& time)
{
    if(time > QDateTime::currentDateTime())
        return;

    //qDebug() <<  "currTime:"  << time.toString("hh:mm:ss.zzz");
    d_ptr->m_curTime = time;
    prepareGeometryChange();
}
QDateTime TimeLineItem::time()
{
    return d_ptr->m_curTime;
}

void TimeLineItem::zoomIn()
{
    d_ptr->m_scaleFactor++;
    if(d_ptr->m_scaleFactor > (int)TU_MSecond_50)
        d_ptr->m_scaleFactor = (int)TU_MSecond_50;
    d_ptr->m_curTimeUnit = (TimeUnit)d_ptr->m_scaleFactor;

    prepareGeometryChange();
    //qDebug() << d_ptr->m_curTimeUnit;
}
void TimeLineItem::zoomOut()
{
    d_ptr->m_scaleFactor--;
    if(d_ptr->m_scaleFactor < 1)
        d_ptr->m_scaleFactor = 1;
    d_ptr->m_curTimeUnit = (TimeUnit)d_ptr->m_scaleFactor;

    prepareGeometryChange();
    //qDebug() << d_ptr->m_curTimeUnit;
}

void TimeLineItem::setTimeUnit(TimeUnit unit)
{
    d_ptr->m_curTimeUnit = unit;
}

TimeUnit TimeLineItem::timeUnit()
{
    return d_ptr->m_curTimeUnit;
}

} // namespace TimeLine
