#include <stdint.h>
#include <signal.h>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include "socket.h"
#include "socket_stream.h"
#include "user_interface_thread.h"

using namespace std;

UserInterfaceThread:: UserInterfaceThread (
	uint16_t telnetPortNumber,
	uint16_t winchPortNumber,
	uint16_t levelWindPortNumber,
	ControlThread&  controller)
	: m_Controller(controller),
	  m_TelnetPortNumber(telnetPortNumber),
	  m_WinchPortNumber(winchPortNumber),
	  m_LevelWindPortNumber(levelWindPortNumber)
{
}

UserInterfaceThread::~UserInterfaceThread(void)
{
}

void* UserInterfaceThread::Run(void* parameter)
{
	m_MotionControlMoxaIP_Address = (char *) parameter;

	try {
		tcp_listener tl(m_TelnetPortNumber);

		tl.listen();
		cout << "LISTENING on " << tl.my_endpoint() << endl;

		tcp_socket s = tl.accept();
		cout << "CONNECTION from "  << s.peer() << endl;
		s.set_input_formatter(new line_input_formatter());

		for (;;)
			processCommands(s);       // Wait for someone to connect
	}
	catch (socket_error_ex& e) {
		cout << "Exception: " << e.what() << endl;
		cout << "Err=" << e.whaterr() << endl;
		cout << "Txt=" << e.whatsystext() << endl;
	}
	catch (socket_error& e) {
		cout << "Exception: " << e.what() << endl;
	}
	return 0;
}

void UserInterfaceThread::processCommands(tcp_socket& telnetSocket)
{
	uint32_t	bytesReceived;

	tcp_client_socket	winch(endpoint(m_MotionControlMoxaIP_Address, m_WinchPortNumber));
	tcpstream			winchStream(winch);

	tcp_client_socket	levelWind(endpoint(m_MotionControlMoxaIP_Address, m_LevelWindPortNumber));
	tcpstream			levelWindStream(levelWind);

	const char	*prompt			= "\n==> ";
	const char	*howdyMessage	= "Howdy, pardner";
	const char	*errorMessage	= "What?";

	try {
		string 				request;
		string 				response;
		string 				command;
		string::size_type	position;

		winch.set_output_formatter(new line_output_formatter());
		levelWind.set_output_formatter(new line_output_formatter());
		for (;;) {
			telnetSocket.send(prompt,strlen(prompt));
			bytesReceived = telnetSocket.recv(request);
			if (bytesReceived > 0) {
				position = 0;
				command = nextToken(request," \t\r\n", position);
				if (command == "wm") {
					position = position + 1;
					command = nextToken(request, "\r\n", position);
					winchStream << command << endl;
					bytesReceived = winch.recv(response);
					if (bytesReceived >= 0) {
						telnetSocket.send(response);
					}
				} else if (command == "lw") {
					position = position + 1;
					command = nextToken(request, "\r\n", position);
					levelWindStream << command << endl;
					bytesReceived = levelWind.recv(response);
					if (bytesReceived >= 0) {
						telnetSocket.send(response);
					}
				} else if (command == "Howdy") {
					telnetSocket.send(howdyMessage,strlen(howdyMessage));
				} else {
					telnetSocket.send(errorMessage,strlen(errorMessage));
				}
			}
		}
	}
	catch (socket_error_ex& e) {
		cout << "Exception: " << e.what() << endl;
		cout << "Err=" << e.whaterr() << endl;
		cout << "Txt=" << e.whatsystext() << endl;
	}
	catch (socket_error& e) {
		cout << "Exception: " << e.what() << endl;
	}
}

string UserInterfaceThread::nextToken(const string& line,
		const string& delim,
		string::size_type& first)
{
	string::size_type last = line.find_first_of(delim, first);
	string next(line.substr(first, last));
	first = last;
	return next;
}
