/*
 *      Code from:              Philipp Meinen
 *      Copyright (C):          2003-2004 Philipp Meinen
 *
 *      Email:                  lancelot@lancelot2k.dyndns.org
 *      Homepage:               http://lancelot2k.dyndns.org
 *      License:                GPL
 *                                                      */

#define _SCREEN_CC_
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <curses.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "screen.h"

Screen::Screen(void)
{
	MainScreen  = NULL;
	TextScreen  = NULL;
	InfoBottom  = NULL;
	InfoTop     = NULL;
	InputScreen = NULL;
	redraw_screen_from_scratch = 0;
	//noecho();
	InputBuffer = new char[INPUT_LEN_MAX+1];
	InputBuffer[0] = '\0';
	num_textscreen_redraws = 0;
	/* Server-screen */
	active_channel = 0;
	first_print_msg = 0;
	/* initialize the structure screeninfo */
        for(int i = 0; i < CHANNELS_MAX; i++)
        {
		screen_info[i].used = screen_info[i].type = 0;
		screen_info[i].channel_name[0] = '\0';
		screen_info[i].channel_topic[0] = '\0';
		screen_info[i].directchat_nickname[0] = '\0';
        }
	screen_info[0].used = 1;
	screen_info[0].type = 0;
	bold_started = 0;
	underline_started = 0;
	strncpy(screen_info[0].channel_name, "Server messages", CHANNELS_NAME_LEN-1);
	MakeAllWindow(0);
	return;
}

Screen::~Screen(void)
{
	EndNcurses();
	if(InputBuffer)
		delete[] InputBuffer;
	return;
}

void Screen::DrawTopScreen(void)
{
	CheckScreenForRedraw();
	werase(InfoTop);
	int textsize = COLSnow - 9;
	char buffer[textsize];
	if(screen_info[active_channel].used) {
		if(screen_info[active_channel].type) {
			/* direct chat */
			snprintf(buffer, textsize, "screen %i - Direct-Chat with User: %s", active_channel, screen_info[active_channel].directchat_nickname);
		} else {
			/* normal channel */
			if(active_channel == 0) {
				snprintf(buffer, textsize, "%s", screen_info[active_channel].channel_name);
			} else {
				snprintf(buffer, textsize, "screen %i - #%s Topic: %s", active_channel,
						screen_info[active_channel].channel_name, screen_info[active_channel].channel_topic);
			}
		}
	} else {
		/* not used screen */
		snprintf(buffer, textsize, SCREEN_NOT_USED);
	}
	InfoTop->_cury = InfoTop->_curx = 0;
	whline(InfoTop, 0, 5);
	InfoTop->_curx = 5;
	wprintw(InfoTop, "%s", buffer);
	InfoTop->_curx = 5 + strlen(buffer);
	whline(InfoTop, 0, COLSnow-(InfoTop->_curx));
	wrefresh(InfoTop);
	SetCursorToInputScreen();
	return;
}

void Screen::DrawBottomScreen(void)
{
	CheckScreenForRedraw();
	werase(InfoBottom);
	int textsize = COLSnow - 24;
	InfoBottom->_cury = InfoBottom->_curx = 0;
	whline(InfoBottom, 0, 15);
	InfoBottom->_curx = 15;
	char * channel_str_ptr = MakeScreenString(0);
	char * dchat_str_ptr = MakeScreenString(1);
	int num_users = 0;
	if(channel_str_ptr)
		num_users = Classes.IrcUserDB->Get_Num_Users_in_Channel(GetChannelName(active_channel));
	char * nickname = Classes.IrcUser->GetNickname();
	if(textsize >= HELP_BUF_LEN) textsize = HELP_BUF_LEN - 1;
	if(channel_str_ptr && ! dchat_str_ptr) { /* only channel */
		snprintf(help_buffer, HELP_BUF_LEN, " %s - %i Users - Screens: (%s|)", nickname, num_users, channel_str_ptr);
	} else if(!channel_str_ptr && dchat_str_ptr) { /* only direct chat */
		snprintf(help_buffer, HELP_BUF_LEN, " %s - Screens: (|%s)", nickname, dchat_str_ptr);
	} else if(channel_str_ptr && dchat_str_ptr) { /* both, direct chat and channels */
		snprintf(help_buffer, HELP_BUF_LEN, " %s - %i Users - Screens: (%s|%s)", nickname, num_users, channel_str_ptr, dchat_str_ptr);
	} else { /* no channel or direct chat */
		snprintf(help_buffer, HELP_BUF_LEN, "%s - no Screens!", nickname);
	}
	int num = print_format_text(InfoBottom, help_buffer, textsize);
	InfoBottom->_curx = 15 + num;
	whline(InfoBottom, 0, COLSnow - (InfoBottom->_curx));
	wrefresh(InfoBottom);
	if(channel_str_ptr) delete[] channel_str_ptr;
	if(dchat_str_ptr) delete[] dchat_str_ptr;
	SetCursorToInputScreen();
	return;
}

