#include <all_far.h>


#include "Int.h"

FTP *FTP::Backups[ FTP_MAXBACKUPS ] = { 0 };
int  FTP::BackupCount = 0;

FTP::FTP()
{
	ResetCache = TRUE;
	ShowHosts = TRUE;
	SwitchingToFTP = FALSE;
	RereadRequired = FALSE;
	CurrentState = fcsNormal;
	*IncludeMask = 0;
	*ExcludeMask = 0;
	PluginColumnModeSet = FALSE;
	ActiveColumnMode = 0;
	NeedToSetActiveMode = FALSE;
	UrlsList = NULL;
	UrlsTail = NULL;
	QuequeSize = 0;
	OverrideMsgCode = ocNone;
	LastMsgCode = ocNone;
	*PanelTitle = 0;
	LongBeep = NULL;
	KeepAlivePeriod = Opt.KeepAlive ? FP_PeriodCreate(Opt.KeepAlive*1000) : NULL;
	hConnect = NULL;
	CallLevel = 0;

	Host.Init();
	memset(HostsPath, 0, sizeof(HostsPath));
	FP_GetRegKey("LastHostsPath",HostsPath,NULL,ARRAYSIZE(HostsPath));

	PanelInfo pi;
	FP_Info->Control(INVALID_HANDLE_VALUE,FCTL_GETPANELINFO,&pi);
	StartViewMode = pi.ViewMode;
}

FTP::~FTP()
{
	if(hConnect)
	{
		delete hConnect;
		hConnect = NULL;
	}

	FP_PeriodDestroy(KeepAlivePeriod);
	LongBeepEnd(TRUE);
	FP_Info->Control(this,FCTL_SETVIEWMODE,&StartViewMode);
	DeleteFromBackup();
	ClearQueue();
}

void FTP::Call(void)
{
	LastUsedPlugin = this;

	if(CallLevel == 0)
		LongBeepCreate();

	CallLevel++;
}
void FTP::End(int rc)
{
	if(rc != -156)
	{
		Log(("rc=%d",rc));
	}

	ShowMemInfo();

	if(!CallLevel) return;

	CallLevel--;

	if(!CallLevel)
	{
		LongBeepEnd();

		if(KeepAlivePeriod)
			FP_PeriodReset(KeepAlivePeriod);
	}
}
LPCSTR FTP::CloseQuery(void)
{
	if(UrlsList != NULL)
		return FMSG("Process queque is not empty");

	return NULL;
}

