#include "Winsock2.h"
#include "Windows.h"
#include "scripts.h"
#include "engine.h"
#include "TCPSocket.h"
#include "YaRR.h"
#include "Hooks.h"
#include "YaRR-IRC.h"
#define Socket_Assert(c) if(!(c)) { /*ERROR_HANDLER*/ printf("Assertion failed\n%s\n", #c); return; }

YaRRIRC *IRCInstance = 0;

YaRRIRC::YaRRIRC()
{
	Socket = 0;
	Packet_Length = 0;
	memset((void *)Server, 0, 128);
	memset((void *)Packet, 0, 512);
	memset((void *)Channels, 0, 32*4);
	Port = 0;
	Connected = 0;
	memset((void *)IRC_Packet_Callbacks, 0, 16*4);
	memset((void *)IRC_Channel_Callbacks, 0, 16*4);
}
YaRRIRC::~YaRRIRC()
{
	if(Socket)
	{
		delete Socket;
	}
}

void YaRRIRC::Load()
{
	IRCInstance = this;
}

void YaRRIRC::Unload()
{
	if(Socket && Connected)
	{
		this->Send("QUIT");
	}
	IRCInstance = 0;
}

void YaRRIRC::Send(const char *Command)
{
	static const char r = '\n';
	Socket_Assert(Socket->Send(Command, (int)strlen(Command)));
	Socket_Assert(Socket->Send(&r, 1));
}

void YaRRIRC::Send_Channel(const char *Channel, const char *Message)
{
	this->Sendf("PRIVMSG %s :%s", Channel, Message);
}

void YaRRIRC::Sendf(const char *Format, ...)
{
	char buffer[256];
	va_list va;
	_crt_va_start(va, Format);
	vsnprintf(buffer, 256, Format, va);
	va_end(va);

	this->Send(buffer);
}

void YaRRIRC::Send_Channelf(const char *Channel, const char *Format, ...)
{
	char buffer[256];
	va_list va;
	_crt_va_start(va, Format);
	vsnprintf(buffer, 256, Format, va);
	va_end(va);

	this->Send_Channel(Channel, buffer);
}

void YaRRIRC::Add_Packet_Callback(_IRC_Packet_Callback _Callback)
{
	for(int i = 0; i < 16; i++)
	{
		if(!IRC_Packet_Callbacks)
		{
			IRC_Packet_Callbacks[i] = _Callback;
			break;
		}
	}
}

void YaRRIRC::Add_Channel_Callback(_IRC_Channel_Callback _Callback)
{
	for(int i = 0; i < 16; i++)
	{
		if(!IRC_Channel_Callbacks)
		{
			IRC_Channel_Callbacks[i] = _Callback;
			break;
		}
	}
}

YaRRIRC_Base::Channel *YaRRIRC::Find_Channel(const char *Name)
{
	for(int i = 0; i < 32; i++)
	{
		if(Channels[i])
		{
			if(_stricmp(Channels[i]->Name, Name) == 0)
			{
				return Channels[i];
			}	
		}
	}
	return 0;
}

YaRRIRC_Base::User *YaRRIRC::Find_User(const char *Channel, const char *Nick)
{
	for(int i = 0; i < 32; i++)
	{
		if(Channels[i])
		{
			if(_stricmp(Channels[i]->Name, Channel) == 0)
			{
				for(int y = 0; y < 64; y++)
				{
					if(Channels[i]->Users[y])
					{
						if(_stricmp(Channels[i]->Users[y]->Nick, Nick) == 0)
						{
							return Channels[i]->Users[y];
						}
					}
				}
			}	
		}
	}
	return 0;
}

void YaRRIRC::Connect(const char *Host, int Port)
{
	if(Socket)
	{
		this->Send("QUIT");
		Socket->Destroy();
		delete Socket;
		Socket = 0;
	}
	Socket = new TCPSocket;
	Socket_Assert(Socket->Client(Host, Port));
	Connected = 1;
}