void Screen::DrawTextScreen(void)
{
	CheckScreenForRedraw();
	if(!Classes.MsgDB->GetChange(active_channel)) return; /* screen not altered */
	Classes.MsgDB->SetChange(active_channel, 0);
	num_textscreen_redraws++;
	/* count how many messages we can print on the screen */
	int messages_to_print = MessagesToPrint();
	werase(TextScreen);
	TextScreen->_curx = TextScreen->_cury = 0;
	for(int i = messages_to_print+first_print_msg-1; i >= first_print_msg; i--)
	{
		/* print 1 line */
		char * text = Classes.MsgDB->GetMessage(active_channel, i);
		if(text != NULL) {
			if(!Classes.MsgDB->GetFormatOptions(active_channel, i)) {
				/* we dont have anything to formate, veeery nice :) */
				wprintw(TextScreen, "%s\n", text);
			} else {
				/* we do have something to format
				 * so I print the Message Titel and then allways only 1 char and check the next one if he is a format char */
				print_format_text(TextScreen, text, LINEBUF_LEN);
			}
		} /* enf of "if(text != NULL)"*/
	} /* end of "for(int i = messages_to_print+first_print_msg-1; i >= first_print_msg; i--)" */
	wrefresh(TextScreen);
	SetCursorToInputScreen();
	return;
}

void Screen::DrawInputScreen(void)
{
	CheckScreenForRedraw();
	werase(InputScreen);
	if(strlen(InputBuffer) <= (unsigned)COLSnow) {
		/* Just print the buffer when enough space is available */
		wprintw(InputScreen, "%s", InputBuffer);
	} else {
		/* Make a new text for printing */
		int input_len = strlen(InputBuffer)-1;
		char TextToPrintOut[COLSnow];
		for(int i = COLSnow-1; i >= 0; i--)
		{
			TextToPrintOut[i] = InputBuffer[input_len];
			input_len--;
		}
		wprintw(InputScreen, "%s", TextToPrintOut);
	}
	wrefresh(InputScreen);
	return;
}

void Screen::GetInput(void)
{
	CheckScreenForRedraw();
	char buf[INPUT_LEN_MAX];
	int num_read = read(0, buf, INPUT_LEN_MAX); /* Read from stdin */
	if(num_read < 1) return;
	buf[num_read] = '\0';
	int ret = Test_Input_for_special_Chars(buf);
	if(ret == 1) {
		if(InputBuffer == '\0') return; /* return when enter is pressed but no input given */
		/* Input Data is ready, parse it */
		if(InputBuffer[0] == '/') {
			ParseCommandToServer(NULL);
			InputBuffer[0] = '\0';
			werase(InputScreen);
			wrefresh(InputScreen);
		} else if(active_channel) {
			/* this is a message for a channel or a direct chat */
			if(screen_info[active_channel].used) {
				/* screen is used */
				if(!screen_info[active_channel].type) {
					/* message for a channel */
					snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG #%s :%s",
							screen_info[active_channel].channel_name, InputBuffer);
				} else {
					/* direct message */
					snprintf(help_buffer, HELP_BUF_LEN, "PRIVMSG %s :%s",
							screen_info[active_channel].directchat_nickname, InputBuffer);
				}
				Classes.Connection->WriteMessageToServer(help_buffer);
				Classes.MsgDB->SetIrcChatMessage(active_channel, Classes.IrcUser->GetNickname(), InputBuffer);
				InputBuffer[0] = '\0';
				werase(InputScreen);
				wrefresh(InputScreen);
				DrawTextScreen();
			} else {
				/* screen is not used */
				Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, "this screen is not used for a channel or a direct-chat");
				DrawTextScreen();
			}
		} else {
			/* this is on the server screen */
			Classes.MsgDB->SetIrcChatMessage(active_channel, DISPLAY_ERROR, "this is the server screen, you can only enter commands on this screen");
			DrawTextScreen();
		}
	} else {
		/* Input Data is not ready, user wants to write more chars */
		DrawInputScreen();
	}
	return;
}

