//..............................................................................
//
// Standard session information (session time and byte counters)
//

import "ui_InformationGrid.jnc"
import "sys_Timer.jnc"
import "sys_Lock.jnc"
import "log_Log.jnc"
import "formatInteger.jnc"

namespace ui {

//! \addtogroup common-ui
//! @{

//..............................................................................

class StdSessionInfoSet {
public:
	bitflag enum InfoId {
		SessionTime,
		TxTotalSize,
		TxThroughput,
		RxTotalSize,
		RxThroughput,
		TotalSize,
		TotalThroughput,

		Default =
			SessionTime |
			TxTotalSize |
			TxThroughput  |
			RxTotalSize |
			RxThroughput,
	}

public:
	InformationValue* readonly m_sessionTimeInfo;
	InformationValue* readonly m_txTotalSizeInfo;
	InformationValue* readonly m_txThroughputInfo;
	InformationValue* readonly m_rxTotalSizeInfo;
	InformationValue* readonly m_rxThroughputInfo;
	InformationValue* readonly m_totalSizeInfo;
	InformationValue* readonly m_totalThroughputInfo;

protected:
	log.TxRxStats* m_txRxStats;
	uint64_t m_txPrevTotalSize;
	uint64_t m_rxPrevTotalSize;

	sys.Timer m_timer;
	uint64_t m_sessionTimestamp;
	uint64_t m_throughputTimestamp;
	uint_t m_syncId;

public:
	void create(
		log.TxRxStats* txRxStats,
		InformationGrid* informationGrid,
		InformationGroup* group = null,
		InformationValue* insertBefore = null,
		InfoId mask = InfoId.Default
	);

	void startSession(jnc.Scheduler* mainThreadScheduler);
	void endSession();

protected:
	void update(uint64_t timestamp = sys.getTimestamp());
	void initialUpdate();

	void onTimer(uint_t syncId);

	void onLogRecord(
		uint64_t timestamp,
		uint64_t recordCode,
		void const* p,
		size_t size
	);
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

void StdSessionInfoSet.create(
	log.TxRxStats* txRxStats,
	InformationGrid* informationGrid,
	InformationGroup* group,
	InformationValue* insertBefore,
	InfoId mask
) {
	m_txRxStats = txRxStats;

	if (mask & InfoId.SessionTime) {
		m_sessionTimeInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"Session time"
		);

		m_sessionTimeInfo.m_isEnabled = false;
	}

	if (mask & InfoId.TxTotalSize) {
		m_txTotalSizeInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"TX total bytes"
		);

		m_txTotalSizeInfo.m_isEnabled = false;
	}

	if (mask & InfoId.TxThroughput) {
		m_txThroughputInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"TX throughput"
		);

		m_txThroughputInfo.m_isEnabled = false;
	}

	if (mask & InfoId.RxTotalSize) {
		m_rxTotalSizeInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"RX total bytes"
		);

		m_rxTotalSizeInfo.m_isEnabled = false;
	}

	if (mask & InfoId.RxThroughput) {
		m_rxThroughputInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"RX throughput"
		);

		m_rxThroughputInfo.m_isEnabled = false;
	}

	if (mask & InfoId.TotalSize) {
		m_totalSizeInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"Total bytes"
		);

		m_totalSizeInfo.m_isEnabled = false;
	}

	if (mask & InfoId.TotalThroughput) {
		m_totalThroughputInfo = informationGrid.createValue(
			group,
			insertBefore,,
			"Total throughput"
		);

		m_totalThroughputInfo.m_isEnabled = false;
	}

	initialUpdate();
}