void YaRRIRC::Send_Handshake(const char *Nick)
{
	strcpy(this->m_Nick, Nick);
	this->Sendf("NICK %s\nUSER %s 0 * :Yet Another Renegade Regulator", Nick, Nick);
}

void YaRRIRC::Packet_Callback(const char *Packet)
{
	for(int i = 0; i < 16; i++)
	{
		if(IRC_Packet_Callbacks[i])
		{
			IRC_Packet_Callbacks[i](Packet);
		}
	}
	char From[256];
	char Command[128];
	char Parameters[512];
	int i;
	if(*Packet == ':')
	{
		Packet++;		
		for(i = 0;*Packet != ' ' && *Packet != 0; Packet++, i++)
		{
			From[i] = *Packet;
		}
		From[i] = 0;
		Packet++;
	}
	for(i = 0;*Packet != ' ' && *Packet != 0; Packet++, i++)
	{
		Command[i] = *Packet;
	}
	Command[i] = 0;
	Packet++;
	for(i = 0; *Packet != 0; Packet++, i++)
	{
		Parameters[i] = *Packet;
	}
	Parameters[i] = 0;
	Packet++;
	if(_stricmp(Command, "PING") == 0)
	{
		this->Sendf("PONG %s", Parameters);
	}
	if(_stricmp(Command, "PRIVMSG") == 0)
	{
		char Nick[64];
		char Channel[64];
		char Message[256];
		if(sscanf(From, "%[^!]!", Nick) == 1 && sscanf(Parameters, "%s :%[^\n]\n", Channel, Message) == 2)
		{
			Message[strlen(Message)-1] = 0;
			Channel_Callback(Nick, Channel, Message);
		}
	}
	if(_stricmp(Command, "332") == 0)
	{
		char c[256];
		if(sscanf(Parameters, "%*s %s", c) != 1)
		{
			return;
		}
		Channel *c_tmp = Find_Channel(c);
		if(!c_tmp)
		{
			c_tmp = new Channel;
			strcpy(c_tmp->Name, c);
			memset((void *)(c_tmp->Users), 0, 64*4);
			for(int i = 0; i < 32; i++)
			{
				if(!Channels[i])
				{
					Channels[i] = c_tmp;
					break;
				}
			}
		}
	}
	if(_stricmp(Command, "353") == 0)
	{
		char *Buffer[72];
		memset((void *)Buffer, 0, 72*4);
		Explode(Parameters, ' ', Buffer);
		Channel *c = Find_Channel(Buffer[2]);
		if(!c)
		{
			return;
		}
		memset((void *)c->Users, 0, 64*4);
		strcpy(Buffer[3], Buffer[3] + 1);
		for(int i = 3; i < 72; i++)
		{
			if(Buffer[i])
			{
				char Mode = 0;
				if(strcspn(Buffer[i], "+%@&~") == 0)
				{
					Mode = *(Buffer[i]);
					strcpy(Buffer[i], Buffer[i] + 1);
				}

				for(int y = 0; y < 64; y++)
				{
					if(!c->Users[y])
					{
						c->Users[y] = new User;
						c->Users[y]->Mode = Mode;
						strcpy(c->Users[y]->Nick, Buffer[i]);
						break;
					}
				}
			}
		}
		for(int i = 0; i < 72; i++)
		{
			if(Buffer[i])
			{
				free((void *)Buffer[i]);
			}
		}
	}	
}

void YaRRIRC::Channel_Callback(const char *Nick, const char *Channel, const char *Message)
{
	for(int i = 0; i < 16; i++)
	{
		if(IRC_Channel_Callbacks[i])
		{
			IRC_Channel_Callbacks[i](Nick, Channel, Message);
		}
	}	
}

void YaRRIRC::Think()
{
	if(!Socket || !Connected)
	{
		return;
	}
	while(Socket->Is_DataAvaliable())
	{
		char c = 0;
		if(Socket->Receive(&c, 1))
		{
			if(c  != '\n')
			{
				Packet[Packet_Length++] = c;
			}
			else
			{
				Packet[Packet_Length] = 0;
				Packet_Length = 0;
				Packet_Callback(Packet);
			}
		}
	}
}