void Screen::MakeAllWindow(int sigwinch)
{
	redraw_screen_from_scratch = 0;
	/* get the terminal size and store it in the ncurses variables "COLS" and "LINES" */
	struct winsize terminal;
	terminal.ws_row = terminal.ws_col = 0;
	ioctl(0, TIOCGWINSZ, &terminal);
	clearok(stdscr, TRUE);
	COLS = COLSnow = terminal.ws_col;
	LINES = LINESnow = terminal.ws_row;
	if(sigwinch) {
		endwin();
		refresh();
		doupdate();
		delwin(InfoTop);
		delwin(InputScreen);
		delwin(InfoBottom);
		delwin(TextScreen);
	} else {
		MainScreen = initscr();
	}
	InfoTop = newwin(1, COLSnow, 0, 0);
	InputScreen = newwin(1, COLSnow, LINESnow-1, 0);
	InfoBottom = newwin(1, COLSnow, LINESnow-2, 0);
	TextScreen = newwin(LINESnow-3, COLSnow, 1, 0);
	whline(InfoTop, 0, COLSnow);
	whline(InfoBottom, 0, COLSnow);
	/* now redraw this screens */
	DrawTopScreen();
	DrawBottomScreen();
	DrawInputScreen();
	DrawTextScreen();
	return;
}

