#pragma once

#ifndef __COMLINEHPP__
#define __COMLINEHPP__

#include <windows.h>
#include "comutil.hpp"
#include "critical.hpp"
class CCommandLineClient;
class CCommandLineServer;
namespace NCOMLINE
{
	enum LineType {LINE_UNDEF,LINE_OUTPUT,LINE_COMMAND};

	const int MAXARGS = 25;
	const int MAXLINES = 100;
	struct LineData
	{
		CCom_String m_Data;
		LineType m_Type;
		int m_ComBreak;
		int m_ArgBreak[MAXARGS];
		int m_NumArgs;

		void PushArg (int loc)
		{
			m_ArgBreak[m_NumArgs] = loc;
			m_NumArgs++;
		}

		void Argument (int id,char *arg,int len)
		{
			assert (id >= 0);
			assert (id <m_NumArgs);
			arg[0] = 0;
			len--;
			if (id == 0)
			{
				if (len < m_ArgBreak[0])
					return;
				strncpy (arg,(LPCTSTR) m_Data,m_ArgBreak[0]);
				len = m_ArgBreak[0];
			}
			else
			{
				if (len < (m_ArgBreak[id]-m_ArgBreak[id-1]-1))
					return;
				strncpy (arg,&(((LPCTSTR) m_Data)[m_ArgBreak[id-1]+1]),(m_ArgBreak[id]-m_ArgBreak[id-1]-1));
				len = m_ArgBreak[id]-m_ArgBreak[id-1]-1;
			}
//			strncpy (arg,(LPCTSTR) name,len);
			arg[len] = 0;
		}

		LineData (void)
		{
			m_NumArgs = 0;
			m_Data.Empty ();
			m_ComBreak = 0;
			m_Type = LINE_UNDEF;
		}
		LineData (const CCom_String& p1,LineType p2)
		{
			m_NumArgs = 0;
			m_Data = p1;
			m_Type = p2;
		}
		LineData (const LineData& p1)
		{
			int i;
			for (i=0;i<MAXARGS;i++)
				m_ArgBreak[i] = p1.m_ArgBreak[i];
			m_Data = p1.m_Data;
			m_ComBreak = p1.m_ComBreak;
			m_Type = p1.m_Type;
			m_NumArgs = p1.m_NumArgs;
		}
		~LineData (void)
		{
		}
	};

	typedef bool (*ComFunc) (CCommandLineServer *thisptr,LineData& p1);
	struct CommandMap
	{
		CCom_String m_Command;
		ComFunc m_Function;
		CommandMap (void)
		{
			m_Function = NULL;
			m_Command = "";
		}
		CommandMap (const CommandMap& p1)
		{
			m_Command = p1.m_Command;
			m_Function = p1.m_Function;
		}
		CommandMap (CCom_String p1,ComFunc p2)
		{
			m_Command = p1;
			m_Function = p2;
		}
	};

	LRESULT WINAPI CommandLineWndProc (HWND thewnd,UINT themsg,WPARAM wParam,LPARAM lParam);
	DWORD WINAPI ServerThreadProc (void *data);
	extern CCommandLineServer *n_CurServer;
};
#ifdef LAB_ONLY
#define COMSPEW(x) if(NCOMLINE::n_CurServer)NCOMLINE::n_CurServer->PushLine (x)
#else
#define COMSPEW(x) ((void)0)
#endif

typedef void (* CommandLineCallProc) (int);
#ifdef COMCLIENT
class CCommandLineClient
{
	friend LRESULT WINAPI NCOMLINE::CommandLineWndProc (HWND thewnd,UINT themsg,WPARAM wParam,LPARAM lParam);
	static int m_WndClassRefCount;

private:
	HWND			m_Window;												// window for the command line
	NCOMLINE::LineData *m_Lines;							// each line that appears in the command line window
	int				m_NumLines,m_SizeLines;
	int				m_TopDisplay;										// line that is the top of the command window
	HFONT			m_Font;													// font used for text
	COLORREF	m_CurLineColor;									// color of current line
	COLORREF	m_CommandColor;									// color of command on previous lines
	COLORREF	m_ArgColor;											// color of arguments on previous lines
	COLORREF	m_OutColor;											// color of output on previous lines

	HPEN			m_CursorPen;										// pen used to draw the cursor
	int				m_CursorPos;										// pos of cursor within current text
	POINT		m_CursorLoc;											// location of cursor on the screen	at top of bar
	bool			m_ShowCursor;										// true if we should show the cursor at all
	bool			m_CursorFlash;									// current state of cursor flash

	CCom_String		m_CurrentLine;									// current line being edited.
	RECT			m_WindowRect;										// size of the window
	int				m_DisplayLines;									// number of lines displayed in the window
  unsigned char pszStringBinding[255];					// rpc binding
	bool			m_Attached;

	LRESULT WndProc (HWND thewnd,UINT themsg,WPARAM wParam,LPARAM lParam);
	void ParseLine (NCOMLINE::LineData& data);
	void ExecuteLine (NCOMLINE::LineData& data);
	bool DumpFile (NCOMLINE::LineData& data);
	void KillServer (NCOMLINE::LineData& data);
	
	HINSTANCE m_Instance;											// main application instance

	bool DumpFile (const CCom_String& filename);
	void PushLine (const NCOMLINE::LineData& data);

public:
	CCommandLineClient (HINSTANCE inst);
	~CCommandLineClient (void);
	
	void ExecuteLine (const char *line);
	void PushLine (const char *line);
	void DumpToFile (const char *filename);

	RPC_STATUS AttachServer (NCOMLINE::LineData& data);
	RPC_STATUS DetachServer (NCOMLINE::LineData& data);
	void ListServers (void);



	void ShowWindow (void);
  void HideWindow (void);
};
#endif



















#ifdef COMSERVER
class CCommandLineServer
{
	friend DWORD WINAPI NCOMLINE::ServerThreadProc (void *data);

private:
	NCOMLINE::LineData *m_Lines;							// each line that appears in the command line window
	int				m_NumLines,m_SizeLines;
//	std::list<NCOMLINE::LineData> m_Lines;		// list of lines pending on the server side.
	HANDLE				m_Thread;
	DWORD 				m_ThreadID;
	ROOT_CRITICAL	m_Critical;
	HANDLE				m_Semaphore;
	HANDLE				m_ExitSemaphore;
	HANDLE				hMappedFile;
	bool					m_Inited;

	HINSTANCE m_Instance;
	NCOMLINE::CommandMap *m_Commands;
	int m_NumCommands,m_SizeCommands;

	void ParseLine (NCOMLINE::LineData& data);
	void PushLine (const NCOMLINE::LineData& data);
	void PushCommand (const NCOMLINE::CommandMap& data);
	void RemoveLine (void);

public:
	CCommandLineServer (void);//,bool startclient = false);
	~CCommandLineServer (void);
	
	bool Inited (void) const
	{ return m_Inited; }
	void ExecuteLine (const char * line);
	void PushLine (const char *line);
	int	 NumOutputLines(void);
	void GetOutputLine(int size,unsigned char * pszString);

	bool AddCommand (NCOMLINE::ComFunc func,const CCom_String& name);
	bool RemoveCommand (const CCom_String& name);
};


#endif

#endif