
#import "FtpSession.h"
#import "FtpConnection.h"
#import "FtpFileSystem.h"
#import "FtpFile.h"
#import "FtpDirectory.h"
#import "FtpBrowserCell.h"
#import "FtpHost.h"
#import "Controller.h"
#import "DirPanel.h"
#import "NXmystd.h"
#import <remote/NXProxy.h>
#import <sys/timeb.h>

void ftime(struct timeb *tp); // This is defined nowhere in the headers !

int my_chdir(const char *path);
void my_unchdir();
FILE *my_fopen(const char *path,const char *name,const char *mode);

@implementation FtpSession

- initForHost:host;
{
	[super init];

	//puts("1");
	if (! [NXApp loadNibSection:"YftpWindow.nib" owner:self withNames:NO])
		return nil;

	//puts("2");
	controller = [NXApp delegate];
	ftpHost = host;
	ftpConn = fileSystem = nil;
	username = [ftpHost user];
	password = [ftpHost pass];
	localpath = [ftpHost localPath];
	//printf("saved localpath:%s\n",localpath);
	if (![self testPath:localpath])
	{
		localpath = NXUniqueString(NXHomeDirectory());
	}
	//printf("localpath = %s\n",localpath);
	
	[self showLoginPanel:self];
	lastprogressupdatetime = 0;
	return self;
}

- showLoginPanel:sender;
{
	[userField setStringValue:username];
	[userField selectText:self];
	[passField setStringValue:"<default>"];
	[passField setTextGray:NX_DKGRAY];
	[passField setTextDelegate:self];
	//printf("init: gray = %f,DKGRAY=%f,gray == DKGRAY: %s\n",[passField textGray],NX_DKGRAY,[passField textGray] == NX_DKGRAY?"YES":"NO");
	[loginPanel setFrameUsingName:"loginPanel"];
	[loginPanel setFrameAutosaveName:"loginPanel"];
	[loginPanel makeKeyAndOrderFront:self];
	[loginPanel setTitle:[ftpHost name]];

	return self;
}

- free;
{
	ftpConn = [ftpConn free];
	fileSystem = [fileSystem free];
	loginPanel = [loginPanel free];
	loginPanel = [loginPanel free];
	defaultPanel = [defaultPanel free];
	return [super free];
}

- autoLoginHost:sender;
{
	if ([ftpHost useDefaultPass] == 2)
		[passField selectText:self];
	else
		[self loginHost:self];
	return self;
}

- loginHost:sender;
{
	//puts("logging in now !!!");
	
	username = NXUniqueString([userField stringValue]);
	//printf("loginHopst: gray = %f,DKGRAY=%f\n",[passField textGray],NX_DKGRAY);
	if ([passField textGray] > NX_LTGRAY)
	{
		//puts("fetch password");
		password = NXUniqueString([passField stringValue]);
	}
	else
		password = [ftpHost pass];

	if (username == emptyString || password == emptyString)
		return nil;
	[passField setStringValue:""];
	[loginPanel close];
	//printf("username = %s,password = %s\n",username,password);
	fileSystem = [ftpHost fileSystemForUser:username];
	if (!ftpConn)
		ftpConn = [[FtpConnection alloc] initFromSession:self];
	
	[fileSystem createDirsForPath:[ftpHost path]];

	[browser reuseColumns:NO];
	[browser setDelegate:fileSystem];
	[browser setTarget:self];
	[browser setDoubleAction:@selector(browserCellDoubleClicked:)];
	//[browser setMatrixClass:[FtpMatrix class]];
	[browser setCellClass:[FtpBrowserCell class]];
	//[browser setMinColumnWidth:20];
	[browser setMaxVisibleColumns:3];
	//[browser setMinColumnWidth:1];
	[browser acceptArrowKeys:YES andSendActionMessages:YES];

	[browser tile];
	[browser loadColumnZero];
	[browser setTitle:"/" ofColumn:0];
	[browser setPath:[ftpHost path]];
	[browser display];

	{
		char buf[1000];
		sprintf(buf,"%s@%s",username,[ftpHost name]);
		[[browser window] setTitle:buf];
		[[browser window] setFrameUsingName:buf];
		[[browser window] setFrameAutosaveName:buf];
		[[browser window] makeKeyAndOrderFront:self];
		[[browser window] setDelegate:self];
	}
	
	[consoleText setSelectable:YES];
	[progressView setMinValue:0];
	[progressView setMaxValue:1];
	[progressView setIntValue:0];

	// setup the queueBrowser (by Peter Lount)
	//puts("queue browser setup");
	[queueBrowser setDelegate:ftpConn];
	[queueBrowser setAction:@selector(singleClickInQueueBrowser)];
	[queueBrowser setDoubleAction:@selector(doubleClickInQueueBrowser)];
	//[queueBrowser setMatrixClass:[NiftyMatrix class]];
	[queueBrowser loadColumnZero];
	//puts("queue browser setup done");

	return self;
}

