
#import "FtpConnection.h"
#import "FtpSubThread.h"
#import "FtpSession.h"
#import "FtpDirectory.h"
#import "NXmystd.h"
#import <remote/NXProxy.h>

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


@implementation FtpConnection


- initFromSession:aSession;
{
	id nxConn;

	[super init];
	session = aSession;
	[session showFilename:""];
	
	queue = [[List alloc] init];

	// fire up the FtpSubThread
	status = FTP_NOCONN;
	connecttries=0;
	nxConn = [NXConnection registerRoot:[[FtpSubThread alloc] init]];
	[nxConn runInNewThread];
	//[nxConn setDelegate:self];
	[nxConn registerForInvalidationNotification:self];
	// get the proxy for the FtpConnection instance back from the NXConnection
	ftpSub = [NXConnection connectToPort:[nxConn inPort]];
	//printf("self = %p, ftpSub = %p,inPort = %p,outPort = %p\n",self, ftpSub,[nxConn inPort],[nxConn outPort]);
	// finally, run our side of the connection
	[[ftpSub connectionForProxy] runFromAppKit];
	// tell the subthread to connect to host (this is a oneway message, which returns immediately)
	[ftpSub setFtpConnection:self];
	[ftpSub connectToHost:[session hostName]];
	// ftpSub will tell us when its finished...
	
	return self;
}

- free;
{
	queue = [queue free];
	ftpSub = [ftpSub free];
	return [super free];
}
	
- terminate;
{
	[ftpSub closeConnection];
	return self;
}

- senderIsInvalid:sender;
{
	ERRORF("%p",sender);
	return self;
}

- addToQueue:obj;
{
	id	firstObj = [queue objectAt:0];
	
	if (status == FTP_CONNECTIONLOST)
	{
		connecttries=0;
		[ftpSub connectToHost:[session hostName]];
	}
	if (!firstObj)
		[queue addObject:obj];
	else
	{
		if (([obj isDir] || [obj isReadme]) && [firstObj isFile] && ![firstObj isReadme])
			shouldinterrupt = YES;
		[queue removeObject:obj];
		if ([obj isFile] && ![obj isReadme])
			[queue addObject:obj];
		else
			[queue insertObject:obj at:0];
	}
	[obj setTransferStatus:1];
	[self ping];
	[[session queueBrowser] loadColumnZero];
	return self;
}

- (BOOL)isInQueue:obj;
{
	return [queue indexOf:obj] != NX_NOT_IN_LIST;
}

- removeFromQueue:obj;
{
	[queue removeObject:obj];
	[obj setTransferStatus:0];
	[self ping];
	[[session queueBrowser] loadColumnZero];
	return self;
}

- ping;
{
	id obj = [queue objectAt:0];
	
	//printf("ping status:%d\n",status);
	if (status == FTP_OK)
	{
		shouldinterrupt = NO;
		if (obj)
		{
			char *aCharBufferPtr[1000];
			[obj fullPath:aCharBufferPtr];
			//printf("PING: obj %s\n",[obj name]);
			[session showFilename:aCharBufferPtr];
			[obj setTransferStatus:2];
			if ([obj isDir])
			{
				status = FTP_LISTINGDIR;
				[ftpSub listDir:obj];
			}
			else
			{
				status = FTP_GETTINGFILE;
				//puts("ping [ftpSub getFile:obj]");
				//LOGF("filename = |%s|",[obj name]);
				[ftpSub getFile:obj];
				//LOGF("filename = |%s|",[obj name]);
				//puts("ping after [ftpSub getFile:obj]");
			}
			currentFile = obj;
		}
		else
		{
			[session showFilename:""];
			currentFile = obj;
		}
	}
	[session setDirty:[queue count]?YES:NO];
	[session validateBrowser];
	return self;
}

- (BOOL)isTransferring;
{
	return (status == FTP_LISTINGDIR || status == FTP_GETTINGFILE);
}

- abortCurrentTransfer;
{
	if (currentFile)
	{
		shouldinterrupt = YES;
		[self removeFromQueue:currentFile];
	}
	return self;
}

- getDirForPath:(const char *)path;
{
	return [[session fileSystem] getDirForPath:path];
}

- (void oneway) console:(const char *)string;
{
	[session console:string];
}

// FtpResult protocol methods

- (void oneway) show:(const char *)string;
{
	[session showStatus:string];
}

- (void oneway) connected;
{
	status = FTP_CONNECTED;
	[session showStatus:"connected to host"];
	[ftpSub loginAsUser:[session user] withPassword:[session pass]];
}

- (void oneway) connectFailed:(const char *)error;
{
	status = FTP_ERROR;
	[session showStatus:error];
}

- (void oneway) loggedIn;
{
	status = FTP_OK;
	[session showStatus:"login successful"];
	[self ping];
}

- (void oneway) loginFailed:(const char *)error;
{
	status = FTP_ERROR;
	[session showStatus:error];
}

- (void oneway) checkingDir:dir;
{
	char buf[1000];
	
	if (status != FTP_LISTINGDIR)
		return;
	sprintf(buf,"checking directory '%s'",[dir path]);
	status = FTP_LISTINGDIR;
	[session showStatus:buf];
	[session validateBrowser];
}

