#include "QueryExplainModel.h"
#include <QColor>
#include <QSize>
#include <cmath>

const int c_ColumnNode = 0;
const int c_ColumnExclusive = 1;
const int c_ColumnInclusive = 2;
const int c_ColumnEstErr = 3;
const int c_ColumnRowCount = 4;
const int c_ColumnLoops = 5;
const int c_ColumnDetails = 6;
const int c_ColumnShared = 7;
const int c_NumberOfColumns = 8;

QueryExplainModel::QueryExplainModel(QObject *parent, ExplainRoot::SPtr exp)
	: QAbstractItemModel(parent)
	, explain(std::move(exp))
{}

QVariant QueryExplainModel::data(const QModelIndex &index, int role) const
{
	QVariant result;
	if (index.isValid()) {
		int col = index.column();
		ExplainTreeModelItem *item = static_cast<ExplainTreeModelItem*>(index.internalPointer());
if (role == Qt::DisplayRole) {
			switch (col) {
			case c_ColumnNode:
				result = item->nodeType;
				break;
			case c_ColumnExclusive:
				result = item->exclusiveTime();
				break;
			case c_ColumnInclusive:
				result = item->inclusiveTime();
				break;
			case c_ColumnEstErr:
				result = item->estimateError();
				break;
			case c_ColumnRowCount:
				result = item->actualRows;
				break;
			case c_ColumnLoops:
				result = item->actualLoops;
				break;
			case c_ColumnDetails:
				result = item->detailString();
				break;
			case c_ColumnShared:
				result = item->sharedBlocks.asString();
				break;
			} // end switch column
		}
		else if (role == Qt::TextAlignmentRole) {
			if (col == c_ColumnNode || col == c_ColumnDetails) {
                result = int(Qt::AlignLeft | Qt::AlignVCenter);
			}
			else {
                result = int(Qt::AlignRight | Qt::AlignVCenter);
			}
		}
        else if (role == Qt::BackgroundRole) {
			if (col == c_ColumnExclusive || col == c_ColumnInclusive) {
				float t = col == 1 ? item->exclusiveTime() : item->inclusiveTime();
				float tt = explain->plan->inclusiveTime();
				if (tt > 0.000000001f) {
					float f = t / tt;
					if (f > 0.9f) {
						result = QColor(255, 192, 192);
					}
					else if (f > 0.63f) {
						result = QColor(255, 224, 192);
					}
					else if (f > 0.36f) {
						result = QColor(255, 255, 192);
					}
					else if (f > 0.09f) {
						result = QColor(255, 255, 224);
					}
					else {
						result = QColor(Qt::white);
					}
				}
			}
			if (col == c_ColumnEstErr) {
				float e = std::fabs(item->estimateError());
				if (e > 1000.0f) {
					result = QColor(255, 192, 192);
				}
				else if (e > 100.0f) {
					result = QColor(255, 224, 192);
				}
				else if (e > 10.0f) {
					result = QColor(255, 255, 192);
				}
				else {
					result = QColor(Qt::white);
				}
			}
		}
	}
	return result;
}

//Qt::ItemFlags QueryExplainModel::flags(const QModelIndex &index) const
//{

//}


QVariant QueryExplainModel::headerData(int section, Qt::Orientation orientation,
	int role) const
{
	QVariant v;
	if (orientation == Qt::Horizontal) {
		if (role == Qt::DisplayRole ) {
			switch (section) {
			case c_ColumnNode:
				v = "Node";
				break;
			case c_ColumnExclusive:
				v = "Exclusive";
				break;
			case c_ColumnInclusive:
				v = "Inclusive";
				break;
			case c_ColumnEstErr:
				v = "Est. Err";
				break;
			case c_ColumnRowCount:
				v = "Rows";
				break;
			case c_ColumnLoops:
				v = "Loops";
				break;
			case c_ColumnDetails:
				v = "Details";
				break;
			case c_ColumnShared:
				v = "Shared";
				break;
			}
		}
//		else if (role == Qt::SizeHintRole) {
//			switch (section) {
//			case 0:
//				v = QSize();
//				break;
//			case 1:
//				v = "Exclusive";
//				break;
//			case 2:
//				v = "Inclusive";
//				break;
//			case 3:
//				v = "Est. Err";
//				break;
//			}
//		}
	}
	return v;
}

QModelIndex QueryExplainModel::index(int row, int column,
	const QModelIndex &parent) const
{
	QModelIndex result;
	if (hasIndex(row, column, parent)) {
		if (parent.isValid()) {
			ExplainTreeModelItem *parentItem =
					static_cast<ExplainTreeModelItem*>(parent.internalPointer());
			if (parentItem) {
				ExplainTreeModelItemPtr childItem = parentItem->child(row);
				if (childItem) {
					result = createIndex(row, column, childItem.get());
				}
			}
		}
		else {
			result = createIndex(row, column, explain->plan.get());
		}
	}
	return result;

}

QModelIndex QueryExplainModel::parent(const QModelIndex &index) const
{
	QModelIndex result;
	if (index.isValid()) {
		ExplainTreeModelItem *childItem = static_cast<ExplainTreeModelItem*>(index.internalPointer());
		auto parentItem = childItem->parent();

		if (parentItem != nullptr) {
			result = createIndex( parentItem->row(), 0, parentItem.get());
		}
	}
	return result;
}

int QueryExplainModel::rowCount(const QModelIndex &parent) const
{
	int result = 0;
	if (parent.column() <= 0) {
		if (parent.isValid()) {
			auto item = static_cast<ExplainTreeModelItem*>(parent.internalPointer());
			result = item->childCount();
		}
		else {
			result = 1;
		}
	}
	return result;
}

int QueryExplainModel::columnCount(const QModelIndex &) const
{
//	if (parent.isValid()) {
//		return 6;//static_cast<ExplainTreeModelItem*>(parent.internalPointer())->columnCount();
//	}
//	else {
//		return 1;
//	}
	return c_NumberOfColumns;
}
