#include <all_far.h>

#include "Int.h"

//------------------------------------------------------------------------
LPCSTR UType2Str(sliTypes tp)
{
	switch (tp) {
		case sltUrlList:
			return "URLS_LIST";
		case sltTree:
			return "URLS_TREE";
		case sltGroup:
			return "URLS_GROUP";
		default:
			HAbort("Url type not supported");
			return NULL;
	}
}
sliTypes Str2UType(LPCSTR s)
{
	if (StrCmpI(s, "URLS_LIST") == 0)
		return sltUrlList;

	if (StrCmpI(s, "URLS_TREE") == 0)
		return sltTree;

	if (StrCmpI(s, "URLS_GROUP") == 0)
		return sltGroup;

	return sltNone;
}
//------------------------------------------------------------------------
LPCSTR GetOtherPath(char *path)
{
	PanelInfo pi;

	do {
		if (FP_Info->Control(INVALID_HANDLE_VALUE, FCTL_GETANOTHERPANELSHORTINFO, &pi)
				&& pi.PanelType == PTYPE_FILEPANEL && !pi.Plugin)
			break;

		if (FP_Info->Control(INVALID_HANDLE_VALUE, FCTL_GETPANELSHORTINFO, &pi)
				&& pi.PanelType == PTYPE_FILEPANEL && !pi.Plugin)
			break;

		return FMSG(MFLErrGetInfo);
	} while (0);

	StrCpy(path, pi.CurDir, MAX_PATH);
	AddEndSlash(path, '/', MAX_PATH);
	return NULL;
}

void SayOutError(LPCSTR m, int tp = 0)
{
	LPCSTR itms[] = {FMSG(MFLErrCReate), NULL, FMSG(MOk)};
	itms[1] = m;
	FMessage(tp + FMSG_WARNING, NULL, itms, 3, 1);
}

void FTP::SaveList(FP_SizeItemList *il)
{
	LPCSTR m;

	if ((m = GetOtherPath(Opt.sli.path)) != NULL) {
		SayOutError(m);
		return;
	}

	strcat(Opt.sli.path, "ftplist.lst");

	if (!AskSaveList(&Opt.sli))
		return;

	FILE *f = fopen(Opt.sli.path, Opt.sli.Append ? "a" : "w");

	if (!f) {
		SayOutError(FMSG(MFLErrCReate), FMSG_ERRORTYPE);
		return;
	}

	PluginPanelItem *p;
	int n;
	int level;
	char str[1024 + 2], BasePath[1024 + 2], CurrentUrlPath[1024 + 2];
	CurrentUrlPath[0] = 0;
	snprintf(BasePath, ARRAYSIZE(BasePath), "%s%s%s%s", Opt.sli.AddPrefix ? "ftp://" : "",
			Opt.sli.AddPasswordAndUser ? Message("%s:%s@", hConnect->UserName, hConnect->UserPassword) : "",
			hConnect->hostname, hConnect->CurDir.c_str());
	AddEndSlash(BasePath, '/', ARRAYSIZE(BasePath));

	if (Opt.sli.ListType == sltTree)
		fprintf(f, "BASE: \"%s\"\n", BasePath);

	for (n = 0; n < il->Count(); n++) {
		p = il->Item(n);

		if (p->CRC32 & 0x80000000)
			continue;

		// URLS --------------------------------------
		if (Opt.sli.ListType == sltUrlList) {
			if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
				continue;

			FixFTPSlash(FTP_FILENAME(p));
			snprintf(str, ARRAYSIZE(str), "%s%s", BasePath, FTP_FILENAME(p));

			if (Opt.sli.Quote)
				QuoteStr(str);

			fprintf(f, "%s\n", str);
		} else

			// TREE --------------------------------------
			if (Opt.sli.ListType == sltTree) {
				StrCpy(str, FTP_FILENAME(p), ARRAYSIZE(str));
				FixFTPSlash(str);

				for (m = str, level = 0; (m = strchr(m, '/')) != NULL; m++, level++)
					;

				fprintf(f, "%*c", level * 2 + 2, ' ');
				m = strrchr(str, '/');

				if (m)
					m++;
				else
					m = str;

				fprintf(f, "%c%s",
						IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) ? '/' : ' ', m);

				if (Opt.sli.Size) {
					level = Max(1, Opt.sli.RightBound - 10 - level * 2 - 2 - 1 - (int)strlen(m));
					fprintf(f, "%*c", level, ' ');

					if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
						fprintf(f, "<DIR>");
					else
						fprintf(f, "%10llu", (long long unsigned int)p->FindData.nFileSize);
				}

				fprintf(f, "\n");
			} else

				// GROUPS ------------------------------------
				if (Opt.sli.ListType == sltGroup) {
					if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
						continue;

					FixFTPSlash(FTP_FILENAME(p));
					snprintf(str, ARRAYSIZE(str), "%s%s", BasePath, FTP_FILENAME(p));

					if (!IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
						*strrchr(str, '/') = 0;

					if (StrCmp(CurrentUrlPath, str, -1, FALSE) != 0) {
						StrCpy(CurrentUrlPath, str, ARRAYSIZE(CurrentUrlPath));
						fprintf(f, "\n[%s]\n", CurrentUrlPath);
					}

					StrCpy(str, FTP_FILENAME(p), ARRAYSIZE(str));
					FixFTPSlash(str);
					m = strrchr(str, '/');

					if (m)
						m++;
					else
						m = str;

					fprintf(f, " %s", m);

					if (Opt.sli.Size) {
						level = Max(1, Opt.sli.RightBound - 10 - (int)strlen(m) - 1);
						fprintf(f, "%*c%10llu", level, ' ', (long long unsigned int)p->FindData.nFileSize);
					}

					fprintf(f, "\n");
				}
	}

	fclose(f);
	LPCSTR itms[] = {FMSG(MFLDoneTitle), FMSG(MFLFile), Opt.sli.path, FMSG(MFLDone), FMSG(MOk)};
	FMessage(FMSG_LEFTALIGN, NULL, itms, 5, 1);
}
//------------------------------------------------------------------------
#define MNUM(v) (((int *)(v).Text)[128 / sizeof(int) - 1])
#define MSZ     (128 - (int)sizeof(int))

