#include "cygwin.h"
#include "donkey.h"
#include "sCommand.h"
#include "sSocket.h"
#include "sGui.h"
#include "misc.h"
#include "protocol.h"
#include "sFile.h"
#include "sPacket.h"
#include "kademlia.h"

unsigned int	sCommand::count = 0;

const char command_help[] = 	"cDonkey\n"
				"Author: thomas@suche.org\n"
				"Text commands:\n"
				"- debug level <INTEGER>      (debuging)\n"
				"- protocol level <INTEGER>   (debuging)\n"
				"- CLIENT_COUNT <INTEGER>     (debuging)\n"
				"- TCP_CLIENT_COUNT <INTEGER> (should go to gui options)\n"
				"- TCP_SERVER_COUNT <INTEGER> (maybe gui option later)\n"
				"- dumax <INTEGER> <INTEGER>  (dl / ul in kByte per Second)\n"
				"- password <STRING>          (not yet saved :-( )\n"
				"- help                       (this screen)\n"
				"- quit                       (command line exit)\n"
				"- shutdown                   (shutdown the core)\n"
				"- ed2k://*                   (add ed2k links (file/server)\n"
				"- dllink ed2k://*            (add ed2k links (file/server)\n"
				"- mcon <INTEGER>             (maximum tcp connections)\n"
				"- s <Keyword List>\n"
				"  (spezials: '-video' '-audio' '-doc' '-prc')\n"
				;

const unsigned char Query_Username[] = "Please Enter Username: ";
				
sCommand::sCommand        (class cSocket *FD_new, struct in_addr, uint16_t) : sSocket(FD_new) {{{
	Type = tCommand;
	count++;
	m_pEOL = "\n";
	auth = 0;
	user = NULL;
	pass = NULL;
	Write (Query_Username, strlen(reinterpret_cast<const char*>(Query_Username)));
	if (mask != 0) doWork(mask);
	}}}
sCommand::~sCommand        (void) {{{
	count--;
	if (pass != NULL) Free2 (pass);
	if (user != NULL) Free2 (user);
	}}}
int  sCommand::doRead_high   (void) {{{
	unsigned len = 0;
	unsigned skip = 0;
	for (; len < read_len; len++) {
		if (read_buf[len] != '\n' && read_buf[len] != '\r') 
			break;
		skip++;
		}
	if (skip > 0)
		Read(read_buf, skip);
	for (len = 0; len < read_len; len++) {
		if (read_buf[len] == '\n' || read_buf[len] == '\r') 
			break;
		}
	if (len == read_len) return 0;
	if (len> 511) {
		Read(read_buf, len);
		return 0;
		}
	char buffer[512];
	Read(reinterpret_cast<unsigned char*>(buffer), len);
	buffer[len]=0;
	
	if (auth == 0) {{{
		// determine EOL string to use
		if( read_len >= 2 && read_buf[0] == '\r' && read_buf[1] == '\n' )
			m_pEOL = "\r\n";
		// Check the user, but only remember the check
		if ( 0 != strcmp (ctrl_user, buffer) ) 	auth = 666;
		else						auth = 1;
		WriteString("Please Enter Password: ");
		return 1;
		}}}
	if (auth == 666) {{{	// do not show the user is user or password is wrong
		Close();
		return 0;
		}}}
	if (auth == 1) {{{	// check if passwort is correct too
		if ( 0 != strcmp (ctrl_pass, buffer) ) {
			Close();
			return 0;
			}
		auth = 2;
		WriteString("> ");
		return 1;
		}}}
	if (auth != 2) return 0; // After here onlz validated user
	if (0 == strcmp("quit", buffer)) {{{
		WriteString("close Connection !\n");
		Close();
		return 1;
		}}}
	const char *msg = Execute(buffer);
	WriteString( msg );
	WriteString("> ");
	return 1;
	}}}

bool sCommand::WriteString( const char* pStr ) {{{
	const char* 	pStart 	= pStr;
	const char* 	pEnd 	= pStr;
	size_t 		len 	= strlen( pStr );
	size_t 		eol_len = strlen( m_pEOL );
	if( len     <= 0 ) return false;
	if( eol_len <= 0 ) return Write(reinterpret_cast<const unsigned char*>(pStr), len );
	while( *pEnd != 0 )	{
		if( *pEnd == '\n' ) {
			if( pEnd > pStart )	Write(reinterpret_cast<const unsigned char*>(pStart), (pEnd - pStart) );
			Write(reinterpret_cast<const unsigned char*>(m_pEOL), eol_len );
			pStart = pEnd + 1;
			}
		pEnd++;
		}
	if( pEnd > pStart )	Write(reinterpret_cast<const unsigned char*>(pStart), (pEnd - pStart) );
	return true;
	}}}