- (BOOL) textWillChange:sender;
{
	//printf("textWillChange: gray = %f,DKGRAY=%f\n",[passField textGray],NX_DKGRAY);
	if ([passField textGray] < NX_LTGRAY)
	{
		int len = [sender textLength];
		//puts("textWill....");
		[sender setSel:0:len];
		[sender replaceSel:""];
		[sender setSel:0:0];
		[passField setTextGray:NX_WHITE];
		[passField display];
	}
	return NO;
}

- openDefaultPanel:sender;
{
	[userDefaultField setStringValue:[ftpHost realUser]];
	[passDefaultField setStringValue:[ftpHost realPass]];
	[useUserDefaultRadio setState:[ftpHost useDefaultUser]];
	[usePassDefaultRadio setState:[ftpHost useDefaultPass]];
	[self defaultSwitchClicked:self];
	
	[hostDefaultField setStringValue:[ftpHost name]];
	[defaultPanel makeKeyAndOrderFront:self];
	[userDefaultField selectText:self];
	return self;
}
	
- defaultOk:sender;
{
	[ftpHost setUser:NXUniqueString([userDefaultField stringValue])];
	[ftpHost setPass:NXUniqueString([passDefaultField stringValue])];
	[ftpHost setUseDefaultUser:[useUserDefaultRadio state]];
	[ftpHost setUseDefaultPass:[usePassDefaultRadio state]];

	[userField setStringValue:[ftpHost user]];
	[passField setStringValue:"<default>"];
	[passField setTextGray:NX_DKGRAY];
	[passField setTextDelegate:self];

	[defaultPanel close];
	[loginPanel makeKeyAndOrderFront:self];
	[userField selectText:self];
	return self;
}

- defaultCancel:sender;
{
	[defaultPanel close];
	[loginPanel makeKeyAndOrderFront:self];
	return self;
}

- defaultSwitchClicked:sender;
{
	[userDefaultField setEnabled:![useUserDefaultRadio state]];
	[passDefaultField setEnabled:![usePassDefaultRadio state]];
	if (sender == useUserDefaultRadio && ![useUserDefaultRadio state])
		[userDefaultField selectText:self];
	if (sender == usePassDefaultRadio && ![usePassDefaultRadio state])
		[passDefaultField selectText:self];
	return self;
}

- openLocalPathPanel:sender;
{
	//printf("localpath = %s\n",localpath);
	[localPathPanel makeKeyAndOrderFront:self];
	[localPathField setStringValue:localpath];
	[localPathField selectText:self];
	return self;
}

- okLocalPath:sender;
{
	const char *newpath = [localPathField stringValue];
	
	if ([self testPath:newpath])
	{
		localpath = NXUniqueString(newpath);
		[localPathPanel performClose:self];
	}
	else
	{
		NXBeep();
		NXRunAlertPanel(NULL,"Directory not found",NULL,NULL,NULL);
		return nil;
	}
	return self;
}