int Screen::Test_Input_for_special_Chars(char * buf)
{
	/*	Some ansi codes
	 * 	F1:		27-91-49-49-126
	 * 	F2:		27-91-49-50-126
	 * 	F3:		27-91-49-51-126
	 * 	F4:		27-91-49-52-126
	 * 	F5:		27-91-49-53-126
	 * 	F6:		27-91-49-55-126
	 * 	F7:		27-91-49-56-126
	 * 	F8:		27-91-49-57-126
	 * 	F9:		27-91-50-48-126
	 * 	F10:		27-91-50-49-126
	 * 	F11:		27-91-50-51-126
	 * 	F12:		27-91-50-52-126
	 * 	F1:		27-79-80             in the programm 'screen'
	 * 	F2:		27-79-81             in the programm 'screen'
	 * 	F3:		27-79-82             in the programm 'screen'
	 * 	F4:		27-79-83             in the programm 'screen'
	 * 	Page-up:        27-91-53-126
	 *	Page-down:      27-91-54-126
	 *	Keyboard-up:    27-91-65
	 *	Keyboard-left:  27-91-68
	 *	Keyboard-right: 27-91-67
	 *	Keyboard-down:  27-91-66
	 *	Backspace:      127
	 *	Delete:         27-91-51-126
	 *	Tabulator:      9
	 *	Enter:          13
	 *	Control-l:      12 
	 *	Escape:         27    
	 *
	 *	This Function will set a '\0' for every char which I dont allow
	 *	On the end of this Function the text will be shrink together 
	 *	example:
	 *	   in this exampl the 4 chars '27'; '91'; '53'; '126' is a page-up
	 *	   input:
	 *			+-----+-----+-----+-----+-----+-----+-----+
	 *			|  a  | 27  | 91  | 53  | 126 |  b  | \0  |
	 *			+-----+-----+-----+-----+-----+-----+-----+
	 *	   after while: |  a  | \0  | \0  | \0  | \0  |  b  | \0  |
	 *	   		+-----+-----+-----+-----+-----+-----+-----+
	 *	   after shrink:|  a  |  b  | \0  |
	 *	   		+-----+-----+-----+
	 *										*/
	int len = strlen(buf);
	int cycle = -1;
	int return_value = 0;
	char *tmp = buf;
	int rest_len;
	do {
		cycle++;
		rest_len = len - cycle;
		if(rest_len >= 5) {
			if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[4] == 126)) { /* Possibly key between F1 and F12 */
				if((tmp[2] == 49) && (tmp[3] == 49)) { /* f1 */
					SetActiveChannel(1);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 50)) { /* f2 */
					SetActiveChannel(2);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 51)) { /* f3 */
					SetActiveChannel(3);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 52)) { /* f4 */
					SetActiveChannel(4);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 53)) { /* f5 */
					SetActiveChannel(5);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 55)) { /* f6 */
					SetActiveChannel(6);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 56)) { /* f7 */
					SetActiveChannel(7);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 49) && (tmp[3] == 57)) { /* f8 */
					SetActiveChannel(8);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 50) && (tmp[3] == 48)) { /* f9 */
					SetActiveChannel(9);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 50) && (tmp[3] == 49)) { /* f10 */
					SetActiveChannel(10);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 50) && (tmp[3] == 51)) { /* f11 */
					SetActiveChannel(11);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				} else if((tmp[2] == 50) && (tmp[3] == 52)) { /* f12 */
					SetActiveChannel(12);
					tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = '\0';
				}
			}
		}
		if(rest_len >= 4) {
			if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 53) && (tmp[3] == 126)) { /* Page Up */
				/* get a bit up */
				first_print_msg += 5;
				if(first_print_msg > NUM_LINES) first_print_msg = NUM_LINES;
				tmp[0] = tmp[1] = tmp[2] = tmp[3] = '\0';
				Classes.MsgDB->SetChange(active_channel, 1);
				DrawTextScreen();
			} else if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 54) && (tmp[3] == 126)) { /* Page Down */
				/* get a bit down when the screen isnt allready at the bottom */
				first_print_msg -= 5;
				if(first_print_msg <0) first_print_msg = 0;
				tmp[0] = tmp[1] = tmp[2] = tmp[3] = '\0';
				Classes.MsgDB->SetChange(active_channel, 1);
				DrawTextScreen();
			} else if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 51) && (tmp[3] == 126)) { /* delete */
				tmp[0] = tmp[1] = tmp[2] = tmp[3] = '\0';
			}
		}
		if(rest_len >= 3) {
			if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 65)) { /* keyboard-up */
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 68)) { /* keyboard-left */
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 67)) { /* keyboard-right */
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 91) && (tmp[2] == 66)) { /* keyboard-down */
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 79) && (tmp[2] == 80)) { /* f1 in programm 'screen' */
				SetActiveChannel(1);
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 79) && (tmp[2] == 81)) { /* f2 in programm 'screen' */
				SetActiveChannel(2);
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 79) && (tmp[2] == 82)) { /* f3 in programm 'screen' */
				SetActiveChannel(3);
				tmp[0] = tmp[1] = tmp[2] = '\0';
			} else if((tmp[0] == 27) && (tmp[1] == 79) && (tmp[2] == 83)) { /* f4 in programm 'screen' */
				SetActiveChannel(4);
				tmp[0] = tmp[1] = tmp[2] = '\0';
			}
		}
		if(rest_len >= 2) {
		}
		if(rest_len >= 1) {
			if(tmp[0] == 13) { /* 13 = '\n' => enter */
				/* User pressed enter, so parse his input */
				return_value = 1;
			} else if(tmp[0] == 127 || tmp[0] == 8) { /* Backspace -> ^? and ^H */
				if((tmp > buf) || (cycle > 0)) { /* this is not the first char in this stream so delete the one before */
					tmp[-1] = tmp[0] = '\0';

				} else {
					int len_now = strlen(InputBuffer);
					if(len_now > 0)
						InputBuffer[len_now-1] = '\0';
						tmp[0] = '\0';
				}
			} else if(tmp[0] == 12) { /* clean the current screen */
				tmp[0] = '\0';
				Classes.MsgDB->EmptyMessages(active_channel);
				DrawTextScreen(); /* and redraw the screen */
			} else if(tmp[0] == 27) { /* Escape -> go to screen 0 (Server messages) */
				tmp[0] = '\0';
				SetActiveChannel(0);
			}
		}
		tmp++; /* increase the pointer for the next cycle */
	} while((len - cycle) >= 5);
	for(int i = 0; i < len; i++) {
		if((unsigned int)buf[i] < 32 && (unsigned int)buf[i] > 0) buf[i] = '\0'; /* dont print this char */
	}
	/* shrink the '\0''s away */
	int position = 0;
	for(int i = 0; i < len; i++)
	{
		if(buf[i] != '\0') {
			buf[position] = buf[i];
			position++;
		}
	}
	buf[position] = '\0';
	/* now add this string to the input buffer */
	AddToInputBuffer(buf);
	return return_value;
}

void Screen::AddToInputBuffer(char * buf)
{
	int buf_len = strlen(buf);
	int pos = 0;
	int i;
	char * buffer = NULL;
	/* I want 4 spaces instead of 1 tab */
	int tab_num = 0;
	for(i = 0; i < buf_len; i++)
		if(buf[i] == 9) tab_num++; /* 9 = ansicode of tabulator */
	if(tab_num) {
		buffer = new char [((buf_len - tab_num) + (4 * tab_num) + 1)];
		for(i = 0; i < buf_len; i++)
		{
			if(buf[i] != 9) {
				buffer[pos] = buf[i];
				pos++;
			} else {
				buffer[pos] = buffer[pos+1] = buffer[pos+2] = buffer[pos+3] = ' ';
				pos += 4;
			}
		}
		buffer[pos] = '\0';
		buf_len = strlen(buffer);
	} else buffer = buf;
	/* I dont want '\r' or '\n' in the InputBuffer */
	pos = 0;
	char tmp_buf[buf_len+1];
	for(i = 0; i < buf_len; i++)
	{
		if(!(buffer[i] == '\r') && !(buffer[i] == '\n')) {
			tmp_buf[pos] = buffer[i];
			pos++;
		}
	}
	tmp_buf[pos] = '\0';
	int len_now = strlen(InputBuffer);
	int len_new = len_now + strlen(tmp_buf);
	int diff = 0;
	if(len_new > INPUT_LEN_MAX) len_new = INPUT_LEN_MAX;
	diff = len_new - len_now;
	strncat(InputBuffer, tmp_buf, diff);
	InputBuffer[len_new] = '\0';
	if(tab_num && buffer) delete[] buffer;
	return;
}

