'Example program for the Network Client/Server command library
'Creates a chat client and connects to the chat server.

$include "NCS_chat.inc"

'variables
int DataSocket = -1
window chat
dialog chat_params
string nickname
string serverIP = "127.0.0.1"
int serverPort = server_port
int Authorized = FALSE
int ncsStatus
InitChatParamDialog()
'Open window and create the controls
OpenWindow chat,0,0,305,300,0x80CA0080, 0, "NCS Chat Client", &ChatHandler
SetWindowColor chat,RGB(0,38,200)

'intialize client/server library
'Only 1 datasocket needed for this example
NCSInit(1,0)
'show the connection dialog
if DoModal(chat_params,chat) = @IDOK
	'Attempt to connect to server
	AppendEdit(chat,CHAT_DISPLAY,"Client Server Library initialized",TRUE)
	ncsStatus = NCSConnectToServer(ServerIP,ServerPort)
	if ncsStatus < 0
		AppendEdit(chat,CHAT_DISPLAY,"Error connecting to server",TRUE)
		AppendEdit(chat,CHAT_DISPLAY,NCSGetErrorText(),TRUE)
	else
		'Register a message to be sent when data is read to be retrieved
		DataSocket = ncsStatus
		AppendEdit(chat,CHAT_DISPLAY,"Connected to server, IP = "+ServerIP,TRUE)
		ncsStatus=NCSOnDataMessage(chat.hWnd, DataSocket, msg_ServerData)
		if ncsStatus < 0
			AppendEdit(chat,CHAT_DISPLAY,"NCSOnDataMessage error",TRUE)
			AppendEdit(chat,CHAT_DISPLAY,NCSGetErrorText(),TRUE)
		endif
	endif

endif

waituntil IsWindowClosed(chat)
if DataSocket > -1
	NCSCloseSocket(DataSocket)
endif
NCSFree()
end

sub ChatHandler
	string text
	Select @Message
		Case @IDCreate
			CenterWindow chat
			CONTROL chat,@RICHEDIT,"",14,14,273,214,0x50A00844,CHAT_DISPLAY
			CONTROL chat,@EDIT,"",15,239,272,23,0x50800000|@CTEditAutoH,CHAT_TEXT_ENTER
			SetControlNotify chat, CHAT_TEXT_ENTER, false, true
			ControlCmd chat,CHAT_DISPLAY,@RTSETDEFAULTFONT,"Arial",9,0,0
			SetFont chat, "Arial",8,400,0,CHAT_TEXT_ENTER
			RedrawFrame chat,CHAT_DISPLAY		
		Case @IDCloseWindow
			if DataSocket > -1
				'let the server know we are closing
				text = "("+Nickname+") left chat"
				SendData2ChatServer(Xfer_Type_ChatSend,text,len(text)+1)
				SendData2ChatServer(Xfer_Type_ClientDisconnect,NULL,0)
			endif
			CloseWindow chat
		Case @IDControl
			Select @ControlID
				Case CHAT_TEXT_ENTER
					if @NotifyCode = @EnEnterKey
						text = nickname +": "+GetControlText(chat,CHAT_TEXT_ENTER)
						SetControlText chat,CHAT_TEXT_ENTER,""
						if DataSocket > -1
							SendData2ChatServer(Xfer_Type_ChatSend,text,len(text)+1)
						endif
					endif
			EndSelect
		Case msg_ServerData
			ProcessDataFromServer()
	Endselect
endsub

