#include "BaseTableView.h"
#include "BaseItemDelegate.h"
#include "BaseHeaderView.h"

#include <DApplication>
#include <DPalette>
#include <DStyle>

#include <QDebug>
#include <QPainter>
#include <QPainterPath>
#include <QHeaderView>
#include <QHoverEvent>
#include <QMouseEvent>
#include <QScroller>
#include <QScrollBar>

#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    #include <DPaletteHelper>
#else
    #include <DApplicationHelper>
#endif

BaseTableView::BaseTableView(DWidget *parent)
        : DTreeView(parent)
{
    m_headerView = new BaseHeaderView(Qt::Horizontal, this);
    setHeader(m_headerView);
    m_headerView->setSectionsClickable(true);
    m_headerView->setStretchLastSection(true);
    m_headerView->setSortIndicatorShown(true);
    m_headerView->setDefaultAlignment(Qt::AlignLeft);
    m_headerView->setContextMenuPolicy(Qt::CustomContextMenu);
    m_headerView->setFocusPolicy(Qt::TabFocus);

    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setRootIsDecorated(false);
    setItemsExpandable(false);
    setFrameStyle(QFrame::NoFrame);
    viewport()->setAutoFillBackground(false);
    // if set to true, qt will draw item background for you, thats not what you want here!
    setAlternatingRowColors(false);
    setAllColumnsShowFocus(false);
    setFocusPolicy(Qt::TabFocus);
    setSelectionMode(QAbstractItemView::NoSelection);
    setTabOrder(m_headerView, this);

    // add treeview touch scroll support
    QScroller::grabGesture(viewport(), QScroller::TouchGesture);
    connect(m_headerView, &BaseHeaderView::checkAllChanged, [=] (Qt::CheckState checkState) {
        Q_EMIT checkAllChanged(checkState);
    });
}

void BaseTableView::setCheckAllState(Qt::CheckState checkState)
{
    if (m_headerView != nullptr) {
        m_headerView->setCheckAllState(checkState);
    }
}

void BaseTableView::paintEvent(QPaintEvent *event)
{
    QPainter painter(viewport());
    painter.save();
    painter.setRenderHints(QPainter::Antialiasing);
    painter.setOpacity(0.02);
    painter.setClipping(true);

    QWidget *wnd = DApplication::activeWindow();
    DPalette::ColorGroup cg;
    if (!wnd) {
        cg = DPalette::Inactive;
    } else {
        cg = DPalette::Active;
    }

    auto style = dynamic_cast<DStyle *>(DApplication::style());
#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    DPalette palette = DPaletteHelper::instance()->palette(this);
#else
    DPalette palette = DApplicationHelper::instance()->palette(this);
#endif

    QBrush bgBrush(palette.color(cg, DPalette::BrightText));

    QStyleOptionFrame option;
    initStyleOption(&option);
    int radius = style->pixelMetric(DStyle::PM_FrameRadius, &option);

    QRect rect = viewport()->rect();
    QRectF clipRect(rect.x(), rect.y() - rect.height(), rect.width(), rect.height() * 2);
    QRectF subRect(rect.x(), rect.y() - rect.height(), rect.width(), rect.height());
    QPainterPath clipPath, subPath;
    clipPath.addRoundedRect(clipRect, radius, radius);
    subPath.addRect(subRect);
    clipPath = clipPath.subtracted(subPath);

    painter.fillPath(clipPath, bgBrush);

    painter.restore();
    DTreeView::paintEvent(event);
}

