#include <all_far.h>

#include "Int.h"

LPCSTR WINAPI FP_GetPluginName(void)
{
	return "FarFtp.dll";
}
LPCSTR WINAPI FP_GetPluginLogName(void)
{
	return "farftp.log";
}
BOOL WINAPI FP_PluginStartup(DWORD Reason)
{
	return TRUE;
}

//------------------------------------------------------------------------
Options Opt;
FTP *FTPPanels[3] = {0};
FTP *LastUsedPlugin = NULL;
// BOOL          SocketStartup  = FALSE;
int SocketInitializeError = 0;
AbortProc ExitProc;
char DialogEditBuffer[DIALOG_EDIT_SIZE];

typedef char FTPDistString[MAX_PATH];
FTPDistString DiskStrings[1 + FTP_MAXBACKUPS];
LPCSTR DiskMenuStrings[1 + FTP_MAXBACKUPS];
int DiskMenuNumbers[1 + FTP_MAXBACKUPS];

//------------------------------------------------------------------------
FTP *WINAPI OtherPlugin(FTP *p)
{
	if (!p)
		return p;

	if (FTPPanels[0] == p)
		return FTPPanels[1];
	else if (FTPPanels[1] == p)
		return FTPPanels[0];

	return NULL;
}

int WINAPI PluginPanelNumber(FTP *p)
{
	if (p) {
		if (FTPPanels[0] == p)
			return 1;
		else if (FTPPanels[1] == p)
			return 2;
	}

	return 0;
}

int WINAPI PluginUsed(void)
{
	return PluginPanelNumber(LastUsedPlugin);
}

//------------------------------------------------------------------------
void _cdecl CloseUp(void)
{
	int n;

	if (FTP::BackupCount) {
		Log(("CloseUp.FreeBackups"));

		for (n = 0; n < FTP::BackupCount; n++)
			delete FTP::Backups[n];

		FTP::BackupCount = 0;
	}

	Log(("CloseUp.FreePlugins"));
	FreePlugins();
	Log(("CloseUp.Delete Opt data"));

	for (n = 0; n < 12; n++)
		free(Opt.Months[n]);

	memset(Opt.Months, 0, sizeof(Opt.Months));

	/*	if(SocketStartup)
		{
			Log(("CloseUp.CloseWSA"));
			WSACleanup();
		}*/

	if (ExitProc)
		ExitProc();
}

void AddPlugin(FTP *ftp)
{
	if (!FTPPanels[0])
		FTPPanels[0] = ftp;
	else if (!FTPPanels[1])
		FTPPanels[1] = ftp;
	else if (!FTPPanels[2])
		FTPPanels[2] = ftp;
	else
		Assert(!"More than two plugins in a time !!");
}

void RemovePlugin(FTP *ftp)
{
	PROC(("RemovePlugin", "%p", ftp))

	if (FTPPanels[0] == ftp)
		FTPPanels[0] = NULL;
	else if (FTPPanels[1] == ftp)
		FTPPanels[1] = NULL;
	else if (FTPPanels[2] == ftp)
		FTPPanels[2] = NULL;

	if (FTPPanels[2]) {
		AddPlugin(FTPPanels[2]);
		FTPPanels[2] = NULL;
	}

	LPCSTR rejectReason;

	if (ftp->isBackup()) {
		ftp->SetBackupMode();
		return;
	}

	LPCSTR itms[] = {FMSG(MRejectTitle), FMSG(MRejectCanNot), NULL, FMSG(MRejectAsk1), FMSG(MRejectAsk2),
			FMSG(MRejectIgnore), FMSG(MRejectSite)};

	do {
		if ((rejectReason = ftp->CloseQuery()) == NULL)
			break;

		itms[2] = rejectReason;

		if (FMessage(FMSG_LEFTALIGN | FMSG_WARNING, "CloseQueryReject", itms, ARRAYSIZE(itms), 2) != 1)
			break;

		ftp->AddToBackup();

		if (!ftp->isBackup()) {
			SayMsg(FMSG(MRejectFail));
			break;
		}

		return;
	} while (0);

	delete ftp;
}