BOOL FTP::ShowFilesList(FP_SizeItemList *il)
{
	int cn, n, i, w, num;
	int Breaks[] = {VK_INSERT, VK_F2, 0}, BNumber;
	char str[500];
	PluginPanelItem *p;
	FarMenuItem *mi = NULL;
	char *m, *nm;

	if (!il || !il->Count())
		return FALSE;

	// Create|Recreate
	mi = (FarMenuItem *)realloc(mi, il->Count() * sizeof(FarMenuItem));
	memset(mi, 0, il->Count() * sizeof(FarMenuItem));
	// Scan number of items
	w = cn = 0;

	for (i = n = 0; n < il->Count(); n++) {
		p = il->Item(n);
		p->NumberOfLinks = StrSlashCount(FTP_FILENAME(p));
		p->CRC32&= 0x7fffffff;
		w = Max(w, static_cast<int>(strlen(PointToName(FTP_FILENAME(p)))) + (int)p->NumberOfLinks + 1);
		cn++;
		MNUM(mi[i++]) = n;
	}

	w = Min(Max(60, Min(w, MSZ)), FP_ConWidth() - 8);

	if (!cn) {
		free(mi);
		return FALSE;
	}

	// Calc length of size and count digits
	int szSize = 0, szCount = 0;

	for (n = 0; n < cn; n++) {
		p = il->Item(MNUM(mi[n]));
		FDigit(str, (int64_t)p->FindData.nFileSize, -1);
		szSize = Max(static_cast<int>(strlen(str)), szSize);

		if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
			FDigit(str, p->CRC32 & 0x7fffffff, -1);
			szCount = Max(static_cast<int>(strlen(str)), szCount);
		}
	}

	// Filename width
	w-= szSize + szCount + 6;

	// Set menu item text
	for (n = 0; n < cn; n++) {
		p = il->Item(MNUM(mi[n]));
		m = mi[n].Text;

		for (i = 0; i < (int)p->NumberOfLinks; i++) {
			*(m++) = ' ';
			*(m++) = ' ';
		}

		nm = PointToName(FTP_FILENAME(p));

		for (i = (int)(m - mi[n].Text); i < w; i++)
			if (*nm)
				*(m++) = *(nm++);
			else
				*(m++) = ' ';

		*(m++) = (*nm) ? FAR_SBMENU_CHAR : ' ';

		if (szSize) {
			*(m++) = ' ';
			*(m++) = FAR_VERT_CHAR;
			*(m++) = ' ';
			FDigit(str, p->FindData.nFileSize, -1);
			m+= sprintf(m, "%*s", szSize, str);
		}

		if (szCount) {
			*(m++) = ' ';
			*(m++) = FAR_VERT_CHAR;
			*(m++) = ' ';

			if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
				FDigit(str, p->CRC32 & 0x7fffffff, -1);
			else
				str[0] = 0;

			m+= sprintf(m, "%*s", szCount, str);
		}

		*m = 0;
	}

	num = -1;

	do {
		// Set selected
		for (n = 0; n < cn; n++)
			mi[n].Checked = (il->Items()[MNUM(mi[n])].CRC32 & 0x80000000) == 0;

		// Title
		int64_t tsz = 0, tcn = 0;

		for (n = 0; n < cn; n++) {
			p = il->Item(MNUM(mi[n]));

			if ((p->CRC32 & 0x80000000) == 0
					&& !IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
				tsz+= p->FindData.nFileSize;
				tcn++;
			}
		}

		StrCpy(str, FP_GetMsg(FMSG(MListTitle)), ARRAYSIZE(str));
		StrCat(str, " (", ARRAYSIZE(str));
		StrCat(str, FDigit(NULL, tsz, -1), ARRAYSIZE(str));

		if (il->TotalFullSize != tsz) {
			StrCat(str, "{", ARRAYSIZE(str));
			StrCat(str, FDigit(NULL, il->TotalFullSize, -1), ARRAYSIZE(str));
			StrCat(str, "}", ARRAYSIZE(str));
		}

		StrCat(str, "/", ARRAYSIZE(str));
		StrCat(str, FDigit(NULL, tcn, -1), ARRAYSIZE(str));

		if (tcn != il->TotalFiles) {
			StrCat(str, "{", ARRAYSIZE(str));
			StrCat(str, FDigit(NULL, il->TotalFiles, -1), ARRAYSIZE(str));
			StrCat(str, "}", ARRAYSIZE(str));
		}

		StrCat(str, ")", ARRAYSIZE(str));
		// Menu
		n = FP_Info->Menu(FP_Info->ModuleNumber, -1, -1, 0, FMENU_SHOWAMPERSAND, str,
				FP_GetMsg(FMSG(MListFooter)), "FTPFilesList", Breaks, &BNumber, mi, cn);

		// key ESC
		if (n == -1) {
			num = FALSE;
			break;
		}

		// key Enter
		if (BNumber == -1) {
			num = TRUE;
			break;
		}

		// Set selected
		if (num != -1)
			mi[num].Selected = FALSE;

		num = n;
		mi[num].Selected = TRUE;
		// Process keys
		bool set;

		switch (BNumber) {
				/*INS*/
			case 0:		// Current
				p = il->Item(MNUM(mi[num]));
				// Next item
				n = num + 1;
				// Switch selected
				set = (p->CRC32 & 0x80000000) == 0;
				p->CRC32&= 0x7fffffff;
				if (set)
					p->CRC32|= 0x80000000;

				// Switch all nested
				if (IS_FLAG(p->FindData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
					i = StrSlashCount(FTP_FILENAME(p));

					for (; n < cn; n++) {
						p = il->Item(MNUM(mi[n]));

						if (StrSlashCount(FTP_FILENAME(p)) <= i)
							break;

						p->CRC32&= 0x7fffffff;
						if (set)
							p->CRC32|= 0x80000000;
					}
				}

				// INS-moves-down
				if (n < cn) {
					mi[num].Selected = FALSE;
					mi[n].Selected = TRUE;
					num = n;
				}

				break;
				/*F2*/
			case 1:
				SaveList(il);
				break;
		}
	} while (true);

	free(mi);

	if (!num)
		return FALSE;

	return TRUE;
}
