#include <cstring>

#include "new.h"
#include "shell.h"

#define ISO_nl       0x0a
#define ISO_cr       0x0d

#define SHELL_PROMPT "PTO, aye -->"

using namespace std;

char foo = 0;
char bar;

#if 0
template <class T>
bool from_string(T& t, const std::string& s, ios_base& (*f)(ios_base&))
{
  stringstream ss(s);
  return !(ss >> f >> t).fail();
}
#endif


char* Shell::allocLine(void)
{
	return (new char[LineLength]);
}

void Shell::deallocLine(char* line)
{
	delete line;
}

void Shell::version(char* str)
{
	shellOutput("Build of October 10, 2012","");
}

void Shell::inttostr(char* str, uint32_t i)
{
	str[0] = '0' + i / 100;
	if(str[0] == '0') {
		str[0] = ' ';
	}
	str[1] = '0' + (i / 10) % 10;
	if(str[0] == ' ' && str[1] == '0') {
		str[1] = ' ';
	}
	str[2] = '0' + i % 10;
	str[3] = ' ';
	str[4] = 0;
}

void Shell::pinheadQuote(char* str)
{

}

void Shell::inform(char* str)
{
}

void Shell::timeAtDepth(char* str)
{
}

void Shell::holdThisDepth(char* str)
{
}

void Shell::startAfter(char* str)
{
}

void Shell::parse(char* str)
{

	struct command* p;
	char* command = strtok(str," ,");
	char* arguments = strtok(NULL," ,");
	static struct command commandTable[] = {
		{"zippy",		&Shell::pinheadQuote	},
		{"depth",    	&Shell::holdThisDepth	},
		{"time", 		&Shell::timeAtDepth		},
		{"start",    	&Shell::startAfter		},
		{"inform",    	&Shell::inform 			},
		{"version", 	&Shell::version			},
		{"?",       	&Shell::help			},
		// Default action
	    {reinterpret_cast<const char*>(NULL), &Shell::unknown}
	};

	if (strncmp(str, "\n", 1)) {
		for (p = &commandTable[0]; p->commandString != NULL; ++p) {
			if (strncmp(p->commandString, command, strlen(p->commandString)) == 0) {
				break;
			}
		}
		ShellMemberFunction tmf = p->commandFunction;
		(*this.*tmf)((p->commandFunction != &Shell::unknown) ? arguments : str);
	}
}

void Shell::help(char* str)
{
	shellOutput("******************************* 10 BASE T ONLY     **********************************","");
	shellOutput("*************************************************************************************","");
	shellOutput("Available commands:", "");
	// shellOutput("current                   - Set a fixed output current","");
	shellOutput("data   actual | canned    - Returns actual or canned data","");
	shellOutput("exit                      - exit shell", "");
	shellOutput("getepsilon                - Get the epsilon in distance change","");
	shellOutput("help, ?                   - Displays a list of commands", "");
	shellOutput("pump   on | off           - Turn the pump on or off.","");
	shellOutput("relay  close | open       - Close or open safety relay.","");
	shellOutput("sensors                   - Returns uncalibrated sensor outputs.","");
	shellOutput("Setepsilon                - Set the epsilon for distance change","");
	shellOutput("version                   - Returns Time and Date of Build", "");
	shellOutput("***********************************************************************************","");
}

void Shell::unknown(char* str)
{
	if(strlen(str) > 0) {
		shellOutput("Unknown command: ", str);
	}
}

void Shell::shellStart(void)
{
	shellOutput("Those who believe in telekinetics, raise my hand...","");
	shellOutput("Type '?' for a list of commands", "");
	shellPrompt(SHELL_PROMPT);
}

void Shell::shellInput(char* cmd)
{
	parse(cmd);
	shellPrompt(SHELL_PROMPT);
}

void Shell::sendLine(char* line)
{
	uint32_t i;
	for (i = 0; i < NumberOfLines; ++i) {
		if(_lines[i] == NULL) {
		  _lines[i] = line;
		  break;
		}
	}
	if (i == NumberOfLines) {
		deallocLine(line);
	}
}

void Shell::shellPrompt(const char* str)
{
	char *line;
	line = allocLine();
	if(line != NULL) {
		strncpy(line, str, LineLength);
		sendLine(line);
	}
}

void Shell::shellOutput(const char* str1, const char* str2)
{
	uint32_t 	len;
	char*		line;

	line = allocLine();
	if(line != NULL) {
		len = strlen(str1);
		strncpy(line, str1, LineLength);
		if(len < LineLength) {
			strncpy(line + len, str2, LineLength - len);
		}
		len = strlen(line);
		if(len < LineLength - 2) {
			line[len] = ISO_cr;
			line[len+1] = ISO_nl;
			line[len+2] = 0;
		}
	sendLine(line);
	}
}

bool Shell::Run(bool whatever)
{

    BEGIN();
	_aUart.Open(115200);
	while(1) {
#if 0
		WAIT_UNTIL(_aUart.TransmitterEmpty());
		_aUart.Send(foo);
		WAIT_UNTIL(_aUart.ReceiverNonEmpty());
		bar = _aUart.Receive();
		if (foo != bar)
			for (;;) ;
		foo++;
#else
		WAIT_UNTIL(_aUart.ReceiverNonEmpty());
		foo = _aUart.Receive();
		WAIT_UNTIL(_aUart.TransmitterEmpty());
		_aUart.Send(foo);
#endif
	}
    END();

	return false;
}

void Shell::getChar(uint8_t c)
{
	if (c == ISO_cr) {
		return;
	}
	_buf[(int)_bufptr] = c;
	if (_buf[(int)_bufptr] == ISO_nl || _bufptr == sizeof(_buf) - 1) {
		if(_bufptr > 0) {
			_buf[(int)_bufptr] = 0;
		}
		shellInput(_buf);
		_bufptr = 0;
	} else {
		++_bufptr;
	}
}