//------------------------------------------------------------------------
SHAREDSYMBOL void WINAPI ExitFAR(void)
{
	// FP_Info = NULL; FP_GetMsg( "temp" );
	CallAtExit();
}

SHAREDSYMBOL void WINAPI SetStartupInfo(const struct PluginStartupInfo *Info)
{
	LastUsedPlugin = NULL;
	FP_SetStartupInfo(Info, "FTP");
	ExitProc = AtExit(CloseUp);
	memset(&Opt, 0, sizeof(Opt));

	for (int n = 0; n < FTP_MAXBACKUPS; n++)
		DiskMenuStrings[n] = DiskStrings[n];

	memset(DiskMenuNumbers, 0, sizeof(DiskMenuNumbers));
	PROC(("SetStartupInfo", NULL))
	ReadCfg();
	LogCmd("FTP plugin loaded", ldInt);
}

SHAREDSYMBOL void WINAPI GetPluginInfo(struct PluginInfo *Info)
{
	LastUsedPlugin = NULL;
	PROC(("GetPluginInfo", "%p", Info))
	static LPCSTR PluginMenuStrings[1];
	static LPCSTR PluginCfgStrings[1];
	static char MenuString[MAX_PATH];
	static char CfgString[MAX_PATH];
	snprintf(MenuString, ARRAYSIZE(MenuString), "%s", FP_GetMsg(MFtpMenu));
	snprintf(DiskStrings[0], ARRAYSIZE(DiskStrings[0]), "%s", FP_GetMsg(MFtpDiskMenu));
	snprintf(CfgString, ARRAYSIZE(CfgString), "%s", FP_GetMsg(MFtpMenu));
	FTPHost *p;
	int n, uLen = 0, hLen = 0;
	char str[MAX_PATH];
	FTP *ftp;

	for (n = 0; n < FTP::BackupCount; n++) {
		ftp = FTP::Backups[n];

		if (!ftp->FTPMode())
			continue;

		p = &ftp->Host;
		uLen = Max(uLen, static_cast<int>(strlen(p->User)));
		hLen = Max(hLen, static_cast<int>(strlen(p->Host)));
	}

	for (n = 0; n < FTP::BackupCount; n++) {
		ftp = FTP::Backups[n];
		ftp->GetCurPath(str, ARRAYSIZE(str));

		if (ftp->FTPMode()) {
			p = &ftp->Host;
			snprintf(DiskStrings[1 + n], ARRAYSIZE(DiskStrings[0]), "FTP: %-*s %-*s %s", uLen, p->User, hLen,
					p->Host, str);
		} else
			snprintf(DiskStrings[1 + n], ARRAYSIZE(DiskStrings[0]), "FTP: %s", str);
	}

	DiskMenuNumbers[0] = Opt.DisksMenuDigit;
	PluginMenuStrings[0] = MenuString;
	PluginCfgStrings[0] = CfgString;
	Info->StructSize = sizeof(*Info);
	Info->Flags = 0;
	Info->DiskMenuStrings = DiskMenuStrings;
	Info->DiskMenuNumbers = DiskMenuNumbers;
	Info->DiskMenuStringsNumber = Opt.AddToDisksMenu ? (1 + FTP::BackupCount) : 0;
	Info->PluginMenuStrings = PluginMenuStrings;
	Info->PluginMenuStringsNumber = Opt.AddToPluginsMenu ? ARRAYSIZE(PluginMenuStrings) : 0;
	Info->PluginConfigStrings = PluginCfgStrings;
	Info->PluginConfigStringsNumber = ARRAYSIZE(PluginCfgStrings);
	Info->CommandPrefix = FTP_CMDPREFIX;
}

SHAREDSYMBOL int WINAPI Configure(int ItemNumber)
{
	LastUsedPlugin = NULL;
	PROC(("Configure", "%d", ItemNumber))

	switch (ItemNumber) {
		case 0:

			if (!Config())
				return FALSE;
	}

	// Update panels
	return TRUE;
}

