#include "util/PgLabItemDelegate.h"
#include <QApplication>
#include <QPainter>

#include "Pgsql_oids.h"
#include "ResultTableModelUtil.h"
#include "CustomDataRole.h"
#include "AbstractEditorFactory.h"
#include "Colors.h"
#include "utils/HumanReadableBytes.h"
#include "qstyleoption.h"

PgLabItemDelegate::PgLabItemDelegate(QObject *parent)
	: QStyledItemDelegate(parent)
{

}


void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option,
										 const QModelIndex &index) const
{
	QVariant value;
//	value = index.data(Qt::FontRole);
//	if (value.isValid() && !value.isNull()) {
//		option->font = qvariant_cast<QFont>(value).resolve(option->font);
//		option->fontMetrics = QFontMetrics(option->font);
//	}

//	value = index.data(Qt::TextAlignmentRole);
//	if (value.isValid() && !value.isNull())
//		option->displayAlignment = Qt::Alignment(value.toInt());

//	value = index.data(Qt::ForegroundRole);
//	if (value.canConvert<QBrush>())
//		option->palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));


	option->index = index;
//	value = index.data(Qt::CheckStateRole);
//	if (value.isValid() && !value.isNull()) {
//		option->features |= QStyleOptionViewItem::HasCheckIndicator;
//		option->checkState = static_cast<Qt::CheckState>(value.toInt());
//	}

//	value = index.data(Qt::DecorationRole);
//	if (value.isValid() && !value.isNull()) {
//		option->features |= QStyleOptionViewItem::HasDecoration;
//		switch (value.type()) {
//		case QVariant::Icon: {
//			option->icon = qvariant_cast<QIcon>(value);
//			QIcon::Mode mode;
//			if (!(option->state & QStyle::State_Enabled))
//				mode = QIcon::Disabled;
//			else if (option->state & QStyle::State_Selected)
//				mode = QIcon::Selected;
//			else
//				mode = QIcon::Normal;
//			QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
//			QSize actualSize = option->icon.actualSize(option->decorationSize, mode, state);
//			// For highdpi icons actualSize might be larger than decorationSize, which we don't want. Clamp it to decorationSize.
//			option->decorationSize = QSize(qMin(option->decorationSize.width(), actualSize.width()),
//										   qMin(option->decorationSize.height(), actualSize.height()));
//			break;
//		}
//		case QVariant::Color: {
//			QPixmap pixmap(option->decorationSize);
//			pixmap.fill(qvariant_cast<QColor>(value));
//			option->icon = QIcon(pixmap);
//			break;
//		}
//		case QVariant::Image: {
//			QImage image = qvariant_cast<QImage>(value);
//			option->icon = QIcon(QPixmap::fromImage(image));
//			option->decorationSize = image.size() / image.devicePixelRatio();
//			break;
//		}
//		case QVariant::Pixmap: {
//			QPixmap pixmap = qvariant_cast<QPixmap>(value);
//			option->icon = QIcon(pixmap);
//			option->decorationSize = pixmap.size() / pixmap.devicePixelRatio();
//			break;
//		}
//		default:
//			break;
//		}
//	}

    const ColorTheme &theme = GetColorTheme();

	Oid oid = InvalidOid;
	value = index.data(CustomDataTypeRole); // get OID
	if (value.isValid())
		oid = value.toUInt(); //getType(index.column());

    value = index.data(CustomDataMeaningRole);
    DataMeaning meaning = value.isValid()
            ? static_cast<DataMeaning>(value.toInt())
            : DataMeaning::Normal;

	value = index.data(Qt::DisplayRole);

	option->displayAlignment = GetDefaultAlignmentForType(oid);


	if (value.isValid() && ! value.isNull()) {
        QColor forground_color;

		option->features |= QStyleOptionViewItem::HasDisplay;
        if (oid == Pgsql::bool_oid) {
            bool b = value.toBool();
            forground_color = GetDefaultBoolColor(b);
            option->text = FormatBoolForDisplay(b);
        }
		else {
            forground_color = theme.GetColorForType(oid);
            if (meaning == DataMeaning::Bytes) {
                option->text = HandleBytes(value.toLongLong(), forground_color);
            }
            else {
                auto str = value.toString();
                auto s = str.left(100);
                option->text = s;
            }
        }
        option->palette.setBrush(QPalette::Text, QBrush(forground_color));
    }
	else {
        option->palette.setBrush(QPalette::Text, QBrush(theme.nullColor));

		option->features |= QStyleOptionViewItem::HasDisplay;
		option->text = "null";
	}


//     if (option->state & QStyle::State_HasFocus) {
//         QColor color = Qt::darkYellow;
//         option->palette.setColor(QPalette::Active, QPalette::Highlight, color);
// //        option->palette.setColor(QPalette::Active, QPalette::AlternateBase, color);
//         option->backgroundBrush = QBrush(color);
//         option->font.setWeight(QFont::ExtraBold);
//      }


//	option->backgroundBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));

	// disable style animations for checkboxes etc. within itemviews (QTBUG-30146)
	option->styleObject = nullptr;
}

QString PgLabItemDelegate::HandleBytes(qlonglong s, QColor &forground_color) const
{
    const ColorTheme& theme = GetColorTheme();
    auto str = HumanReadableBytes(s);
    if (s > 1024 * 1024 * 1024) {
        forground_color = theme.gigaBytes;
    }
    else if (s > 1024 * 1024) {
        forground_color = theme.megaBytes;
    }
    else if (s > 1024) {
        forground_color = theme.kiloBytes;
    }
    else {
        forground_color = theme.bytes;
    }
    return QString::fromStdString(str);
}



void PgLabItemDelegate::paint(QPainter *painter,
                              const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_ASSERT(index.isValid());

    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

    const QWidget *widget = option.widget; // QStyledItemDelegatePrivate::widget(option);
    QStyle *style = widget ? widget->style() : QApplication::style();
    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);

    if (option.state & QStyle::State_HasFocus) {
        QColor color = Qt::red;
        painter->setPen(QPen(QBrush(color), 2.0));
        painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
    }

}

QWidget *PgLabItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (m_editorFactory)
        return m_editorFactory->createEditor(parent, option, index);
    return QStyledItemDelegate::createEditor(parent, option, index);
}

void PgLabItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (m_editorFactory)
        m_editorFactory->setEditorData(editor, index);
	else
		QStyledItemDelegate::setEditorData(editor, index);
}

void PgLabItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
	if (m_editorFactory)
		m_editorFactory->setModelData(editor, model, index);
	else
		QStyledItemDelegate::setModelData(editor, model, index);
}

AbstractEditorFactory* PgLabItemDelegate::editorFactory()
{
	return m_editorFactory;
}

void PgLabItemDelegate::setEditorFactory(AbstractEditorFactory *editor_factory)
{
	m_editorFactory = editor_factory;
}
