#include <RumPi/AlertManager.h>
#include "../../Headers/ResourceManager.h"
#include "../../Headers/GUI/LoggerListData.h"

/**
* Builds an empty logger list model.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	LoggerListData model;
* @endcode
*/
LoggerListData::LoggerListData() : wxDataViewVirtualListModel()
{
	myHasWarnedAtCapacity = false;
}

/**
* Appends a log line to the model and notifies the view that a row was added.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	model.AddToList(logLine);
* @endcode
*
* @param [in] dataToAdd The log line to append.
*/
void LoggerListData::AddToList(const LoggerLineData& dataToAdd)
{
	//Cap the history so a long-running kiosk doesn't grow this unbounded. Drop the oldest line (and tell the view)
	//before appending, keeping the vector and the view's row count in lockstep.
	const size_t maxLoggerLines = 5000;
	if (myLoggerLineDatas.size() >= maxLoggerLines)
	{
		myLoggerLineDatas.erase(myLoggerLineDatas.begin());
		RowDeleted(0);

		//Let the user know - once per capacity episode - that the log has filled and is now discarding its oldest
		//lines. This MUST stay latched: the warning is itself reported through AlertManager, which loops back here
		//as a new log line; without the latch that new line would (still at capacity) trigger another warning, and
		//so on forever. The latch re-arms in the else branch once the log drops back under the cap (e.g. a clear).
		if (myHasWarnedAtCapacity == false)
		{
			myHasWarnedAtCapacity = true;
			RumPi::AlertManager::GetInstance().Report(RumPi::EAlertLevel::Warning, "On-screen log reached its " + std::to_string(maxLoggerLines) + "-line capacity; the oldest entries are now being dropped.");
		}
	}
	else
	{
		//Back under capacity (e.g. after a clear) - re-arm the one-time warning for the next time the log fills.
		myHasWarnedAtCapacity = false;
	}

	myLoggerLineDatas.push_back(dataToAdd);

	//Tell the view a row was appended so it refreshes. Keep this in lockstep with the vector
	//so GetValueByRow() is never asked for a row we don't have.
	RowAppended();
}

/**
* Supplies the value for a given row and column to the data-view control (icon, timestamp, level text, or
* description).
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	//Called by the wxDataViewCtrl as it renders each cell.
* @endcode
*
* @param [out] variant The variant to fill with the cell's value.
* @param [in]  row     The row index.
* @param [in]  col     The column index (a LoggerColumnID).
*/
void LoggerListData::GetValueByRow(wxVariant& variant, unsigned int row, unsigned int col) const
{
	const LoggerLineData& specifiedRowItem = myLoggerLineDatas[row];

	if (col == LoggerColumnID::E_COL_ALERTICON)
	{
		variant << ResourceManager::GetAlertLevelImage(specifiedRowItem.GetAlertLevel());
	}
	else if (col == LoggerColumnID::E_COL_LOGTIME)
	{
		variant = specifiedRowItem.GetLogTime();
	}
	else if (col == LoggerColumnID::E_COL_ALERTLEVEL)
	{
		variant = specifiedRowItem.GetAlertLevelText();
	}
	else //if (col == LoggerColumnID::E_COL_EVENTDESCRIPTION)
	{
		variant = specifiedRowItem.GetEventDescription();
	}
}

/**
* Supplies a per-row display attribute, colouring alert rows red/bold and warning rows amber so the log is
* scannable at a glance.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	//Called by the wxDataViewCtrl as it styles each row.
* @endcode
*
* @param [in]  row  The row index.
* @param [in]  col  The column index.
* @param [out] attr The attribute to set for the row.
*
* @return True if a custom attribute was set (Alert/Warning), false to keep default styling (OK).
*/
bool LoggerListData::GetAttrByRow(unsigned int row, unsigned int col, wxDataViewItemAttr& attr) const
{
	//Colour the row by severity so the log is scannable at a glance. Return false for OK so the
	//control keeps its default styling (returning true means "I set a custom attribute").
	if (myLoggerLineDatas[row].GetAlertLevel() == RumPi::EAlertLevel::Alert)
	{
		attr.SetColour(*wxRED);
		attr.SetBold(true);

		return true;
	}
	else if (myLoggerLineDatas[row].GetAlertLevel() == RumPi::EAlertLevel::Warning)
	{
		attr.SetColour(wxColour(200, 120, 0));
		return true;
	}

	return false; //OK
}

/**
* Rejects edits from the UI: the log is read-only from the view's perspective.
*
* @author Eddie O'Hagan
* @date 8/13/2026
*
* @code
*	//Called by the wxDataViewCtrl on an edit attempt; always refuses.
* @endcode
*
* @param [in] variant The value the control tried to set.
* @param [in] row     The row index.
* @param [in] col     The column index.
*
* @return Always false (the log cannot be edited).
*/
bool LoggerListData::SetValueByRow(const wxVariant& variant, unsigned int row, unsigned int col)
{
	//The log is read-only from the UI's perspective.
	return false;
}