SHAREDSYMBOL HANDLE WINAPI OpenPlugin(int OpenFrom, INT_PTR Item)
{
	fprintf(stderr, "FARFTP: OpenPlugin\n");
	LastUsedPlugin = NULL;
	PROC(("OpenPlugin", "%d,%d", OpenFrom, Item))
	FTP *Ftp;
	ReadCfg();

	if (!InitPlugins())
		return INVALID_HANDLE_VALUE;

	if (Item == 0 || Item > FTP::BackupCount)
		Ftp = new FTP;
	else {
		Ftp = FTP::Backups[Item - 1];
		Ftp->SetActiveMode();
	}

	AddPlugin(Ftp);
	Ftp->Call();
	Log(("FTP handle: %p", Ftp));

	do {
		if (OpenFrom == OPEN_SHORTCUT) {
			if (!Ftp->ProcessShortcutLine((char *)Item))
				break;

			Ftp->End();
		} else if (OpenFrom == OPEN_COMMANDLINE) {
			if (!Ftp->ProcessCommandLine((char *)Item))
				break;
		}

		Ftp->End();
		return (HANDLE)Ftp;
	} while (0);

	RemovePlugin(Ftp);
	return INVALID_HANDLE_VALUE;
}

SHAREDSYMBOL void WINAPI ClosePlugin(HANDLE hPlugin)
{
	FTP *p = (FTP *)hPlugin;
	PROC(("ClosePlugin", "%p", hPlugin))
	LastUsedPlugin = p;
	RemovePlugin(p);
}

