#include "sensorlistwidget.h"

#include <QDebug>
#include <QHeaderView>
#include <QScroller>
#include <QMap>
#include <QJsonObject>
#include <QJsonArray>

#include "sensorsettingsdialog.h"

SensorListWidget::SensorListWidget(const bool showHidden, QWidget *parent): QTreeWidget(parent),
	showHidden_(showHidden)
{
	setColumnCount(3);
	setHeaderLabels({"Sensor", "Value", "Time"});
	setSelectionBehavior(QAbstractItemView::SelectRows);
	header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
	header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
	header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
	QScroller::grabGesture(this, QScroller::LeftMouseButtonGesture);
	setAutoScroll(true);
	setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
	sensorsChanged(std::vector<Sensor>());

	connect(this, &QTreeWidget::itemDoubleClicked, this, &SensorListWidget::onDoubleClick);
}

SensorListWidget::SensorListWidget(SensorStore& sensorStore, const bool showHidden,
                                   QWidget* parent): QTreeWidget (parent), showHidden_(showHidden)
{
	sensorsChanged(*(sensorStore.getSensors()));
	connect(this, &QTreeWidget::itemDoubleClicked, this, &SensorListWidget::onDoubleClick);
}

void SensorListWidget::onDoubleClick(QTreeWidgetItem *item, int column)
{
	if(item && item->type() == 1001)
	{
		Sensor sensor = static_cast<SensorListItem*>(item)->getSensor();
		SensorSettingsDialog diag(sensor, this);
		if(diag.exec())
		{
			sensor.name = diag.getName();
			sensor.hidden = diag.getHidden();
			sensor.groupName = diag.getGroupName();

			globalSensors.sensorGotState(sensor, SENSOR_UPDATE_USER);
		}
	}
}

void SensorListWidget::sensorsChanged(std::vector<Sensor> sensors)
{
	QMap<QString, bool> expandedStates;
	QList<int> columnWidths;

	for(int i = 0; i < columnCount(); ++i)
		columnWidths.append(columnWidth(i));

	for(int i = 0; i < topLevelItemCount(); ++i)
	{
		QTreeWidgetItem* item = topLevelItem(i);
		if(item->type() != 1001)
		{
			expandedStates[item->text(0)] = item->isExpanded();
		}
	}

	clear();

	QMap<QString, QTreeWidgetItem*> groupItems;

	QStringList headerLabels = {"Sensor", "Value", "Time"};
	setHeaderLabels(headerLabels);

	QList<SensorListItem*> ungroupedItems;

	for(const Sensor& sensor : sensors)
	{
		if(!showHidden_ && sensor.hidden)
			continue;

		QString itemString = QString::number(sensor.field);

		if(sensor.type == Sensor::TYPE_DOOR)
		{
			if(static_cast<bool>(sensor.field))
				itemString = "\"Open\"";
			else
				itemString = "\"Closed\"";
		}
		else if(sensor.type == Sensor::TYPE_AUDIO_OUTPUT)
		{
			if(static_cast<bool>(sensor.field))
				itemString = "\"Playing\"";
			else
				itemString = "\"Silent\"";
		}
		else if(!sensor.getUnit().isEmpty())
		{
			itemString.append(" ");
			itemString.append(sensor.getUnit());
		}

		SensorListItem* sensorItem = new SensorListItem(sensor.name + (sensor.hidden ? " (H)" : ""), sensor);
		sensorItem->setText(0, sensor.name + (sensor.hidden ? " (H)" : ""));
		sensorItem->setText(1, itemString);
		if(sensor.type <= 128)
			sensorItem->setText(2, sensor.lastSeen.time().toString("hh:mm"));

		if(sensor.groupName.isEmpty())
		{
			ungroupedItems.append(sensorItem);
		}
		else
		{
			QTreeWidgetItem* groupItem;
			auto it = groupItems.find(sensor.groupName);
			if(it == groupItems.end())
			{
				groupItem = new QTreeWidgetItem(this);
				groupItem->setText(0, sensor.groupName);

				bool wasExpanded = expandedStates.value(sensor.groupName, false);
				if(pendingGroupExpandedStates_.contains(sensor.groupName))
					wasExpanded = pendingGroupExpandedStates_.take(sensor.groupName);
				groupItem->setExpanded(wasExpanded);
				groupItems[sensor.groupName] = groupItem;
			}
			else
			{
				groupItem = it.value();
			}
			groupItem->addChild(sensorItem);
		}
	}

	for(SensorListItem* item : ungroupedItems)
	{
		addTopLevelItem(item);
	}
	sortItems(0, Qt::AscendingOrder);

	for(auto it = groupItems.begin(); it != groupItems.end(); ++it)
	{
		it.value()->sortChildren(0, Qt::AscendingOrder);
	}

	for(int i = 0; i < columnCount() && i < columnWidths.size(); ++i)
		setColumnWidth(i, columnWidths.at(i));
}

const Sensor& SensorListWidget::getSensorForIndex(const QModelIndex &index)
{
	QTreeWidgetItem* item = itemFromIndex(index);
	if(item && item->type() == 1001)
		return static_cast<SensorListItem*>(item)->getSensor();
	static Sensor dummy;
	return dummy;
}

void SensorListWidget::setShowHidden(const bool showHidden)
{
	showHidden_ = showHidden;
	sensorsChanged(*globalSensors.getSensors());
}

void SensorListWidget::store(QJsonObject& json) const
{
	QJsonObject sensorListJson;

	QJsonObject groupStates;
	for(int i = 0; i < topLevelItemCount(); ++i)
	{
		QTreeWidgetItem* item = topLevelItem(i);
		if(item->type() != 1001)
		{
			groupStates[item->text(0)] = item->isExpanded();
		}
	}
	sensorListJson["GroupStates"] = groupStates;

	json["SensorList"] = sensorListJson;
}

void SensorListWidget::load(const QJsonObject& json)
{
	QJsonObject sensorListJson = json["SensorList"].toObject();

	QJsonObject groupStates = sensorListJson["GroupStates"].toObject();
	pendingGroupExpandedStates_.clear();
	for(auto it = groupStates.begin(); it != groupStates.end(); ++it)
	{
		pendingGroupExpandedStates_[it.key()] = it.value().toBool();
	}
}

const Sensor& SensorListItem::getSensor()
{
	return sensor;
}

SensorListItem::SensorListItem(const QString& text, const Sensor& sensor):
	 QTreeWidgetItem(1001), sensor(sensor)
{
	setText(0, text);
}