- (void oneway) listingDir:dir;
{
	char buf[1000];
	
	if (status != FTP_LISTINGDIR)
		return;
	sprintf(buf,"retrieving directory '%s'",[dir path]);
	status = FTP_LISTINGDIR;
	[session showStatus:buf];
	[session validateBrowser];
}

- (void oneway) dirListed:dir;
{
	if (status != FTP_LISTINGDIR)
		return;
	status = FTP_OK;
	connecttries=0;
	[session showStatus:"directory retrieved"];
	[self removeFromQueue:dir];
}

- (void oneway) retrievingFile:file;
{
	char buf[1000];
	
	if (status != FTP_GETTINGFILE)
		return;
	sprintf(buf,"transferring file '%s'",[file name]);
	status = FTP_GETTINGFILE;
	[session showStatus:buf];
	[session setProgressSize:[file fileSize]];

	[session validateBrowser];
}

- (void oneway) fileRetrieved:file;
{
	char buf[1000];
	
	if (status != FTP_GETTINGFILE)
		return;
	status = FTP_OK;
	connecttries=0;
	[session showStatus:"filetransfer successful"];
	[self removeFromQueue:file];
	if ([file shouldAutoOpen])
	{
		LOGF("%s should Autoopen",[file name]);
		//[NXApp deactivateSelf];
		[session deactivateWindow];
		my_chdir([file localPath]);
		sprintf(buf,"open %s",[file localName]);
		system(buf);
		my_unchdir();
	}
}

- (void oneway) fileInterrupted:file;
{
	if (status != FTP_GETTINGFILE)
		return;
	status = FTP_OK;
	[session showStatus:"filetransfer interrupted"];
	[file setShouldReget:YES];
	[self ping];
}

- (void oneway) fileRetrievingFailed:(const char *)error;
{
	status = FTP_ERROR;
	[session showStatus:error];
}

- (void oneway) transferError:obj:(const char *)error;
{
	if (status != FTP_OK && status != FTP_LISTINGDIR && status != FTP_GETTINGFILE)
		return;
	status = FTP_OK;
	[session showStatus:error];
	[self removeFromQueue:obj];
	[[obj parentDir] setShouldTransferAlways];
	[self addToQueue:[obj parentDir]];
}
	
- (void oneway) socketError:(const char *)error;
{
	if (status != FTP_OK && status != FTP_LISTINGDIR && status != FTP_GETTINGFILE)
		return;
	status = FTP_ERROR;
	[session showStatus:error];
}


- (void oneway) unrecoverableError:(const char *)error;
{
	status = FTP_ERROR;
	[session showStatus:error];
}

- (void oneway) connectionLost:(const char *)error;
{
	if (status != FTP_OK && status != FTP_LISTINGDIR && status != FTP_GETTINGFILE)
		return;
	status = FTP_CONNECTIONLOST;
	[session showStatus:error];
	connecttries++;
	if (connecttries <3)
		[ftpSub connectToHost:[session hostName]];
	return;
}


- (void oneway) loggingOut;
{
	status = FTP_LOGGEDIN;
	[session showStatus:"logging out"];
}

- (void oneway) loggedOut;
{
	status = FTP_NOCONN;
	[session showStatus:"connection closed"];
}

- (BOOL) shouldStopAtPosition:(long)pos;
{
	//printf("pos = %d, shouldinterrupt = %d\n",pos,(int)shouldinterrupt);
	[session showProgress:pos];
	if (shouldinterrupt)
		return YES;
	else
		return NO;
}

/*
	Queue Browser delegate methods (by Peter Lount)
*/
- (int) browser:sender fillMatrix:matrix inColumn:(int)column;
{
	int		i;
	int		rows,
			cols;
	id		cell,
			obj;
	char	aCharBufferPtr[1000];
		
	[matrix getNumRows:&rows numCols:&cols];
//	printf("fillQueueMatrix: rows = %d,cols = %d\n",rows,cols);
	if (cols != 1)
	{
		NXBeep();
		exit(-1);
	}
	for (i=0;i<[queue count];i++)
	{
		obj = [queue objectAt:i];
		cell = [matrix cellAt:i:0];
		//printf("cell = %p,i=%d\n",cell,i);
		if ( ! cell )
		{
			[matrix insertRowAt:i];
			cell = [matrix cellAt:i:0];
			//printf("new cell = %p,i=%d\n",cell,i);
		}	
//		[cell setStringValue:[obj name]];
		
		[obj fullPath:aCharBufferPtr];
		[cell setStringValue:aCharBufferPtr];
		[cell setLeaf:YES];
		[cell setLoaded:YES];
	}
	return i;
}

- singleClickInQueueBrowser:sender;
{
/*
	id cell = [sender selectedCell];
	if (cell)
		[hostField setStringValue:[cell stringValue]];
	[hostField selectText:self];
*/
	return self;
}

- doubleClickInQueueBrowser:sender;
{
/*
	id cell = [sender selectedCell];
*/
	return self;
}

- matrixDidShuffle:sender; // we could use this to change the order of transfers
{
/*
	id	cellList = [sender cellList];
	int i,count = [cellList count];
	

	[browserList empty];
	for (i=0;i<count;i++)
	{
		 [browserList addObject:[self ftpHostForName:NXUniqueString([[cellList objectAt:i] stringValue])]];
	}
*/
	return self;
}

@end