int Screen::MessagesToPrint(void)
{
	CheckScreenForRedraw();
	/* count how many messages we can print on the screen */
	if(!Classes.MsgDB->GetLinesNum(active_channel)) return 0;
	int num_lines_left = LINESnow-3;/* maximum count of possible messages */
	int control = 1;
	int message = first_print_msg;
	int messages_to_print = 0;   /* how many messages we have to print out */
	do {
		char * text = Classes.MsgDB->GetMessage(active_channel, message);
                if(text != NULL) {
			/* we have a text, now test how many lines we need to print this text */
                        int len = num_lines(strlen(text), COLSnow);
			if(num_lines_left > len) {
				/* we have enough space left to print out this text */
				num_lines_left -= len;
				messages_to_print++;
			} else if(num_lines_left == len) {
				/* we have exactly enough space to print the text */
				messages_to_print++;
				return messages_to_print;
			} else {
				/* there is not enough space to print this text, so we do not */
				return messages_to_print;
			}
			message++;
		} else return messages_to_print;
	} while(control);
	return messages_to_print;
}

void Screen::SetActiveChannel(int new_active_channel)
{
	CheckScreenForRedraw();
	if((new_active_channel < 0) || (new_active_channel >= CHANNELS_MAX)) return;
	Classes.MsgDB->SetChange(new_active_channel, 1); /* force a screen redraw, even if the content didnt change */
	active_channel = new_active_channel;
	DrawTopScreen();
	DrawBottomScreen();
	DrawTextScreen();
	return;
}

int Screen::GetActiveChannel(void)
{
	return active_channel;
}

int Screen::GetScreenNr(char * name, int type)
{
	CheckScreenForRedraw();
	if((type > 1) || (type < 0)) return 0;
	if(name[0] == '\0') return 0;
	for(int i = 1; i < CHANNELS_MAX; i++)
	{
		if(screen_info[i].used) {
			/* i is a used screen */
			if(screen_info[i].type == type) {
				/* we have the same type as requested */
				if(type == 0) {
					/* channel */
					if(strcmp(screen_info[i].channel_name, name) == 0)
						return i;
				} else {
					/* direct chat */
					if(strcmp(screen_info[i].directchat_nickname, name) == 0)
						return i;
				}
			}
		}
	}
	return 0;
}

int Screen::GetNotUsedScreen(int type)
{
	CheckScreenForRedraw();
        for(int i = 1; i < CHANNELS_MAX; i++)
        {
                if(!screen_info[i].used) {
                        /* this screen is not used */
                        if((type == 0) || (type == 1)) {
                                screen_info[i].used = 1;
                                screen_info[i].type = type;
                                return i;
                        }
                }
        }
        return 0; /* 0 when we have no screen left */
}

void Screen::EmptyScreen(int screen_nr)
{
	CheckScreenForRedraw();
	if((screen_nr < 1) || (screen_nr >= CHANNELS_MAX)) return;
	screen_info[screen_nr].used = 0;
	screen_info[screen_nr].type = 0;
	screen_info[screen_nr].channel_name[0] = '\0';
	screen_info[screen_nr].channel_topic[0] = '\0';
	screen_info[screen_nr].directchat_nickname[0] = '\0';
	DrawTopScreen();
	DrawBottomScreen();
	return;
}

void Screen::EmptyAllScreens(void)
{
	CheckScreenForRedraw();
	for(int i = 1; i < CHANNELS_MAX; i++)
	{
		EmptyScreen(i);
	}
	return;
}