int FTP::GetFindData(PluginPanelItem **pPanelItem, int *pItemsNumber, int OpMode)
{
	PROC(("FTP::GetFindData",NULL))
	DWORD        b,e;
	char            *Data[3];
	*pPanelItem   = NULL;
	*pItemsNumber = 0;

//Hosts
	if(ShowHosts)
	{
		EnumHost        Enum(HostsPath);
		FP_SizeItemList il(FALSE);
		PluginPanelItem tmp;
		FTPHost         h;

		if(!IS_SILENT(OpMode))
		{
			memset(&tmp, 0, sizeof(tmp));
			strcpy(tmp.FindData.cFileName,"..");
			tmp.FindData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;

			if(!IS_SILENT(OpMode))
			{
				tmp.Description               = (char *)"..";
				tmp.CustomColumnNumber        = 3;
				tmp.CustomColumnData          = Data;
				tmp.CustomColumnData[0]       = (char *)"..";
				tmp.CustomColumnData[1]       = (char *)"..";
				tmp.CustomColumnData[2]       = (char *)"..";
			}

			if(!il.Add(&tmp))
				return FALSE;
		}

		while(true)
		{
			if(!Enum.GetNextHost(&h))
				break;

			if(!h.Read(NULL))
				continue;

			memset(&tmp, 0, sizeof(tmp));
			/* Panel item MUST have name the save as file saved to disk
			   in case you want to copy between panels work.
			*/
			h.MkINIFile(tmp.FindData.cFileName,NULL,"");
			tmp.FindData.ftLastWriteTime  = h.LastWrite;
			tmp.FindData.dwFileAttributes = h.Folder ? FILE_ATTRIBUTE_DIRECTORY : 0;
			tmp.Flags                     = PPIF_USERDATA;
			tmp.FindData.nPhysicalSize    = FTP_HOSTID;
			tmp.UserData                  = (DWORD_PTR)&h;

			if(!IS_SILENT(OpMode))
			{
				tmp.Description               = h.HostDescr;
				tmp.CustomColumnNumber        = 3;
				tmp.CustomColumnData          = Data;
				tmp.CustomColumnData[0]       = h.Host;  //C0
				tmp.CustomColumnData[1]       = h.Home;  //C1
				tmp.CustomColumnData[2]       = h.User;  //C2
			}

			if(!il.Add(&tmp))
				return FALSE;

			Log(("Item[%d]=[%s] attr=%08X",
			     il.Count()-1, FTP_FILENAME(il.Item(il.Count()-1)),
			     il.Item(il.Count()-1)->FindData.dwFileAttributes));
		}

		*pPanelItem   = il.Items();
		*pItemsNumber = il.Count();
		return TRUE;
	}

//FTP
	FP_Screen _scr;
	FTPFileInfo FileInfo;

	if(!hConnect)
	{
		goto AskConnect;
	}

Restart:

	if(!FtpFindFirstFile(hConnect, "*", &FileInfo, &ResetCache))
	{
		if(WINPORT(GetLastError)() == ERROR_NO_MORE_FILES)
		{
			*pItemsNumber = 0;
			return TRUE;
		}

		if(SwitchingToFTP && WINPORT(GetLastError)() == ERROR_CANCELLED)
		{
			;
		}
		else
		{
			if(CurrentState == fcsExpandList)
			{
				FreeFindData(*pPanelItem,*pItemsNumber);
				*pPanelItem   = NULL;
				*pItemsNumber = 0;
				return FALSE;
			}

//Query reconnect
			do
			{
				if(!hConnect)
					break;

				if(WINPORT(GetLastError)() == ERROR_CANCELLED)
					break;

				if(!hConnect->ConnectMessageTimeout(MConnectionLost,Host.HostName,-MRestore))
				{
					Log(("WaitMessage cancelled"));
					break;
				}

				if(FtpCmdLineAlive(hConnect) &&
				        FtpKeepAlive(hConnect))
					goto Restart;

				if(SelectFile.Length() && CurrentState != fcsExpandList)
					SaveUsedDirNFile();

AskConnect:

				if(Connect())
					goto Restart;
				else
					break;
			}
			while(true);
		}

		if(!ShowHosts)
			BackToHosts();

		FreeFindData(*pPanelItem, *pItemsNumber);
		return GetFindData(pPanelItem,pItemsNumber,OpMode);
	}

	GET_TIME(b);

	do
	{
		if(Opt.ShowIdle)
		{
			char str[ 200 ];
			GET_TIME(e);

			if(CMP_TIME(e,b) > 0.5)
			{
				snprintf(str,ARRAYSIZE(str),"%s%d", FP_GetMsg(MReaded), *pItemsNumber);
				WINPORT(SetLastError)(ERROR_SUCCESS);
				IdleMessage(str,Opt.ProcessColor);
				b = e;

				if(CheckForEsc(FALSE))
				{
					WINPORT(SetLastError)(ERROR_CANCELLED);
					return FALSE;
				}
			}
		}

		PluginPanelItem *NewPanelItem=*pPanelItem;

		if((*pItemsNumber % 1024) == 0)
		{
			if(!NewPanelItem)
				NewPanelItem = (PluginPanelItem *)malloc((1024+1)*sizeof(PluginPanelItem));
                        else {
                                PluginPanelItem *tmp  = (PluginPanelItem *)realloc(NewPanelItem,(*pItemsNumber+1024+1)*sizeof(PluginPanelItem));
                                if ( tmp ) NewPanelItem = tmp;
                                else {
					free(NewPanelItem);
					NewPanelItem = nullptr;
				     }
                             }
                        if(NewPanelItem == nullptr)
			{
				/*-*/Log(("GetFindData(file)::!reallocate plugin panels items %d -> %d",*pItemsNumber,*pItemsNumber+1024+1));
				return FALSE;
			}

			*pPanelItem=NewPanelItem;
		}

		PluginPanelItem *CurItem = &NewPanelItem[*pItemsNumber];
		memset(CurItem, 0, sizeof(PluginPanelItem));
		CurItem->FindData = FileInfo.FindData;

		if(!IS_SILENT(OpMode))
		{
			CurItem->CustomColumnNumber             = FTP_COL_MAX;
			CurItem->Owner                          = FileInfo.FTPOwner[0] ? strdup(FileInfo.FTPOwner) : NULL;
			CurItem->CustomColumnData               = (LPSTR*)malloc(sizeof(LPSTR*)*FTP_COL_MAX);
			CurItem->CustomColumnData[FTP_COL_MODE] = strdup(FileInfo.UnixMode);
			CurItem->CustomColumnData[FTP_COL_LINK] = strdup(FileInfo.Link);
//			hConnect->ToOEM(CurItem->CustomColumnData[FTP_COL_LINK]);
		}

		(*pItemsNumber)++;
	}
	while(FtpFindNextFile(hConnect,&FileInfo));

	return TRUE;
}

void FTP::FreeFindData(PluginPanelItem *PanelItem,int ItemsNumber)
{
	FP_SizeItemList::Free(PanelItem,ItemsNumber);
}

void FTP::SetBackupMode(void)
{
	PanelInfo  pi;
	FP_Info->Control(INVALID_HANDLE_VALUE, FCTL_GETPANELINFO, &pi);
	ActiveColumnMode = pi.ViewMode;
}

void FTP::SetActiveMode(void)
{
	NeedToSetActiveMode = TRUE;
	CurrentState        = fcsNormal;
}

BOOL FTP::isBackup(void)
{
	for(int n = 0; n < FTP::BackupCount; n++)
		if(FTP::Backups[n] == this)
			return TRUE;

	return FALSE;
}

void FTP::DeleteFromBackup(void)
{
	for(int n = 0; n < FTP::BackupCount; n++)
		if(FTP::Backups[n] == this)
		{
			memmove(&FTP::Backups[n], &FTP::Backups[n+1], (FTP::BackupCount-n)*sizeof(FTP*));
			FTP::BackupCount--;
		}
}

void FTP::AddToBackup(void)
{
	if(!Opt.UseBackups)
		return;

	if(!isBackup())
		FTP::Backups[ FTP::BackupCount++ ] = this;
}