- testPath:(const char *)path;
{
	char buf[1000];
	
	if (path)
		strcpy(buf,path);
	else
		strcpy(buf,NXHomeDirectory());
	if (my_chdir(path))
	{
		chdir(NXHomeDirectory());
		if (chdir(path))
		{
			my_unchdir();
			return nil;
		}
		//sprintf(buf,"%s/%s",NXHomeDirectory(),path);
	}
	my_unchdir();
	return self;
}

- openDirPanel:sender;
{
	id panel = [SavePanel new];
	
	[panel setDirectory:localpath];
	[panel setPrompt:"Directory:"];
	if ([panel dirPanelRunModal] == NX_CANCELTAG)
		return nil;
	
	[localPathField setStringValue:[panel directory]];
	[localPathField selectText:self];
	return self;
}

- okDefaultLocalPath:sender;
{	
	if ([self okLocalPath:self])
		[ftpHost setLocalPath:localpath];
	return self;
}

- setRemotePath:sender;
{
	char path[1000];
	[browser getPath:path toColumn:[browser lastColumn]];
	[ftpHost setPath:NXUniqueString(path)];
	return self;
}

- (NXAtom) user;
{
	return username;
}

- (NXAtom) pass;
{
	return password;
}

- ftpHost;
{
	return ftpHost;
}

- fileSystem;
{
	return fileSystem;
}

- ftpConn;
{
	return ftpConn;
}

- (NXAtom) hostName;
{
	return [ftpHost name];
}

- deactivateWindow;
{
	[NXApp deactivateSelf];
	return self;
}

// window delegate methods

- windowDidBecomeKey:sender;
{
	active = TRUE;
	[controller ftpDidActivate:self];
	[controller setProgress:-1:-1 from:self];
	return self;
}

- windowWillClose:sender;
{
	if ([browserWindow isDocEdited])
	{
		if (NX_ALERTDEFAULT != NXRunAlertPanel("Warning","There are filetransfers in progress. Really disconnect ?","OK","Cancel",NULL))
			return NO;
	}
	[ftpConn terminate];
	return YES;
}

- showQueue:sender; // (by Peter Lount)
{	/* Show the queue and set it's title to that of it's window with the word 'Queue' appended
	   so that it's easy to find in the list of windows. */
	char	aCharBuffer[401];
	sprintf(aCharBuffer, "%s - Queue", [ftpHost name]);
	[queueWindow setTitle: aCharBuffer];
	[queueWindow orderFront:self];
	return self;
}

- showConsole:sender; // (by Peter Lount)
{	/* Show the console and set it's title to that of it's window with the word 'Console' appended
	   so that it's easy to find in the list of windows. */
	char	aCharBuffer[401];
	sprintf(aCharBuffer, "%s - Console", [ftpHost name]);
	[[consoleText window] setTitle: aCharBuffer];
	[[consoleText window] orderFront:self];
	return self;
}

- (void oneway) console:(const char *)string;
{
	int len = [consoleText textLength];
	[consoleText setSel:len:len];
	[consoleText replaceSel:string];
	[consoleText scrollSelToVisible];
}

- showStatus:(const char *)string;
{
	[statusField setStringValue:string];
	[queueStatusField setStringValue:string];
	return self;
}

- showFilename:(const char *)string;
{
	[queueFilenameField setStringValue:string];
	return self;
}

- setProgressSize:(long)x;
{
	[progressView setMinValue:0];
	if (x != -1)
	{
		[progressView setMaxValue:x];
		[fileLengthField setIntValue:x];
	}
	else
	{
		[progressView setMaxValue:0];
		[fileLengthField setStringValue:"unknown"];
	}
	[progressView setIntValue:0];
	[fileProgressField setIntValue:0];
	return self;
}

- showProgress:(long)x;
{
	long now;
	struct timeb tp;
	int len = [fileLengthField intValue];
	ftime(&tp);
	now = tp.time*1000 + tp.millitm;
	
	if (now > lastprogressupdatetime + 20 || len <= x)
	{
		[progressView setFloatValue:x*0.995];
		[fileProgressField setIntValue:x];
		if (active)
			[controller setProgress:x:len from:self];
	}
	lastprogressupdatetime = now;
	return self;
}