void Screen::ParseCommandToServer(char * message)
{
	/* commands that will be parsed
	 * Command:	What will be sent
	 * MSG		PRIVMSG, argument = nickname, message
	 * M		same as MSG
	 * PART		PART or just leave the direct message screen, possible arguments = leavemsg
	 * P		same as PART
	 * QUIT		exit the irc-client, possible argument = leavemsg
	 * Q		same as QUIT
	 * JOIN		Joines a channel, argument = channel
	 * J		same as JOIN                        
	 * SCREEN	Go to a Screen (for the programm 'screen')
	 * S		same as SCREEN
	 * TOPIC        change the topic of the current channel
	 * T            same as TOPIC
	 * NICK         changes the nickname
	 * ME		action
	 * WHO		list the people who are in a channel
	 * W		same as WHO
	 * NAMES        same as WHO
	 * CTCP		get informations about a user
	 * RECONNECT    reconnect to the irc-network
	 * CONNECT      connect to the specified server
	 * RECONNECT    same as CONNECT
	 * HELP         print help to a command
	 * DISCONNECT   disconnect from the irc network */
	
	CheckScreenForRedraw();
	char tmp_command[COMMAND_LEN];
	int len;
	if(message == NULL) len = strlen(InputBuffer);
		else len = strlen(message);
	if(len < 2) return; /* only "/" */
	/* is this a single word or a fully command? */
	int spacepos;
	if(message == NULL) spacepos = position_of_num_char(InputBuffer, ' ', 1);
		else spacepos = position_of_num_char(message, ' ', 1);
	if(spacepos == 1) return; /* message is of type "/ message" */
	int command_len = 0;
	if(spacepos == -1) {
		/* only 1 word after "/" */
		command_len = len - 1;
	} else {
		/* more than one words */
		command_len = spacepos - 1;
	}
	if(command_len >= COMMAND_LEN - 1) command_len = COMMAND_LEN - 1;
	if(message == NULL) memcpy(tmp_command, InputBuffer+1, command_len);
		else memcpy(tmp_command, message+1, command_len);
	tmp_command[command_len] = '\0';
	/* make the command to uppercase */
	string_toupper(tmp_command);
	/* now check this command */
	int command_used = 0;
	char * user_input = NULL; /* pointer to the position of 'InputBuffer' where the options are*/
	if(message == NULL) {
		if(len > command_len+2) user_input = InputBuffer + command_len + 2; /* bsp: "/msg a" => "a"*/
	} else { 
		if(len > command_len+2) user_input = message + command_len + 2;
	}
	if((command_len+2) >= len) user_input = NULL; /* no parameters */
	if(command_len == 1) {
		if(strcmp(tmp_command, "M") == 0) {
			command_used = 1;
			Classes.Connection->DirectMSG(user_input);
		} else if(strcmp(tmp_command, "P") == 0) {
			command_used = 1;
			Classes.Connection->PARTChannelorChat(user_input);
		} else if(strcmp(tmp_command, "Q") == 0) {
			command_used = 1;
			Classes.Connection->QUITIrc(user_input);
		} else if(strcmp(tmp_command, "J") == 0) {
			command_used = 1;
			Classes.Connection->JOINChannel(user_input);
		} else if(strcmp(tmp_command, "S") == 0) {
			command_used = 1;
			user_input_SCREEN(user_input);
		} else if(strcmp(tmp_command, "T") == 0) {
			command_used = 1;
			Classes.Connection->TOPIC_Change(user_input);
		} else if(strcmp(tmp_command, "W") == 0) {
			command_used = 1;
			Classes.IrcUserDB->ListUsersToScreen(user_input);
		}
	} else if(command_len == 2) {
		if(strcmp(tmp_command, "ME") == 0) {
			command_used = 1;
			Classes.Connection->MECommand(user_input);
		}
	} else if(command_len == 3) {
		if(strcmp(tmp_command, "MSG") == 0) {
			command_used = 1;
			Classes.Connection->DirectMSG(user_input);
		} else if(strcmp(tmp_command, "WHO") == 0) {
			command_used = 1;
			Classes.IrcUserDB->ListUsersToScreen(user_input);
		}
	} else if(command_len == 4) {
		if(strcmp(tmp_command, "PART") == 0) {
			command_used = 1;
			Classes.Connection->PARTChannelorChat(user_input);
		} else if(strcmp(tmp_command, "QUIT") == 0) {
			command_used = 1;
			Classes.Connection->QUITIrc(user_input);
		} else if(strcmp(tmp_command, "JOIN") == 0) {
			command_used = 1;
			Classes.Connection->JOINChannel(user_input);
		} else if(strcmp(tmp_command, "NICK") == 0) {
			command_used = 1;
			Classes.Connection->NICK_Change(user_input);
		} else if(strncmp(tmp_command, "CTCP", 4) == 0) {
			command_used = 1;
			Classes.Connection->CTCP_User(user_input);
		} else if(strncmp(tmp_command, "HELP", 4) == 0) {
			command_used = 1;
			help_me(user_input);
		}
	} else if(command_len == 5) {
		if(strcmp(tmp_command, "TOPIC") == 0) {
			command_used = 1;
			Classes.Connection->TOPIC_Change(user_input);
		} else if(strcmp(tmp_command, "NAMES") == 0) {
			command_used = 1;
			Classes.IrcUserDB->ListUsersToScreen(user_input);
		}
	} else if(command_len == 6) {
		if(strcmp(tmp_command, "SCREEN") == 0) {
			command_used = 1;
			user_input_SCREEN(user_input);
		}
	} else if(command_len == 7) {
		if(strcmp(tmp_command, "CONNECT") == 0) {
			command_used = 1;
			Classes.Connection->Connect_to_Server(user_input);
		}	
	} else if(command_len == 9) {
		if(strcmp(tmp_command, "RECONNECT") == 0) {
			command_used = 1;
			Classes.Connection->Connect_to_Server(user_input);
		}
	} else if(command_len == 10) {
		if(strcmp(tmp_command, "DISCONNECT") == 0) {
			command_used = 1;
			Classes.Connection->Disconnect();
			Classes.Connection->UnsetMaybeReconnect();
		}
	}
	if(message == NULL) if(!command_used) Classes.Connection->WriteMessageToServer(InputBuffer+1);
		else if(!command_used) Classes.Connection->WriteMessageToServer(message+1);
	DrawTextScreen();
	return;
}

