/*
 * Copyright 2023, ttcoder
 * All rights reserved. Distributed under the terms of the MIT license.
 */
#ifndef RingLog_H
#define RingLog_H


// base.lib.a
//#include <base/mutex.h>  // member
#include <timer_session/connection.h>  // member


//+ template <size_t SIZE=256>
class RingLog
{
	// This logging class is an interesting alternative to Genode::log()
	// for high-volume tracing. For instance: Audio_out packets
	// being processed by the hundreds every second.
	// It could also be named (more appropriately) "Tail Log", since
	// most contents passed to log() never makes it to the screen, except
	// some 'snapshots' which dump the tail-end (latest contents) to LOG.
	// Optim:
	// To avoid moving data around, we have a "front buffer"
	// and a "back buffer" and swap them. We take that (and other) shortcuts to keep
	// the design as simple and trivial as possible whilst being light on CPU usage.
	
public:

		RingLog(
			Genode::Env & env,
			bool enable_periodic_snapshots = true,
			bool enable_instant_parrot = false
			);
		~RingLog();
		
		void log( const char * text );
		void log( int num );
		
		void Dump();


private:  // Constants & Types

	///ToDo: convert these enums to "static constexpr" before the switch to "c++20" in the next GCC, otherwise it will error out on "forbidden to do arithmetic with enums" ?
	enum { SIZE = 128/*256*/ };
	enum { SLEEP = 15 };
	
	class LogThread : public Genode::Thread
	{
	public:
		LogThread( Genode::Env & env, RingLog & ring );
		
		void entry() override;
		
	public:  // (!)
		bool tearDown;
		Timer::Connection conTimer;
		RingLog & ringLog;
	};


private:  // Code

		const char * oldest();
		char * newest();


private:  // Data

		// serialize access from <logThread> etc
		Genode::Mutex logMutex;
		
		// support for when <enableSnapshots> == true
		LogThread logThread;
		bool logThreadNeedsJoining;  // no choice but to maintain this state here
			// (there is no other way to retrieve it that I can tell), as we MUST
			// make sure to NOT call join() on a thread that was never started (or
			// that was already joined) on pain of catastrophic consequences/silent exception.
		
		// state: config
		bool enableSnapshots;
		bool instantMode;
		
		// state: bizlogic
		char buf1[ SIZE ];
		char buf2[ SIZE ];
		bool buf2isOldest;
};


#endif // RingLog_H