void BaseTableView::drawRow(QPainter *painter, const QStyleOptionViewItem &options,
                            const QModelIndex &index) const
{
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setOpacity(0.05);
#ifdef ENABLE_INACTIVE_DISPLAY
    QWidget *wnd = DApplication::activeWindow();
#endif
    DPalette::ColorGroup cg;
    if (!(options.state & DStyle::State_Enabled)) {
        cg = DPalette::Disabled;
    } else {
#ifdef ENABLE_INACTIVE_DISPLAY
        if (!wnd) {
            cg = DPalette::Inactive;
        } else {
            if (wnd->isModal()) {
                cg = DPalette::Inactive;
            } else {
                cg = DPalette::Active;
            }
        }
#else
        cg = DPalette::Active;
#endif
    }

    auto *style = dynamic_cast<DStyle *>(DApplication::style());

    auto radius = style->pixelMetric(DStyle::PM_FrameRadius, &options);
//    auto margin = style->pixelMetric(DStyle::PM_ContentsMargins, &options);

    auto palette = options.palette;
    QBrush background;
    auto baseColor = palette.color(DPalette::Active, DPalette::WindowText);
    if (index.row() % 2 == 0) {
        background = palette.color(DPalette::Active, DPalette::AlternateBase);
    } else {
        background = baseColor;
    }

    if (options.state & DStyle::State_Enabled) {
        if (selectionModel()->isSelected(index)) {
            background = palette.color(cg, DPalette::Highlight);
            if (m_hover.isValid() && m_hover.row() == index.row()) {
                // hovered
                background = style->adjustColor(background.color(), 0, 0, 50);
            }
        } else {
            if (m_hover.isValid() && m_hover.row() == index.row()) {
                // hovered
                background = style->adjustColor(baseColor, 0, 0, - 100);
            }
        }
    }

    // draw row background
    QPainterPath path;
    QRect rowRect { options.rect.x() - header()->offset() + m_rowBackgroundDelta,
                    options.rect.y(),
                    header()->length() - 10 - m_rowBackgroundDelta,
                    options.rect.height() };
    rowRect.setX(rowRect.x());
    rowRect.setWidth(rowRect.width());

    path.addRoundedRect(rowRect, radius, radius);
    painter->fillPath(path, background);

    QTreeView::drawRow(painter, options, index);

    painter->restore();
}

void BaseTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    DTreeView::currentChanged(current, previous);

    if (previous.isValid()) {
        QRect previousRect = visualRect(previous);
        previousRect.setX(0);
        previousRect.setWidth(viewport()->width());
        viewport()->update(previousRect);
    }
    if (current.isValid()) {
        QRect currentRect = visualRect(current);
        currentRect.setX(0);
        currentRect.setWidth(viewport()->width());
        viewport()->update(currentRect);
    }
}

bool BaseTableView::viewportEvent(QEvent *event)
{
    switch (event->type()) {
        case QEvent::HoverLeave: {
            auto rect = visualRect(m_hover);
            rect.setX(0);
            rect.setWidth(viewport()->width());
            m_hover = QModelIndex();
            viewport()->update(rect);
            break;
        }
        case QEvent::HoverEnter:
        case QEvent::HoverMove: {
            auto *hev = dynamic_cast<QHoverEvent *>(event);
            m_hover = indexAt(hev->pos());
            auto rect = visualRect(m_hover);
            rect.setX(0);
            rect.setWidth(viewport()->width());
            viewport()->update(rect);
            break;
        }
        case QEvent::MouseMove:
        case QEvent::MouseButtonRelease:
        case QEvent::MouseButtonDblClick:
        case QEvent::MouseButtonPress: {
            auto *mev = dynamic_cast<QMouseEvent *>(event);
            auto newIndex = indexAt(mev->pos());
            QRegion region;
            QRect rect;
            if (m_pressed.isValid()) {
                rect = visualRect(m_pressed);
                rect.setX(0);
                rect.setWidth(viewport()->width());
                region += rect;
            }
            if (newIndex.isValid() && newIndex.row() != m_pressed.row()) {
                rect = visualRect(newIndex);
                rect.setX(0);
                rect.setWidth(viewport()->width());
                region += rect;
            }
            m_pressed = (mev->button() == Qt::LeftButton && (mev->type() == QEvent::MouseButtonPress || mev->type() == QEvent::MouseButtonDblClick)) ? newIndex : QModelIndex();
            viewport()->update(region);
            break;
        }
        default:
            break;
    }
    return DTreeView::viewportEvent(event);
}