SHAREDSYMBOL int WINAPI
GetFindData(HANDLE hPlugin, struct PluginPanelItem **pPanelItem, int *pItemsNumber, int OpMode)
{
	FPOpMode _op(OpMode);
	FTP *p = (FTP *)hPlugin;
	p->Call();
	int rc = p->GetFindData(pPanelItem, pItemsNumber, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL void WINAPI FreeFindData(HANDLE hPlugin, struct PluginPanelItem *PanelItem, int ItemsNumber)
{
	FTP *p = (FTP *)hPlugin;
	p->Call();
	p->FreeFindData(PanelItem, ItemsNumber);
	p->End();
}

SHAREDSYMBOL void WINAPI GetOpenPluginInfo(HANDLE hPlugin, struct OpenPluginInfo *Info)
{
	//	fprintf(stderr, "FARFTP: GetOpenPluginInfoy \n");
	FTP *p = (FTP *)hPlugin;
	p->Call();
	p->GetOpenPluginInfo(Info);
	p->End();
}

SHAREDSYMBOL int WINAPI SetDirectory(HANDLE hPlugin, LPCSTR Dir, int OpMode)
{
	fprintf(stderr, "FARFTP: SetDirectory '%s'\n", Dir);
	FPOpMode _op(OpMode);
	FTP *p = (FTP *)hPlugin;
	p->Call();
	int rc = p->SetDirectoryFAR(Dir, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI GetFiles(HANDLE hPlugin, struct PluginPanelItem *PanelItem, int ItemsNumber, int Move,
		char *DestPath, int OpMode)
{
	FPOpMode _op(OpMode);
	FTP *p = (FTP *)hPlugin;

	if (!p || !DestPath || !DestPath[0])
		return FALSE;

	String s(DestPath);
	p->Call();
	int rc = p->GetFiles(PanelItem, ItemsNumber, Move, s, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI
PutFiles(HANDLE hPlugin, struct PluginPanelItem *PanelItem, int ItemsNumber, int Move, int OpMode)
{
	FPOpMode _op(OpMode);
	FTP *p = (FTP *)hPlugin;
	p->Call();
	int rc = p->PutFiles(PanelItem, ItemsNumber, Move, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI
DeleteFiles(HANDLE hPlugin, struct PluginPanelItem *PanelItem, int ItemsNumber, int OpMode)
{
	FPOpMode _op(OpMode);
	FTP *p = (FTP *)hPlugin;
	p->Call();
	int rc = p->DeleteFiles(PanelItem, ItemsNumber, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI MakeDirectory(HANDLE hPlugin, char *Name, int OpMode)
{
	fprintf(stderr, "FARFTP: MakeDirectory '%s'\n", Name);
	FPOpMode _op(OpMode);

	if (!hPlugin)
		return FALSE;

	FTP *p = (FTP *)hPlugin;
	String s(Name ? Name : "");
	p->Call();
	int rc = p->MakeDirectory(s, OpMode);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI ProcessKey(HANDLE hPlugin, int Key, unsigned int ControlState)
{
	FTP *p = (FTP *)hPlugin;
	p->Call();
	int rc = p->ProcessKey(Key, ControlState);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI ProcessEvent(HANDLE hPlugin, int Event, void *Param)
{
	FTP *p = (FTP *)hPlugin;
	LastUsedPlugin = p;
#if defined(__FILELOG__)
	static LPCSTR evts[] = {"CHANGEVIEWMODE", "REDRAW", "IDLE", "CLOSE", "BREAK", "COMMAND"};
	PROC(("FAR.ProcessEvent", "%p,%s[%08X]", hPlugin,
			(Event < ARRAYSIZE(evts)) ? evts[Event] : Message("<unk>%d", Event), Param))
#endif
	p->Call();
	int rc = p->ProcessEvent(Event, Param);
	p->End(rc);
	return rc;
}

SHAREDSYMBOL int WINAPI
Compare(HANDLE hPlugin, const PluginPanelItem *i, const PluginPanelItem *i1, unsigned int Mode)
{
	if (Mode == SM_UNSORTED)
		return -2;

	FTPHost *p = FTPHost::Convert(i), *p1 = FTPHost::Convert(i1);
	int n;

	if (!i || !i1 || !p || !p1)
		return -2;

#define CMP(v, v1)                                                                                             \
	(WINPORT(CompareStringA)(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, v, -1, v1, -1) - 2)

	switch (Mode) {
		case SM_EXT:
			n = CMP(p->Home, p1->Home);
			break;
		case SM_DESCR:
			n = CMP(p->HostDescr, p1->HostDescr);
			break;
		case SM_OWNER:
			n = CMP(p->User, p1->User);
			break;
		case SM_MTIME:
		case SM_CTIME:
		case SM_ATIME:
			n = (int)WINPORT(CompareFileTime)(&p1->LastWrite, &p->LastWrite);
			break;
		default:
			n = CMP(p->Host, p1->Host);
			break;
	}

	do {
		if (n)
			break;

		n = CMP(p->Host, p1->Host);

		if (n)
			break;

		n = CMP(p->User, p1->User);

		if (n)
			break;

		n = CMP(p->HostDescr, p1->HostDescr);

		if (n)
			break;
	} while (0);

#undef CMP

	if (n)
		return (n > 0) ? 1 : (-1);
	else
		return 0;
}

void InitDialogItems(const InitDialogItem *Init, FarDialogItem *Item, int ItemsNumber)
{
	for (int i = 0; i < ItemsNumber; i++) {
		Item[i].Type = Init[i].Type;
		Item[i].X1 = Init[i].X1;
		Item[i].Y1 = Init[i].Y1;
		Item[i].X2 = Init[i].X2;
		Item[i].Y2 = Init[i].Y2;
		Item[i].Focus = Init[i].Focus;
		Item[i].History = (const CHAR *)Init[i].Selected;
		Item[i].Flags = Init[i].Flags;
		Item[i].DefaultButton = Init[i].DefaultButton;
#ifdef UNICODE
		Item[i].MaxLen = 0;
#endif

		if ((DWORD_PTR)Init[i].Data < 2000)
#ifndef UNICODE
			strcpy(Item[i].Data, FP_GetMsg((unsigned int)(DWORD_PTR)Init[i].Data));

#else
			Item[i].PtrData = FP_GetMsg((unsigned int)(DWORD_PTR)Init[i].Data);
#endif
		else
#ifndef UNICODE
			strcpy(Item[i].Data, Init[i].Data);

#else
			Item[i].PtrData = Init[i].Data;
#endif
	}
}