void Screen::MarktoRedrawScreen(void)
{
	redraw_screen_from_scratch = 1;
	return;
}

void Screen::CheckScreenForRedraw(void)
{
	if(redraw_screen_from_scratch) MakeAllWindow(1);
	return;
}

void Screen::EndNcurses(void)
{
	delwin(TextScreen);
	delwin(InfoBottom);
	delwin(InfoTop);
	delwin(InputScreen);
	endwin();
	return;
}

void Screen::user_input_SCREEN(char * user_input)
{
	if(user_input) {
		int channel_nr = atoi(user_input);
		SetActiveChannel(channel_nr);
	} else {
		help_me("screen");
	}
	return;
}

int Screen::GetScreenUse(int screen_nr)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return 0;
	return screen_info[screen_nr].used;
}

void Screen::SetScreenUse(int screen_nr, int new_use)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return;
	screen_info[screen_nr].used = new_use;
	return;
}

int Screen::GetScreenType(int screen_nr)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return 0;
	return screen_info[screen_nr].type;
}

void Screen::SetScreenType(int screen_nr, int new_type)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return;
	screen_info[screen_nr].type = new_type;
	return;
}

char * Screen::GetChannelName(int screen_nr)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return NULL;
	return screen_info[screen_nr].channel_name;
}

int Screen::GetScreenNumForChannel(char * tmp_channel)
{
	if(tmp_channel[0] == '\0') return 0;
	for(int i = 0; i < CHANNELS_MAX; i++)
		if(strcmp(tmp_channel, screen_info[i].channel_name) == 0) return i;
	return 0;
}

int Screen::GetScreenNumForDirectChat(char * tmp_nickname)
{
	if(tmp_nickname[0] == '\0') return 0;
	for(int i = 0; i < CHANNELS_MAX; i++)
		if(strcmp(tmp_nickname, screen_info[i].directchat_nickname) == 0) return i;
	return 0;
}

void Screen::SetChannelName(int screen_nr, char * new_channelname)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return;
	snprintf(screen_info[screen_nr].channel_name, CHANNELS_NAME_LEN, "%s", new_channelname);
	return;
}

char * Screen::Screen::GetTopic(int screen_nr)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return NULL;
	return screen_info[screen_nr].channel_topic;
}

void Screen::SetTopic(int screen_nr, char * new_topic)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return;
	snprintf(screen_info[screen_nr].channel_topic, TOPIC_LEN_MAX, "%s", new_topic);
	return;
}

char * Screen::GetDirectChatNick(int screen_nr)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return NULL;
	return screen_info[screen_nr].directchat_nickname;
}

int Screen::GetScreenCols(void)
{
	return COLSnow;
}

void Screen::SetDirectChatNick(int screen_nr, char * new_directchatnick)
{
	if((screen_nr < 0) || (screen_nr >= CHANNELS_MAX)) return;
	snprintf(screen_info[screen_nr].directchat_nickname, NICKNAME_LEN, "%s", new_directchatnick);
	return;
}

