#pragma once

#pragma warning(push)
#pragma warning(disable: 4100)
#include "FastDelegate.h"
#pragma warning(pop)

#include "shared/SharedMemory.h"
#include "shared/Structures.h"

//////////////////////////////////////////////////////////////////////////////

typedef fastdelegate::FastDelegate1<bool>	ConsoleChangeDelegate;
typedef fastdelegate::FastDelegate0<>		ConsoleCloseDelegate;

//////////////////////////////////////////////////////////////////////////////
#define MAX_TERM_BUFFERS	3
#define TERM_BUFFER_SIZE 20000
struct Term_Data{
public:
	CONSOLE_CURSOR_INFO cursorInfo;
	CONSOLE_SCREEN_BUFFER_INFO screenInfo;
	ConsoleParams		conParams;
	string				buffer;
	struct Term_Data	*_n;
	struct Term_Data	*_p;
	int					full;
	CHAR_INFO			conBuffer[TERM_BUFFER_SIZE];
};
typedef struct Term_Data Term_Data_t;

class ConsoleHandler
{
	private:
		Term_Data_t *pre_term;
		Term_Data_t *cur_term;
		Term_Data_t *wor_term;
		int			scroll_pos;

	public:
		ConsoleHandler();
		ConsoleHandler(void *evt);
		~ConsoleHandler();

	public:

		void CloseHandle();
		void SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ConsoleCloseDelegate consoleCloseDelegate);
		bool StartShellProcess(const wstring& strCustomShell, const wstring& strInitialDir, const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns);

		DWORD StartMonitorThread();
		void StopMonitorThread();

		shared_ptr<void> GetConsoleHandle() const					{ return m_hConsoleProcess; }

		SharedMemory<ConsoleParams>& GetConsoleParams()				{ return m_consoleParams; }
		SharedMemory<CONSOLE_SCREEN_BUFFER_INFO>& GetConsoleInfo()	{ return m_consoleInfo; }
		SharedMemory<CONSOLE_CURSOR_INFO>& GetCursorInfo()			{ return m_cursorInfo; }
		SharedMemory<CHAR_INFO>& GetConsoleBuffer()					{ return m_consoleBuffer; }
		SharedMemory<UINT_PTR>& GetConsolePasteInfo()				{ return m_consolePaste; }
		SharedMemory<ConsoleSize>& GetNewConsoleSize()				{ return m_newConsoleSize; }
		SharedMemory<SIZE>& GetNewScrollPos()						{ return m_newScrollPos; }

		void ConsoleChange(bool reSize);
		void ConsoleClose();
		void SendTextToConsole(const char *ptext);
		void ConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
		int GetConsoleOutput(char *buf,int len);
		void AdjustSize(int _c,int _r);
		void AdjustScrollBarPos(int nDelta);
		void AdjustBufferSize(int lines);
		void ShowConsole(int show);

	private:

		bool CreateSharedMemory(DWORD dwConsoleProcessId);

		bool InjectHookDLL();

	private:
		
		static DWORD WINAPI MonitorThreadStatic(LPVOID lpParameter);
		DWORD MonitorThread();


	private:
		
		wstring GetModulePath(HMODULE hModule);


	private:

		ConsoleChangeDelegate						m_consoleChangeDelegate;
		ConsoleCloseDelegate						m_consoleCloseDelegate;

		shared_ptr<void>							m_hConsoleProcess;

		SharedMemory<ConsoleParams>					m_consoleParams;
		SharedMemory<CONSOLE_SCREEN_BUFFER_INFO>	m_consoleInfo;
		SharedMemory<CONSOLE_CURSOR_INFO>			m_cursorInfo;
		SharedMemory<CHAR_INFO>						m_consoleBuffer;
		SharedMemory<UINT_PTR>						m_consolePaste;

		SharedMemory<ConsoleSize>					m_newConsoleSize;
		SharedMemory<SIZE>							m_newScrollPos;

		shared_ptr<void>							m_hMonitorThread;
		shared_ptr<void>							m_hMonitorThreadExit;
		string										buffer;
		COORD 										pre_pos;
		void*										evt_owner;
		void*										front;
		int											updated;
};

//////////////////////////////////////////////////////////////////////////////
