/* --- MAIN.CPP ---
/  
/ Written by Phil Himsworth, 2001-2002.
/
/*/

#include <windows.h>
#include <process.h>
#include <winver.h>
#include "types.h"
#include "plugin.h"
#include "resource.h"

#include "main.h"

char szAppName[] = "Winamp Web Interface";
char szAppVer[10];		// now filled in automagically on startup


char mp3root[MAX_PATH];
char playlistdir[MAX_PATH];
char filetypes[255];						// file types which will show in the browse bit.
char pagetitle[255];

char logfiledir[MAX_PATH];

extern char bchars[];			// lookup table for base64 needs to be built on startup
extern char achars[256];

// All winamp needs to know about the plugin
winampGeneralPurposePlugin plugin =
{
	GPPHDR_VER,
	"",
	init,
	config,
	quit,
};


// Globals for actual server (rather than random winamp things)

LPDWORD client_thread;
SOCKET server_socket;
int con_port, hide_error, frames, title_refresh;
int show_other_files, dl_wa_files, dl_other_files;

extern HWND ConfigWnd;




// --------------------------------------------------------------------------------
// Entry point of DLL for windows; does nothing
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
	return TRUE;
}

// --------------------------------------------------------------------------------
// The interface which Winamp sees-
// It returns the plugin information struct
extern "C"
{
	__declspec( dllexport ) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin()
	{
		return &plugin;
	}
}



// --------------------------------------------------------------------------------
// Startup. This is where interesting things start happening
int init()
{

	HANDLE newthread;
	DWORD newthread_id;
	static char c[512];
	char filename[512],*p;
	GetModuleFileName(plugin.hDllInstance,filename,sizeof(filename));

	// Retrieve version info
	DWORD versize = GetFileVersionInfoSize(filename, NULL);
	char * versiondata = new char[versize];
	GetFileVersionInfo(filename, NULL, versize, versiondata);
	VS_FIXEDFILEINFO * info;
	UINT verlen;
	VerQueryValue(versiondata,"\\",(void**)&info,&verlen);
	int ver_l = (int)info->dwFileVersionLS;
	int ver_h = (int)info->dwFileVersionMS;

	int ver1, ver2, ver3, ver4;		// version of form ver1,ver2,ver3,ver4
	/*
	ver1 = (ver_h & 0xFFFF0000) >> 16;
	ver2 = (ver_h & 0x0000FFFF);
	ver3 = (ver_l & 0xFFFF0000) >> 16;
	ver4 = (ver_l & 0x0000FFFF);
	*/
	ver1 = HIWORD(ver_h);
	ver2 = LOWORD(ver_h);
	ver3 = HIWORD(ver_l);
	ver4 = LOWORD(ver_l);
	if (ver3 == 0)
		wsprintf(szAppVer,"%u.%u", ver1, ver2);
	else
		wsprintf(szAppVer,"%u.%u.%u", ver1, ver2, ver3);
	
	delete versiondata;

	ZeroMemory(achars,256);
	for(int i = 0; i < 64; i++)			// build lookup table for FromBase64()
		achars[bchars[i]] = i;
	
	p = filename+lstrlen(filename);
	while (p >= filename && *p != '\\') p--;
	wsprintf((plugin.description=c),"%s Plugin v.%s (%s)",szAppName,szAppVer,p+1);
	newthread = CreateThread(NULL,0,HTTPServerThread,0,0,&newthread_id);
	return 0;
}


// --------------------------------------------------------------------------------
// Config dialog please
void config()
{
	if (!ConfigWnd)
	{
		NewConfig();
		ConfigWnd = NULL;
	}
	else
		SetActiveWindow(ConfigWnd);
	
}


// --------------------------------------------------------------------------------
// Winamp is saying goodbye
void quit()
{
	// Hmmm. Did there always used to be nothing in here? Curiouser and curiouser...
}