const char *sCommand::Execute  (const char *text) {
static	char out [128];
	int len = 0;
	if (0 == strncasecmp ("debug level "     , text, strlen ("debug level "     ))) {{{
		int old = pref.verbose;
		pref.verbose = atoi (text + strlen("debug level "));
		len = snprintf(out, 128, "debug log level old/new = %i/%i\n", old, pref.verbose);
		goto done;
		}}}
	if (0 == strncasecmp ("protocol level "  , text, strlen ("protocol level "  ))) {{{
		protocol_logLevel = atoi (text + strlen("protocol level "));
		len = snprintf(out, 128, "protocol log level = %i\n", protocol_logLevel);
		goto done;
		}}}
	if (0 == strncasecmp ("mcon "            , text, strlen ("mcon "            ))) {{{
		TCP_CLIENT_COUNT = atoi (text + strlen("mcon "));
		TCP_SERVER_COUNT = atoi (text + strlen("mcon "));
		len = snprintf(out, 128, "max connection = %i\n", TCP_CLIENT_COUNT);
		goto done;
		}}}
	if (0 == strncasecmp ("TCP_CLIENT_COUNT ", text, strlen ("TCP_CLIENT_COUNT "))) {{{
		TCP_CLIENT_COUNT = atoi (text + strlen("TCP_CLIENT_COUNT "));
		len = snprintf(out, 128, "TCP client count = %i\n", TCP_CLIENT_COUNT);
		goto done;
		}}}
	if (0 == strncasecmp ("TCP_SERVER_COUNT ", text, strlen ("TCP_SERVER_COUNT "))) {{{
		TCP_SERVER_COUNT = atoi (text + strlen("TCP_SERVER_COUNT "));
		len = snprintf(out, 128, "TCP client count = %i\n", TCP_SERVER_COUNT);
		goto done;
		}}}
	if (0 == strncasecmp ("CLIENT_COUNT "    , text, strlen ("CLIENT_COUNT "    ))) {{{
		CLIENT_COUNT = atoi (text + strlen("CLIENT_COUNT "));
		len = snprintf(out, 128, "TCP client count = %i\n", CLIENT_COUNT);
		goto done;
		}}}
	if (0 == strncasecmp ("dumax "           , text, strlen ("dumax "           ))) {{{
		long ul = 0;
		long dl = 0;
		char *tmp = NULL;
		dl = strtol (text + strlen ("dumax "), &tmp, ul);
		ul = strtol (tmp + 1, &tmp, ul);
		if (ul * 10 >= dl) {
			ulSecond = ul * 1024;
			dlSecond = dl * 1024;
			}
		len = snprintf(out, 128, "New UL/DL Speed %li/%li\n", ul, dl);
		goto done;
		}}}
	if (0 == strncasecmp ("pass "            , text, strlen ("pass "            ))) {{{
		Free2 (ctrl_pass);
		ctrl_pass = STRDUP (text+ strlen ("pass "));
		len = snprintf(out, 128, "New Pass %s\n", ctrl_pass);
		goto done;
		}}}
	if (0 == strncasecmp ("help"             , text, strlen ("help"             ))) {{{
		return command_help;
		}}}
	if (0 == strncasecmp ("shutdown"         , text, strlen ("shutdown"         ))) {{{
		running = false;
		len = snprintf(out, 128, "Core will quit now\n");
		goto done;
		}}}
	if (0 == strncasecmp ("ed2k"             , text, strlen ("ed2k"	            ))) {{{
		if (split_link (text)) 	 len = snprintf(out, 128, "Added link: %s\n", text);
		else			 len = snprintf(out, 128, "Failed to parse %s\n", text);
		goto done;
		}}}
	if (0 == strncasecmp ("dllink "          , text, strlen ("dllink"           ))) {{{
		const char* ed2k_string = text + strlen("dllink ");
		if (split_link (ed2k_string))
			len = snprintf(out, 128, "Added link: %s\n", ed2k_string);
		else	len = snprintf(out, 128, "Failed to parse %s\n", text);
		goto done;
		}}}
	if (0 == strncasecmp ("vc "              , text, strlen ("vc"               ))) {{{
		len = snprintf(out, 128, "%u contacts", overnet.getNumContacts());
		goto done;
		}}}
	if (0 == strncasecmp ("s "               , text, strlen ("s"                ))) {{{
		manager.findKeywords(text + strlen("s "));
		len = snprintf(out, 128, "searching...");
		goto done;
		}}}
	if (0 == strncasecmp ("g", text, strlen ("g"))) {{{
		GUI_LIST akt->GUI_txt_g();
	        goto done;
        	}}}
	len = snprintf(out, 128, "Unknown command %s\n", text);
	printf("UNKNOWN ext command %s\n", text);
done:	if (len >= 128) printf("%s output buffer to small (%i)\n", __PRETTY_FUNCTION__, len);
	return out;
	}

/*
 * vim600: fdm=marker
 */