Sub ProcessDataFromServer()
	int xfercode
	int datalen
	int ncsStatus
	char buffer[max_data_transfer]
	pointer pBuffer=&buffer
	'read the header
	ncsStatus = NCSReadData(DataSocket,pBuffer,len(chat_packet_header),0)
	if ncsStatus < len(chat_packet_header)
		'couldnt read the header, bad packet or error
		return
	else
		xfercode = #<int>pBuffer:pBuffer+=4
		datalen = #<int>pBuffer:pBuffer+=4
		if datalen
			if datalen > (max_data_transfer - len(chat_packet_header))
				'datalen exceeds maximum transfer, ignore the packet
				return
			else
				ncsStatus = NCSReadData(DataSocket,pBuffer,datalen,0)
				if ncsStatus < datalen
					'bad packet or error
					return
				endif
			endif
		endif
		'ok if we got here then we successfully read a packet from a client.
		if Authorized
			select xfercode
				case Xfer_Type_ChatSend
					AppendEdit(chat,CHAT_DISPLAY,#<string>pBuffer,TRUE)
				case Xfer_Type_ServerClosing
					AppendEdit(chat,CHAT_DISPLAY,"---Server closing, Chat ended",TRUE)
					NCSCloseSocket(DataSocket)
					DataSocket = -1
			endselect
		else
			if xfercode = Xfer_Type_Challenge
				string Response = NCSCreateResponseString(#<string>pBuffer,RESP_MULT,RESP_MASK)
				SendData2ChatServer(Xfer_Type_Response,Response,len(Response)+1)
			elseif xfercode = Xfer_Type_ClientApproved
				Authorized = TRUE
				AppendEdit(chat,CHAT_DISPLAY,"---Authenticated, Entering chat mode",TRUE)
				string text = "("+Nickname+")"+" Entering chat"
				SendData2ChatServer(Xfer_Type_ChatSend,text,len(text)+1)
			elseif xfercode = Xfer_Type_ConnectionRefused
				AppendEdit(chat,CHAT_DISPLAY,"---Connection refused by server",TRUE)
				NCSCloseSocket(DataSocket)
				DataSocket = -1
			else
				'disconnect the client, the only valid code would be Xfer_Type_Challenge
				'So either this isn't a chat server, or a server didn't challenge properly
				NCSCloseSocket(DataSocket)
				DataSocket = -1
			endif
		endif
	endif
	if DataSocket > -1
		'rearm the registered data message
		ncsStatus=NCSOnDataMessage(chat.hWnd, DataSocket, msg_ServerData)	
	endif
Endsub

Sub SendData2ChatServer(int xfercode, pointer buffer, int datalen)
	int ncsStatus
	char xferbuffer[max_data_transfer]
	pointer pxfer = &xferbuffer
	if len(chat_packet_header) + datalen > max_data_transfer
		return
	endif
	#<chat_packet_header>pxfer.xfercode = xfercode
	#<chat_packet_header>pxfer.datalen = datalen
	pxfer += len(chat_packet_header)
	if buffer AND datalen
		'copy the data
		RtlMoveMemory(pxfer,buffer,datalen)
	endif
	ncsStatus = NCSSendData(DataSocket,&xferbuffer,len(chat_packet_header) + datalen )
	if ncsStatus < -1
		'log the error
		AppendEdit(chat,CHAT_DISPLAY,"Error sending data to server Errorcode:"+str$(NCSGetLastError),TRUE)
	endif
Endsub

'The char parameters dialog
CONST EDIT_ADDRESS = 10
CONST BUTTON_OK = 1
CONST BUTTON_CANCEL = 2
CONST EDIT_PORT = 11
CONST EDIT_NICKNAME = 12

SUB InitChatParamDialog
	CREATEDIALOG chat_params,0,0,362,171,0x80C80080,0,"Connect to Chat Server",&chat_params_handler
	CONTROL chat_params,@EDIT,ServerIP,86,34,191,21,0x50800000,EDIT_ADDRESS
	CONTROL chat_params,@BUTTON,"Connect",83,132,70,20,0x50000000,BUTTON_OK
	CONTROL chat_params,@SYSBUTTON,"Cancel",209,132,70,20,0x50000000,BUTTON_CANCEL
	CONTROL chat_params,@STATIC,"Address",28,36,53,16,0x5000010B,99
	CONTROL chat_params,@EDIT,ltrim$(str$(serverPort)),85,66,70,20,0x50802000,EDIT_PORT
	CONTROL chat_params,@STATIC,"Port",33,68,36,16,0x5000010B,100
	CONTROL chat_params,@EDIT,"",85,99,191,20,0x50800000,EDIT_NICKNAME
	CONTROL chat_params,@STATIC,"Nickname",20,101,52,17,0x5000010B,101
Endsub

SUB chat_params_handler
	SELECT @MESSAGE
		CASE @IDINITDIALOG
			CENTERWINDOW chat_params
			/* Initialize any controls here */
		CASE @IDCLOSEWINDOW
			CLOSEDIALOG chat_params,@IDCANCEL
		CASE @IDCONTROL
			SELECT @CONTROLID
				CASE EDIT_ADDRESS
				/* respond to edit notifications here */
				CASE EDIT_PORT
				/* respond to edit notifications here */
				CASE BUTTON_OK
					IF @NOTIFYCODE = 0
						ServerIP = GetControlText(chat_params,EDIT_ADDRESS)
						ServerPort = VAL(GetControlText(chat_params,EDIT_PORT))
						Nickname = GetControlText(chat_params,EDIT_NICKNAME)
						CloseDialog chat_params,@IDOK
					ENDIF
				CASE BUTTON_CANCEL
					IF @NOTIFYCODE = 0
						CloseDialog chat_params,@IDCancel
					ENDIF
			ENDSELECT
	ENDSELECT
RETURN
ENDSUB

'subroutine to easily append text in an edit control.
CONST WM_GETTEXTLENGTH = 0xE
Sub AppendEdit(window win,int id,string text,int addNL)
	int _textlen:_textlen =SendMessage(win, WM_GETTEXTLENGTH,0,0,id)
	ControlCmd win, id, @EDSETSELECTION, _textlen, _textlen
	if(addNL)
		ControlCmd win, id, @EDREPLACESEL, text + "\n"
	else
		ControlCmd win, id, @EDREPLACESEL, text
	endif
Endsub