char * Screen::MakeScreenString(int type)
{
	/*
	 * If the screens 1,3,5,7 and 10 are used and number 3 and 7 are direct chats
	 * this function will return a string like:
	 * "1,5,10"
	 * if the type is 0.
	 * If the type is 1 the returned string will be like this:
	 * "3,7"
	 * */
	if(type < 0 || type > 1) return NULL;
	char * tmp_buf = NULL;
	int num_screens = 0;
	for(int i = 1; i < CHANNELS_MAX; i++)
		if((GetScreenUse(i)) && (GetScreenType(i) == type)) num_screens++;
	if(num_screens == 0) return NULL; /* we dont have screens of the requested type */
	int string_len = (num_screens * (CHANNELS_MAX_STRLEN + 3)) + 1; /* +3 because we have to be able to store a ',' and 2 format chars */
	tmp_buf = new char[string_len];
	tmp_buf[0] = '\0';
	int num_handled = 0;
	char * num = new char[CHANNELS_MAX_STRLEN + 4]; /* +4 because we have to be able to store a ',' and 2 format chars */
	int have_change;
	int screen = Classes.IrcScreen->GetActiveChannel();
	for(int i = 1; i < CHANNELS_MAX; i++)
	{
		if((GetScreenUse(i)) && (GetScreenType(i) == type)) {
			num_handled++;
			have_change = Classes.MsgDB->GetChange(i);
			if(num_handled == num_screens) { /* this is the last screen */
				if(have_change && screen != i)
					snprintf(num, CHANNELS_MAX_STRLEN + 3, "\2%i\2", i);
				else
					snprintf(num, CHANNELS_MAX_STRLEN + 1, "%i", i);
			} else {
				if(have_change && screen != i)
					snprintf(num, CHANNELS_MAX_STRLEN + 4, "\2%i\2,", i);
				else
					snprintf(num, CHANNELS_MAX_STRLEN + 2, "%i,", i);
			}
			strcat(tmp_buf, num);
		}
	}
	delete[] num;
	return tmp_buf;
}

void Screen::SetCursorToInputScreen(void)
{
	int xpos_inputscreen = strlen(InputBuffer);
	if(xpos_inputscreen >= COLSnow) xpos_inputscreen = COLSnow - 1;
	move(LINESnow-1, xpos_inputscreen);
	wrefresh(InputScreen);
	return;
}

void Screen::ResetFormat(WINDOW * screen)
{
	underline_started = 0;
	bold_started = 0;
	wattrset(screen, WA_NORMAL);
	return;
}

void Screen::SetBold(WINDOW * screen)
{
	if(bold_started) {
		wattroff(screen, WA_BOLD);
		bold_started = 0;
	} else {
		wattron(screen, WA_BOLD);
		bold_started = 1;
	}
	return;
}

void Screen::SetUnderline(WINDOW * screen)
{
	if(underline_started) {
		wattroff(screen, WA_UNDERLINE);
		underline_started = 0;
	} else {
		wattron(screen, WA_UNDERLINE);
		underline_started = 1;
	}
	return;
}

int Screen::SetColor(char * string)
{
	int colorchars = 0;
	if(!string) return 0;
	if(string[0] != FORMAT_COLOR_NUM || string[1] == '\0') {
		return colorchars;
	}
	int num = string[1];
	if(num >= 48 && num <= 57) {/* 48 = 0; 49 = 1; .... ; 57 = 9 */
		num -= 48;
		colorchars++;
	} else {
		return colorchars;
	}
	/* check if the number is higher then 9 */
	if(string[2] != '\0') {
		int num2 = string[2];
		if(num2 >= 48 && num2 <= 57) {
			num2 -= 48;
			colorchars++;
			num = (num * 10) + num2;
		}
	}
	return colorchars;
}

int Screen::print_format_text(WINDOW * screen, char * string, int max_chars)
{
	int count = 0;
	int num = 0;
	while(*(string+count) && (num < max_chars))
	{
		switch((unsigned int)*(string+count)) {
			case FORMAT_BOLD_NUM:
				SetBold(screen);
				break;
                        case FORMAT_UNDERLINE_NUM:
				SetUnderline(screen);
				break;
			case FORMAT_COLOR_NUM:
				count += SetColor(string+count);
				break;
			case FORMAT_RESET_NUM:
				ResetFormat(screen);
				break;
                        default:
				num++;
				wprintw(screen, "%c", *(string+count));
                                break;
		}
		count++;
	}
	/* print a newline on the end and reset the formats */
	ResetFormat(screen);
	wprintw(screen, "\n");
	return num;
}

#undef _SCREEN_CC_


syntax highlighted by Code2HTML, v. 0.9.1