// --------------------------------------------------------------------------------
// Opens the server socket
bool InitServerSocket()
{
	config_read();

	WORD wVersionRequested = MAKEWORD(2,2);
	WSADATA wsaData;
	
	if (WSAStartup(wVersionRequested, &wsaData ) != 0 ) 
	{
		if (hide_error == 0)
			MessageBox(plugin.hwndParent, "ERROR: Winsock not available", "Winamp Web Interface", MB_OK);
		return false;
	}

	server_socket = socket(AF_INET,SOCK_STREAM,0);
	if (server_socket == INVALID_SOCKET)
	{
		if (hide_error == 0)
			MessageBox(plugin.hwndParent, "ERROR: Couldn't create socket", "Winamp Web Interface", MB_OK);
		return false;
	}

	struct sockaddr_in server_address;
	ZeroMemory(&server_address,sizeof(server_address));
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(con_port);

	if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) != 0)
	{
		if (hide_error == 0)
			MessageBox(plugin.hwndParent, "ERROR: Couldn't open port", "Winamp Web Interface", MB_OK);
		return false;
	}

	if (listen(server_socket,5) != 0)
	{
		if (hide_error == 0)
			MessageBox(plugin.hwndParent, "ERROR: Cannot act as server", "Winamp Web Interface", MB_OK);
		return false;
	}

	return true;			// Server socket opened successfully
}




// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Server main thread entry point
DWORD WINAPI HTTPServerThread(LPVOID param)
{

	// initialise winsock
	if (InitServerSocket())
	{

		//printf("Server is listening for connections on port %d.\n",ntohs(server_address.sin_port));

		struct sockaddr_in client_address;
		SOCKET client_socket;
		int client_address_length = sizeof(client_address);
		while (true)
		{
			client_socket = accept(server_socket,(struct sockaddr *) &client_address, &client_address_length);
			//printf("Connection request from %s:%d - ", (char*)inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port));
			if (client_socket != INVALID_SOCKET)
			{
				DWORD connection_id;
				client_thread = (DWORD*)CreateThread(NULL,0,ClientConnection,(void*)client_socket, 0, &connection_id);
			}
		}

		closesocket(server_socket);
	}
	return true;
}





// --------------------------------------------------------------------------------
// *** WINAMP FUNCTIONS ***
// Returns handle to winamp window
HWND WAwnd()
{
	return plugin.hwndParent;
}


// --------------------------------------------------------------------------------
// Insert a node into a list starting from 'current'
void Insert(fileinfo *newfile, fileinfo *current)
{
	if (GoesBefore(newfile->name,current->name))		// newfile goes before current
	{
		//wsprintf(tempstring,"%s goes before %s and after %s",newfile->name,current->name, current->prev->name);
		//MessageBox(NULL,tempstring,"gen_httpsrv debug goes before",MB_OK);

		if (current->prev != NULL)						
			current->prev->next = newfile;
		
		newfile->prev = current->prev;
		newfile->next = current;
		current->prev = newfile;

		//wsprintf(tempstring,"Order is now %s, %s, %s",newfile->prev->name,newfile->name,newfile->next->name);
		//MessageBox(NULL,tempstring,"gen_httpsrv debug goes before result",MB_OK);
	} 
	else
	{
		if (current->next == NULL)					// newfile is after current; current is the last node
		{
			//wsprintf(tempstring,"%s goes after %s and is the last record",newfile->name,current->name);
			//MessageBox(NULL,tempstring,"gen_httpsrv debug after and last",MB_OK);

			current->next = newfile;
			newfile->prev = current;
		}
		else
		{											// newfile is after current but before something else
			Insert(newfile,current->next);			// AAARGH! RECURSION! Like hell it'll work...
		}
	}
}


// --------------------------------------------------------------------------------
// Compare two strings, return TRUE if the first one should be before the second alphabetically

bool GoesBefore(char *file1, char *file2)
{
	if (file1 == NULL || file2 == NULL)
		return true;

	int i=0;
	while (ToLowerCase(file1[i]) == ToLowerCase(file2[i]))
	{
		if (file1[i] == 0)
			return true;
		i++;
	}
	if (ToLowerCase(file1[i]) > ToLowerCase(file2[i]))
		return false;
	else
		return true;
}