- (void) setDirty:(BOOL)flag;
{
	[browserWindow setDocEdited:flag];
}

- validateBrowser;
{
	[browserWindow disableDisplay];
	//[browser validateVisibleColumns];
	[[browser delegate] validateBrowser:browser];
	[browserWindow reenableDisplay];
	[browserWindow displayIfNeeded];
	return self;
}

- browserCellSelected:sender;
{
	id list = nil;
	int i;
	
	LOGF("start");
	[browserWindow disableDisplay];
	//list = [sender cellList];
	//for (i=[list count]-1;i>=0;i--)
	//	[[[list objectAt:i] file] setSelected:NO];
	list = [sender getSelectedCells:nil];
	//printf("list count = %d\n",[list count]);
	for (i=[list count]-1;i>=0;i--)
	{
		id dir = [[list objectAt:i] file];
		//puts([dir name]);
		//[dir setSelected:YES];
		if (![dir isDir])
			continue;
		if ([dir needsCheck] || [dir needsUpdate])
		{
			//puts("dir needs check");
			[dir setShouldTransferIfNeeded];
			[ftpConn addToQueue:dir];
		}
		//[dir addSubDirsToCheckTo:ftpConn];
	}
	[self validateBrowser];
	[list free];
	[browserWindow reenableDisplay];
	[browserWindow displayIfNeeded];
	LOGF("ende");
    return self;
}

- browserCellDoubleClicked:sender;
{
	id	obj = [[sender selectedCell] file];
	
	[obj setShouldAutoOpen:YES];
	[self getIt:obj];
	return self;
}

- pressedGetButton:sender;
{
	static id list = nil;
	int i;
	
	[browserWindow disableDisplay];
	if (!list)
		list = [[List alloc] init];
	[browser getSelectedCells:list];
	//printf("list count = %d\n",[list count]);
	for (i=[list count]-1;i>=0;i--)
	{
		[self getIt:[[[list objectAt:i] file] setShouldAutoOpen:NO]];
	}
	[self validateBrowser];
	[list empty];
	[browserWindow reenableDisplay];
	//[browserWindow displayIfNeeded];
	[browserWindow display];
    return self;
}

- getIt:obj;
{
	FILE *fp;
	const char *name=[obj name];
	
	[obj setShouldReget:NO];
	[obj setLocalName:NULL];
	[obj setLocalPath:localpath];
	if ([obj isDir])
	{
		[obj setShouldTransferAlways];
		[ftpConn addToQueue:obj];
		return self;
	}
	fp = my_fopen(localpath,name,"r");
	fclose(fp);
	if (fp)
	{
		while(1)
		{
			int res = [controller showRegetPanelForFile:[obj name]];
			if (res == 0)
			{
				[obj setShouldReget:NO];
				break;
			}
			else if (res == 1)
			{
				[obj setShouldReget:YES];
				break;
			}
			else if (res == 2)
			{
				id savePanel = [SavePanel new];
				int ok = [savePanel runModalForDirectory:localpath file:name];
				const char *filename = [savePanel filename];
				if (ok != NX_OKTAG)
					continue;
				if (filename && strrchr(filename,'/'))
				{
					[obj setLocalPath:[savePanel directory]];
					[obj setLocalName:strrchr(filename,'/')+1];
					break;
				}
			}
			else
				return self;
		}
	}
	//LOGF("localpath = %s,localName = %s in file %s\n",localpath,[obj localName],[obj name]);
	[ftpConn addToQueue:obj];
	return self;
}

/* Queue Browser methods (by Peter Lount) */
- queueBrowser;
{
	return queueBrowser;
}

- queueAbortButtonPressed:sender;
{
	[ftpConn abortCurrentTransfer];
	return self;
}

@end
