#include <windows.h>
#include "resource.h"
#include <stdio.h>
#include <string>
#include <fstream>
#include <vector>
#include "mxsocket.h"


HWND hwnd,hDirHandle,hDir,hLog = 0,hFileList;
struct Dir {
	std::string name;
	std::string directory;
};
std::vector< struct Dir > dirs;
std::vector < struct mxSocket > sockets;

bool openfile(char* cFile)
{
	char szFile[MAX_PATH];
	char title[MAX_PATH];
	sprintf(title,"Choose Directory");


	OPENFILENAME ofn;       // common dialog box structure

	strcpy(szFile, "Makefile");

	// Initialize OPENFILENAME
	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = GetForegroundWindow();
	ofn.lpstrFile = szFile;
	ofn.nMaxFile = sizeof(szFile);
	ofn.lpstrFilter = "Makefile\0*.*\0ALL\0*.*\0\0";
	ofn.nFilterIndex = 1;
	ofn.lpstrFileTitle = title;
	ofn.nMaxFileTitle = MAX_PATH;
	ofn.lpstrInitialDir = NULL;
	ofn.hInstance = GetModuleHandle(0);
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;


	if (GetOpenFileName(&ofn)==TRUE)
	{
		strcpy(cFile, ofn.lpstrFile);
		return true;
	}
	else
	{
		return false;
	}

}

void Log(const char *src, ...) {
	char data[5000];
	va_list l;
	va_start(l,src);
	vsprintf(data, src, l);
	va_end(l);
	LRESULT len = SendMessage(hLog,WM_GETTEXTLENGTH,0,0);
	sprintf(data,"%s\r\n", data);
	SendMessage(hLog,EM_SETSEL,len,len);
	SendMessage(hLog,EM_REPLACESEL, strlen(data), (LPARAM)(LPCSTR)data);
	len = SendMessage(hLog,WM_GETTEXTLENGTH,0,0);
	SendMessage(hLog,EM_SETSEL,len,len);
}

std::string mid(std::string source, size_t start, size_t stop)  {
	std::string rt = "";
	for(size_t i = start; i < stop; i++)
		rt += source[i];
	return rt;
}

struct sockaddr_in addy;

inline void ReloadSocket() {
	if(!sockets.empty()) {
		closesocket(sockets[0].s);
		sockets.erase(sockets.begin(),sockets.end());
		WSACleanup();
	}
	InitWinsock();
	mxSocket s;
	s.port = 1024;
	sockets.push_back(s);
	mxListen(&sockets[0], addy);
}

