#ifndef KINDA_SERVERSIDE_H_
#define KINDA_SERVERSIDE_H_

/*
 * Copyright 2020-2023, ttcoder
*/


// genode/base.lib.a
#include <base/log.h>  // error()...
#include <base/semaphore.h>  // member
#include <util/string.h>  // member

// stdcxx.lib.so
#include <map>  // member
#include <vector>  // member

// haiku.lib.so
#include <OS.h>  // int32 etc


/****************/
#define HAS_BROKER  /// NOT used here, only used by "api-main.cpp" and "api-public_sem-port-thread-etc.cpp"...


namespace hog {
	struct PortItem;
	class ThreadWithFunc;
	class HaiCalls_Srv;
}


struct hog::PortItem
{
	int32 code;
	size_t size; ///later: or maybe Ssize_t, like PortPeek() and port_buffer_size() ?
	void * data;
};


class hog::ThreadWithFunc
{
public:

		ThreadWithFunc( thread_func func, const char * name, void * data );
		~ThreadWithFunc();
		
		// mimic Genode::Thread
		//
		const char * name() const;
	static void * entry( void * hog_thread_uncast );
		
		// misc. new
		//
		status_t Resume();
		pthread_t PosixID() const;
		
		void CancelAndMark();
		sem_id EndOfLife_Sem() const;
		
		void Dump() const;


private:  // Data

		const thread_func addyFunc;
		void * funcData;
		pthread_t pthreadID;
		const Genode::String<64> haiThreadName; ///B_OS_NAME_Length instead of 64
		enum { READY_TO_RUN, RUNNING, NEEDS_JOINING, NEEDS_DELETING }
			lifeState;
		sem_id deathNoticeSem;  // aka "join-sem" aka "completion/exit-notice sem" : needed if several threads are calling wait_for_thread() on us


private:  // Forbidden

		ThreadWithFunc( const ThreadWithFunc & );
		ThreadWithFunc & operator=( const ThreadWithFunc & );
};



//#pragma mark -


#include <stdlib.h>  /// free()

class hog::HaiCalls_Srv
{
public:
		HaiCalls_Srv();
		
		// sems
		sem_id   SemCreate( int32 count, const char * name );
		status_t SemDelete( sem_id id );
		status_t SemAcquire( sem_id id );
		status_t SemRelease( sem_id id );
		status_t SemGet( sem_id id, int32 * thread_count );
		
		// ports
		void WaitBlockadeForPort( port_id port );
		void ReleaseBlockadeForPort( port_id port );
		port_id	PortCreate( const char * name, int port_numbering_base );
		void	PortClose( port_id port );
		void	PortDelete( port_id port );
		int32	PortCount( port_id port );
		status_t PortInfo( port_id port, port_info & info );
		ssize_t	PortRead(
			port_id port,
			int32 * code,
			void * buffer,
			size_t size
			);
		status_t PortAppend(
			port_id port,
			int32 code,
			const void * buffer,
			size_t size
			);
		ssize_t PortPeek(
			port_id port,
			uint32 flags,
			bigtime_t timeout
			);
		
		// threads
		thread_id ThreadCreate(
			thread_func func,
			const char * name,
			void * data
			);
		status_t  ThreadStart( thread_id thread );
		status_t  ThreadJoin( thread_id thread );
		thread_id ThreadByName( const char * name );
		hog::ThreadWithFunc *
			LookupThread( thread_id thread );


private:  // Types, Constants

	class PortFifo
	{
	public:
		PortFifo()
		:	semBlockade()
			,itemQueue()
			,isClosedDown( false )
		{
		}
		
		~PortFifo()
		{
			// for each 'msg' in the port's queue:
			// for each in itemQueue
			for( unsigned i = 0; i < itemQueue.size(); i++ )
			{
				// free() the malloc:
				free( itemQueue[i].data );
			}
			itemQueue.erase( itemQueue.begin(), itemQueue.end() );
		}
		
		ssize_t size() const
		{
			return itemQueue.size();
		}
		
		PortItem & front()
		{
			return itemQueue.front();
		}
		
		void push_back( const PortItem & item )
		{
			///+? ASSERT( isClosedDown == false );
			
			itemQueue.push_back( item );
		}
		
		void erase_first_item() ///+ erase_front
		{
			itemQueue.erase( itemQueue.begin() );
		}
		
		void close_down()
		{
			isClosedDown = true;
		}
		
		bool is_closed() const
		{
			return isClosedDown;
		}
		
		Genode::Semaphore * blockade()
		{
			// Used By:
			// WaitBlockadeForPort()
			
			if( isClosedDown )
				Genode::error( "requesting blockade on a closed-down port ; makes little sense for someone to wait on new msgs that won't be allowed to arrive!");
			
			return &semBlockade;
		}
		
	private:  // Data
	
	///ToDo: why not an actual Genode::Blockade or Genode::Mutex ?
		Genode::Semaphore semBlockade;  // each port is 'synced' through its own semaphore
		std::vector<PortItem> itemQueue;  // 'messages' queued up in this port
		bool isClosedDown;  // if true, close_port() has been called : we no longer accept any write_port(), and just await delete_port()
	
	private:  // Disabled
	
		PortFifo( const PortFifo & peer );
		PortFifo & operator=( const PortFifo & peer );
	};
	

private:  // Code

		PortFifo *
			lookupPort( port_id port );
		hog::ThreadWithFunc *
			lookupThread( thread_id thread );


private:  // Data

		// !
		Genode::Mutex
			kernelLock;
		// !
		// be careful if activating full-fledged log()ging:
		// boot-up will take 10+ mins in qemu, ouch (maybe try on bare/metal)
//#	define MTSAFE_GUARD  Genode::log( "kernel-lock >>>>>>> ", __func__ ); Genode::Lock::Guard lock_guard( kernelLock );
//#	define MTSAFE_GUARD_Epilogue  Genode::log("kern-lock released............ ", , __func__);
#	define MTSAFE_GUARD  Genode::Mutex::Guard lock_guard( kernelLock );
#	define MTSAFE_GUARD_Epilogue
		
		// sems
		int32 nextSemaphore;
		typedef
			std::map<sem_id, Genode::Semaphore*> SemMap;
		SemMap semMap;
		
		// ports
		//++int32 nextPort;
		std::map<port_id, PortFifo*> portQueues;
		
		// threads
		int32 nextThread;
		std::map<thread_id, hog::ThreadWithFunc*>
			threadsMap;  // each Haiku thread maps to a ThreadWithFunc, i.e. a POSIX pthread, i.e. a Genode::Thread
};


/*********************/
extern hog::HaiCalls_Srv
	haiku_syscalls_srv_;



#endif  // ~KINDA_SERVERSIDE_H_