void StdSessionInfoSet.startSession(jnc.Scheduler* mainThreadScheduler) {
	if (m_sessionTimeInfo)
		m_sessionTimeInfo.m_isEnabled = true;

	if (m_txTotalSizeInfo)
		m_txTotalSizeInfo.m_isEnabled = true;

	if (m_txThroughputInfo)
		m_txThroughputInfo.m_isEnabled = true;

	if (m_rxTotalSizeInfo)
		m_rxTotalSizeInfo.m_isEnabled = true;

	if (m_rxThroughputInfo)
		m_rxThroughputInfo.m_isEnabled = true;

	if (m_totalSizeInfo)
		m_totalSizeInfo.m_isEnabled = true;

	if (m_totalThroughputInfo)
		m_totalThroughputInfo.m_isEnabled = true;

	m_txRxStats.reset();
	m_txPrevTotalSize = 0;
	m_rxPrevTotalSize = 0;

	m_syncId++;
	m_timer.startPeriodicTimer(onTimer~(m_syncId) @ mainThreadScheduler, 500);

	initialUpdate();
}

void StdSessionInfoSet.endSession() {
	m_timer.stop();

	update(); // final update

	if (m_sessionTimeInfo)
		m_sessionTimeInfo.m_isEnabled = false;

	if (m_txTotalSizeInfo)
		m_txTotalSizeInfo.m_isEnabled = false;

	if (m_txThroughputInfo)
		m_txThroughputInfo.m_isEnabled = false;

	if (m_rxTotalSizeInfo)
		m_rxTotalSizeInfo.m_isEnabled = false;

	if (m_rxThroughputInfo)
		m_rxThroughputInfo.m_isEnabled = false;

	if (m_totalSizeInfo)
		m_totalSizeInfo.m_isEnabled = false;

	if (m_totalThroughputInfo)
		m_totalThroughputInfo.m_isEnabled = false;

	m_syncId++;
}

void StdSessionInfoSet.onTimer(uint_t syncId) {
	if (syncId == m_syncId)
		update();
}

void StdSessionInfoSet.initialUpdate() {
	uint64_t timestamp = sys.getTimestamp();
	m_sessionTimestamp = timestamp;
	m_throughputTimestamp = timestamp;
	update(timestamp);
}

void StdSessionInfoSet.update(uint64_t timestamp) {
	// take snapshots...

	uint64_t txTotalSize = m_txRxStats.m_txTotalSize;
	uint64_t rxTotalSize = m_txRxStats.m_rxTotalSize;

	// ...then calculate

	size_t txThroughput;
	size_t rxThroughput;

	if (timestamp > m_throughputTimestamp) {
		uint64_t timeSpan = timestamp - m_throughputTimestamp;
		txThroughput = (txTotalSize - m_txPrevTotalSize) * 10000000 / timeSpan;
		rxThroughput = (rxTotalSize - m_rxPrevTotalSize) * 10000000 / timeSpan;

		m_txPrevTotalSize = txTotalSize;
		m_rxPrevTotalSize = rxTotalSize;
		m_throughputTimestamp = timestamp;
	}

	if (m_sessionTimeInfo)
		m_sessionTimeInfo.m_value = sys.formatTimestamp(timestamp - m_sessionTimestamp, 0, "%h:%m:%s");

	if (m_txTotalSizeInfo)
		m_txTotalSizeInfo.m_value = $"$(formatIntegerWithThousandSep(txTotalSize))";

	if (m_txThroughputInfo)
		m_txThroughputInfo.m_value = $"$(formatIntegerWithThousandSep(txThroughput))";

	if (m_rxTotalSizeInfo)
		m_rxTotalSizeInfo.m_value = $"$(formatIntegerWithThousandSep(rxTotalSize))";

	if (m_rxThroughputInfo)
		m_rxThroughputInfo.m_value = $"$(formatIntegerWithThousandSep(rxThroughput))";

	if (m_totalSizeInfo)
		m_totalSizeInfo.m_value = $"$(formatIntegerWithThousandSep(txTotalSize + rxTotalSize))";

	if (m_totalThroughputInfo)
		m_totalThroughputInfo.m_value = $"$(formatIntegerWithThousandSep(txThroughput + rxThroughput))";
}

//..............................................................................

//! @}

} // namespace ui