LRESULT APIENTRY WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) {
	switch(msg) {
		case WM_DESTROY:
			WSACleanup();
			PostQuitMessage(0);
			break;
		case WM_CREATE:
			{
				hDirHandle = CreateWindow("ListBox","",WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_NOTIFY, 10,10,200,200,hwnd,HMENU(1),GetModuleHandle(0),0);
				hDir = CreateWindow("ListBox", "", WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_NOTIFY, 210,10,200,200,hwnd,HMENU(2),GetModuleHandle(0),0);
				hFileList = CreateWindow("ListBox","",WS_CHILD | WS_VISIBLE | LBS_STANDARD, 420,10,200,200,hwnd,0,GetModuleHandle(0),0);
			}
			break;
		case ON_SOCKET:
			{
		     switch (WSAGETSELECTEVENT(lParam)) {
				case FD_ACCEPT: {

					sockets[0].s = accept(sockets[0].s,0,0);
					    Log("Socket accepted sending handshake...");
						char *buf = "lsdmake 1.0";
						if(send(sockets[0].s,buf,int(strlen(buf)),0) == SOCKET_ERROR) {
							Log("Error sending handshake.");
							ReloadSocket();
							return 0;
						}
					}
					break;
				case FD_READ: {
					char buf[256];
					memset(buf,0,sizeof(buf));
					int rt_val = recv(sockets[0].s, buf,sizeof(buf), 0);

					if(rt_val < 0)
					{
						Log("Error reading from socket...");
						ReloadSocket();
						return 0;
					}
					else {

						std::string path = buf;
						size_t pos = path.find("get");
						if(pos != -1) {
							std::string file_path = path.substr(pos+4,path.length());
							// find directory
							size_t dir_pos = 0;// for now set it to 0
							for(dir_pos = 0; dir_pos < dirs.size(); dir_pos++) {
								if(dirs[dir_pos].name == file_path) {
									break;
								}
							}
							std::string str = dirs[dir_pos].directory + "\\*.*";
							SendMessage(hFileList,LB_DIR,DDL_DIRECTORY,(LPARAM)(LPCSTR)str.c_str());
							LRESULT pos;
							for(pos = 0; pos < SendMessage(hFileList,LB_GETCOUNT,0,0); pos++) {
								// send each file
								char file_name[MAX_PATH];
								SendMessage(hFileList,LB_GETTEXT,pos,(LPARAM)(LPCSTR)file_name);
								std::string full_path = file_name;
								if(full_path.find("[") == -1) {
									full_path = dirs[dir_pos].directory + "\\" +  file_name;
									Log("Sending file %s", full_path.c_str());
									std::fstream file;
									file.open(full_path.c_str(), std::ios::in | std::ios::binary );
									if(file.is_open()) {
										file.seekg(0,std::ios::end);
										size_t len = file.tellg();
										file.seekg(0,std::ios::beg);
										static char filen[256];
										memset(filen,0,sizeof(filen));
										sprintf(filen,"%d:%s",long(len),file_name);
										Sleep(10);
										if(send(sockets[0].s,filen, sizeof(filen), 0) == SOCKET_ERROR)
										{
											Log("error on send.");
											ReloadSocket();
											return 0;
										}

										while(!file.eof()) {
												static char read_buffer[256];
												memset(read_buffer,0,sizeof(read_buffer));
												file.read((char*)read_buffer,sizeof(read_buffer));
												Sleep(100);
												if(send(sockets[0].s,read_buffer,sizeof(read_buffer),0) == SOCKET_ERROR) {
													Log("Error on send. closing ");
													ReloadSocket();
													return 0;
												}
										}
										file.close();
									}

								}

							}

							memset(buf,0,sizeof(buf));
							sprintf(buf,"term...");
							send(sockets[0].s,buf,sizeof(buf),0);
							Log("Connection closed.");
							ReloadSocket();

						}
						
					}

				  }
					break;
				case FD_CONNECT: {
				
					}
					break;
				case FD_CLOSE:
					ReloadSocket();
					break;
				}
			}
			break;
		case WM_COMMAND:
			{
				switch(wParam) 
				{
				case ID_FILE_EXIT:
					SendMessage(hwnd,WM_CLOSE,0,0);
					break;
				case ID_HELP_ABOUT:
					MessageBox(hwnd,"LSD Make Server \r\n Quick and Dirty \r\n by Jared Bruni", "=)", MB_OK  | MB_ICONINFORMATION);
					break;
				case ID_FILE_ADDDIRECTORY:
					MessageBox(hwnd,"Add Directory by Selecting the Makefile for the project you want people to download & build.","Select Makefile", MB_OK | MB_ICONINFORMATION);
					char directory[MAX_PATH];
					if(openfile(directory) == true) {
						std::string fm = directory;
						size_t pos = fm.rfind("Makefile");
						if(pos == -1) {
							MessageBox(hwnd,"Error you didnt select a Makefile!", "Error", MB_ICONERROR);
							break;
						}
						pos = fm.rfind("\\", fm.rfind("\\")-1);
						std::string part_name = mid(fm, pos+1, fm.rfind("\\"));
						std::string full_name = mid(fm, 0, fm.rfind("\\"));

						SendMessage(hDirHandle,LB_ADDSTRING,part_name.length(),(LPARAM)(LPCSTR)part_name.c_str());
						SendMessage(hDir,LB_ADDSTRING,strlen(directory),(LPARAM)(LPCSTR)full_name.c_str());
						struct Dir dirz;
						dirz.directory = full_name;
						dirz.name = part_name;
						dirs.push_back(dirz);
					}
					break;
				case ID_START_STARTSERVER:
					{
						if(hLog == 0) {
							hLog = CreateWindow("Edit","", WS_VSCROLL | ES_AUTOVSCROLL | WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY, 10, 250, 640-20, 100, hwnd,0,GetModuleHandle(0),0);
							Log("Starting Server...");
							InitWinsock();
							mxSocket s;
							s.port = 1024;
							sockets.push_back(s);
							struct sockaddr_in any;
							mxListen(&sockets[0], any);
							Log("Server Started waiting for incoming connections..");
						}	
					}
					break;
				case ID_START_STOPSERVER:
					{
						WSACleanup();
					}
					break;
				case ID_FILE_LOADDIRECTORYSLISTFROMFILE:
					{
						if(!dirs.empty()) {
							dirs.erase(dirs.begin(),dirs.end());
							SendMessage(hDir,LB_RESETCONTENT,0,0);
							SendMessage(hDirHandle,LB_RESETCONTENT,0,0);
						}
						std::fstream file;
						file.open("conf.txt", std::ios::in );
						while(file.is_open() && !file.eof()) {
							struct Dir d;
							std::getline(file,d.directory);
							std::getline(file,d.name);
							if(d.directory.length() != 0 && d.name.length() != 0) {
							dirs.push_back(d);
							SendMessage(hDir,LB_ADDSTRING,d.directory.length(),(LPARAM)(LPCSTR)d.directory.c_str());
							SendMessage(hDirHandle,LB_ADDSTRING,d.name.length(),(LPARAM)(LPCSTR)d.name.c_str());
							}
						}
						file.close();
						//MessageBox(hwnd,"Succesfully loaded from file", "YEP" , MB_OK | MB_ICONINFORMATION);

					}
					break;
		
				}



		switch(HIWORD(wParam)) {
		case LBN_SELCHANGE:
			switch(LOWORD(wParam)) 
			{
			case 1:
				break;
			case 2:
				break;
			}
			break;
				}
			}
			break;
		default:
			return DefWindowProc(hwnd,msg,wParam,lParam);
	}
	return 0;
}


int PASCAL WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpszLine, int iCmdShow) {

	WNDCLASS wc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
	wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hInstance = hInst;
	wc.lpfnWndProc = (WNDPROC) WndProc;
	wc.lpszClassName = "lsdmake_server";
	wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
	wc.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&wc);

	hwnd = CreateWindow("lsdmake_server", "LSDMake Server", WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, 0,0, 640,480, 0,0,GetModuleHandle(0),0);
	ShowWindow(hwnd,SW_SHOW);
	UpdateWindow(hwnd);
	SendMessage(hwnd,WM_COMMAND,ID_FILE_LOADDIRECTORYSLISTFROMFILE,0);


	MSG msg;
	while(GetMessage(&msg,0,0,0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}