
#import "Controller.h"
#import "FtpSession.h"
#import "FtpHost.h"
#import "FtpFileSystem.h"
#import "NiftyMatrix.h"
#import "NXmystd.h"
#import "objc/objc-runtime.h"
#import "parser.h"
#import "ObjectError.h"

#define DIRCACHE DIRCACHE3

#define DIRCACHE3 ".NeXT/.YFtpDirectoryCache3"
#define DIRCACHE2 ".NeXT/.YFtpDirectoryCache2"
#define DIRCACHE1 ".NeXT/.YFtpDirectoryCache"

#define DEFAULTOBJECTVERSION 6


int my_chdir(const char *path);
void my_unchdir();


NXAtom	emptyString;


// For GatorFTP
@interface ClickCell:TextFieldCell
@end
@implementation ClickCell
@end

@implementation Controller

- appDidInit:sender
{
	NXTypedStream *stream;
	
	char buf[1000];
	sprintf(buf,"-%s@",NXUserName());
	[defaultUserField setStringValue:"ftp"];
	[defaultPassField setStringValue:buf];
	[defaultPathField setStringValue:"/pub"];
	[defaultLocalPathField setStringValue:NXHomeDirectory()];

	//malloc_debug(7);
	[ObjectError setup];
	objc_setMultithreaded(YES);
	[NXConnection setDefaultTimeout:-1];

	//parseHostAndFile("on fp server cis.uni-muenchen.de bla \n in the file /pub/next/Yftp.tar.gz !!");
	
	[[NXApp appListener] setServicesDelegate:self];

	sessionList = [[List alloc] init];
	emptyString = NXUniqueString("");
	
	chdir(NXHomeDirectory());
	if ((stream = NXOpenTypedStreamForFile(DIRCACHE3, NX_READONLY)))
	{
		int v;
		LOGF("Reading dircache !!!");
		NXReadType(stream,@encode(int),&v);
		[Object setVersion:v];
		if (v >= 6)
		{
			NXAtom s;
			NXReadType(stream,"%",&s);[defaultUserField setStringValue:s];
			NXReadType(stream,"%",&s);[defaultPassField setStringValue:s];
			NXReadType(stream,"%",&s);[defaultPathField setStringValue:s];
			NXReadType(stream,"%",&s);[defaultLocalPathField setStringValue:s];
		}
		hostList = NXReadObject(stream);
		browserList = NXReadObject(stream);
		NXCloseTypedStream(stream);
	}
	else if ((stream = NXOpenTypedStreamForFile(DIRCACHE2, NX_READONLY)))
	{
		LOGF("Reading OLD V2 dircache !!!");
		[Object setVersion:2];
		hostList = NXReadObject(stream);
		browserList = NXReadObject(stream);
		NXCloseTypedStream(stream);
	}
	else if ((stream = NXOpenTypedStreamForFile(DIRCACHE1, NX_READONLY)))
	{
		LOGF("Reading OLD V1 dircache !!!");
		[Object setVersion:1];
		hostList = NXReadObject(stream);
		browserList = NXReadObject(stream);
		NXCloseTypedStream(stream);
	}
	else
	{
		chdir([[NXBundle mainBundle] directory]);
		system("gzip -d < default.cache.gz > ~/.NeXT/.YFtpDirectoryCache3");
		chdir(NXHomeDirectory());
		stream = NXOpenTypedStreamForFile(DIRCACHE3, NX_READONLY);
		if (stream)
		{
			int v;
			LOGF("Reading DEFAULT DIRCACHE !!!");
			NXReadType(stream,@encode(int),&v);
			[Object setVersion:v];
			hostList = NXReadObject(stream);
			browserList = NXReadObject(stream);
			NXCloseTypedStream(stream);
		}
		else
		{
			puts("NO dircache found !");
			hostList = [[List alloc] init];
			browserList = [[List alloc] init];
		}
	}

	if ([Object version] <= 5) // Try to read .gatorftprc
	{
		[self openGatorWindow:self];
	}
	// setup the hostBrowser
	//puts("browser setup");
	[[hostBrowser window] setFrameUsingName:"hostBrowser"];
	[[hostBrowser window] setFrameAutosaveName:"hostBrowser"];
	[hostBrowser setDelegate:self];
	[hostBrowser setDoubleAction:@selector(hostDoubleClicked)];
	[hostBrowser setMatrixClass:[NiftyMatrix class]];
	[hostBrowser acceptArrowKeys:YES andSendActionMessages:YES];
	[hostBrowser loadColumnZero];
	//puts("browser setup done");
	
	[addButton setIcon:"NXreturnSign"];
	[loginButton setIcon:"NXreturnSign"];
	[self showHostWindow:self];
	
	// just for testing
	//ftp = [[FtpSession alloc] initForHost:"localhost" user:"ftp" pass:"yoda@"];
	//[sessionList addObject:ftp];
	
	chdir([[NXBundle mainBundle] directory]);
	[versionStrings readFromFile:"version.strings"];

	LOGF("compile version: %s\n",[versionStrings valueForStringKey:"Version"]);
	LOGF("cache version: %d\n",[Object version]);

	//defaultAppIconView = [[NXApp appIcon] contentView];
	//LOGF("appicon = %p,class = %s",defaultAppIconView,[defaultAppIconView name]);

	chdir("/");
	return self;
}

- appWillTerminate:sender;
{
	[[NXApp windowList] makeObjectsPerform:@selector(close)];
	/*
	puts("forking");
	if (fork())
	{
		sleep(5);
		puts("child exiting");
		exit(0);
	}
	sleep(10);
	puts("parent exiting");
	*/
	[self writeDirCache:self];
	return self;
}

- writeDirCache:sender;
{
	NXTypedStream *stream;
	
	[cachePanel makeKeyAndOrderFront:self];
	my_chdir(NXHomeDirectory());
	stream = NXOpenTypedStreamForFile(DIRCACHE, NX_WRITEONLY);
	if (stream)
	{
		int v=DEFAULTOBJECTVERSION;
		NXAtom s;
		LOGF("Writing DIRCACHE !!!");
		[Object setVersion:v];
		NXWriteType(stream,@encode(int),&v);
		if ([Object version] != 4)
		{
			s=[self defaultUser];NXWriteType(stream,"%",&s);
			s=[self defaultPass];NXWriteType(stream,"%",&s);
			s=[self defaultPath];NXWriteType(stream,"%",&s);
			s=[self defaultLocalPath];NXWriteType(stream,"%",&s);
		}
		NXWriteObject(stream,hostList);
		NXWriteObject(stream,browserList);
		NXCloseTypedStream(stream);
	}
	else
	{
		NXBeep();
		NXRunAlertPanel("ERROR","Couldnt WRITE dircache !!! !",NULL,NULL,NULL);
	}
	[cachePanel close];
	my_unchdir();
	return self;
}

- savingHost:(const char *)host;
{
	//LOGF("%s,%p",host, cacheSaveHostField);
	[cacheSaveHostField setStringValue:host];
	[[cacheSaveHostField window] display];
	return self;
}

- emptyCache:sender;
{
	puts("emptying CACHE");
	[hostList makeObjectsPerform:@selector(debugClearFileSystem)];
	[browserList makeObjectsPerform:@selector(debugClearFileSystem)];
	[hostBrowser loadColumnZero];
	return self;
}

- purgeCache:sender;
{
	puts("removing CACHE");
	chdir(NXHomeDirectory());
	unlink(DIRCACHE);
	chdir("/");
	hostList = [[List alloc] init];
	browserList = [[List alloc] init];
	[hostBrowser loadColumnZero];
	return self;
}

- showHostWindow:sender;
{
	[hostWindow makeKeyAndOrderFront:self];
	
	[hostField setTextDelegate:self];
	[hostField setStringValue:[[hostBrowser selectedCell] stringValue]];
	[hostField selectText:self];
	[self updateHostTextField];
    return self;
}

- (int) browser:sender fillMatrix:matrix inColumn:(int)column;
{
	int i;
	int rows,cols;
	id cell,obj;
	
	[matrix getNumRows:&rows numCols:&cols];
	//printf("fillHostMatrix: rows = %d,cols = %d\n",rows,cols);
	if (cols != 1)
	{
		NXBeep();
		exit(-1);
	}
	for (i=0;i<[browserList count];i++)
	{
		obj = [browserList 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]];
		[cell setLeaf:YES];
		[cell setLoaded:YES];
	}
	return i;
}

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

- matrixDidShuffle:sender;
{
	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])]];
	}
	[self updateHostTextField];
	return self;
}

- clickLoginButton;
{
	[loginButton performClick:self];
	return self;
}

- hostDoubleClicked;
{
	[[self loginHost:self] autoLoginHost:self];
	return self;
}

- loginHost:sender;
{
	NXAtom name = NXUniqueString([hostField stringValue]);
	id ftpHost;
	id session;
	
	if (name == emptyString)
		return nil;
	ftpHost = [self ftpHostForName:name];
	[hostWindow performClose:self];
	session = [ftpHost startSession];
	[sessionList addObject:session];
	return session;
}

- pressedEnter:sender;
{
	NXAtom name = NXUniqueString([hostField stringValue]);
	id ftpHost;
	
	[hostField selectText:self];
	if (name == emptyString)
		return nil;
	ftpHost = [self ftpHostForName:name];
	if ([browserList indexOf:ftpHost] == NX_NOT_IN_LIST)
	{
		[addButton performClick:self];
	}
	else
	{
		[loginButton performClick:self];
	}
	[self updateHostTextField];
	return self;
}

- addHost:sender;
{
	NXAtom name = NXUniqueString([hostField stringValue]);
	id ftpHost;
	
	[hostField selectText:self];
	if (name == emptyString)
		return nil;
	ftpHost = [self ftpHostForName:name];
	//printf("name=%s,ftphost=%p,browserlist=%p\n",name,ftpHost,browserList);
	[browserList addObjectIfAbsent:ftpHost];
	[hostBrowser loadColumnZero];
	[hostBrowser setPath:[ftpHost name]];
	[self updateHostTextField];
	return self;
}
	

- renameHost:sender;
{
	NXAtom s = NXUniqueString([hostField stringValue]);
	NXAtom t = NXUniqueString([[hostBrowser selectedCell] stringValue]);
	id host = [self ftpHostForName:t];
	if (strcmp(s,t)==0)
	{
		int i = [browserList indexOf:host];
		[browserList removeObject:host];
		[hostList removeObject:host];
		if (i >= [browserList count])
			i = [browserList count] - 1;
		[hostBrowser loadColumnZero];
		[hostBrowser setPath:[[browserList objectAt:i] name]];
		[hostField setStringValue:[[browserList objectAt:i] name]];
		//[host free];
	}
	else
	{
		[host renameTo:s];
		[hostBrowser loadColumnZero];
		[hostBrowser setPath:s];
	}
	[self updateHostTextField];
	return self;
}

- textDidGetKeys:sender isEmpty:(BOOL)flag;
{
	[self updateHostTextField];
	return self;
}

- updateHostTextField;
{
	NXAtom s = NXUniqueString([hostField stringValue]);
	NXAtom t = NXUniqueString([[hostBrowser selectedCell] stringValue]);

	if (!s || !*s)
	{
		[renameButton setEnabled:NO];
		[addButton setEnabled:NO];
		[loginButton setEnabled:NO];
		[addButton setIconPosition:NX_TITLEONLY];
		[loginButton setIconPosition:NX_TITLEONLY];
	}
	else
	{
		[loginButton setEnabled:YES];
		if (s == t)
		{
			[renameButton setEnabled:YES];
			[addButton setEnabled:NO];
			[renameButton setTitle:"REMOVE"];
			[addButton setIconPosition:NX_TITLEONLY];
			[loginButton setIconPosition:NX_ICONRIGHT];
		}
		else
		{
			int i,count = [browserList count];
			BOOL found = NO;
			for (i=0;i<count;i++)
			{
				if (s==[[browserList objectAt:i] name])
				{
					found = TRUE;
					break;
				}
			}
			[renameButton setTitle:"Rename"];
			if (found)
			{
				[renameButton setEnabled:NO];
				[addButton setEnabled:NO];
				[addButton setIconPosition:NX_TITLEONLY];
				[loginButton setIconPosition:NX_ICONRIGHT];
			}
			else
			{
				[renameButton setEnabled:YES];
				[addButton setEnabled:YES];
				[addButton setIconPosition:NX_ICONRIGHT];
				[loginButton setIconPosition:NX_TITLEONLY];
			}
		}
	}		
	return self;
}

- openGatorWindow:sender;
{
	NXTypedStream *stream;
	
	my_chdir(NXHomeDirectory());
	stream = NXOpenTypedStreamForFile(".gatorftprc", NX_READONLY);
	my_unchdir();
	if (stream)
	{
		id gatorScrollView,gatorList;
		int i;
		LOGF("Reading GATORFTPRC !!!");
		gatorScrollView = NXReadObject(stream);
		NXCloseTypedStream(stream);
		[gatorBox setContentView:gatorScrollView];
		[gatorBox display];
		[[gatorBox window] makeKeyAndOrderFront:self];
		if ([NXApp runModalFor:[gatorBox window]])
		{
			gatorList = [[gatorScrollView docView] cellList];
			for (i=0;i<[gatorList count];i++)
			{
				id ftpHost;
				NXAtom host;
				NXAtom defaultDir = NULL;
				char s[1000];
				char *s1;
				strcpy(s,[[gatorList objectAt:i] stringValue]);
				s1 = strchr(s,'\n');
				if (s1)
				{
					*s1 = '\0';
					s1++;
					if (strncmp(s1,":Directory:",strlen(":Directory:")) == 0)
					{
						char *s2 = strchr(s1,'\n');
						if (s2)
							*s2 = '\0';
						s1+= strlen(":Directory:");
						while(*s1 == ' ')
							s1++;
						defaultDir = NXUniqueString(s1);
					}
				}
				host = NXUniqueString(s);
				LOGF("GATORHost: %s",host);
				if (defaultDir)
					LOGF("GATORdir: %s",defaultDir);
				ftpHost = [self ftpHostForName:host];
				[browserList addObjectIfAbsent:ftpHost];
				if (defaultDir)
					[ftpHost setPath:NXUniqueString(defaultDir)];
			}
			[hostBrowser loadColumnZero];
			[hostBrowser display];
		}
		[[gatorBox window] close];
	}
	else
		NXRunAlertPanel([NXApp appName],"You are lucky, you don't have a .gatorftprc !",NULL,NULL,NULL);
	return self;
}	

- gatorOK:sender;
{
	[NXApp stopModal:1];
	return self;
}

- gatorCancel:sender;
{
	[NXApp stopModal:0];
	return self;
}
	
- ftpHostForName:(NXAtom)name;
{
	int i,count = [hostList count];
	id host=nil;
	
	for (i=0;i<count;i++)
	{
		host = [hostList objectAt:i];
		//printf("looking for %s, found %s\n",name,[host name]);
		if (name == [host name])
		{
			return host;
		}
	}
	//printf("creating %s\n",name);
	host = [[FtpHost alloc] initForName:name];
	[hostList addObject:host];
	return host;
}

- openPreferences:sender;
{
	[preferencesPanel makeKeyAndOrderFront:self];
	[defaultForm selectTextAt:0];
	return self;
}


// Methods forwarded to Ftp
// none :)

// Methods received from Ftp
- ftpDidActivate:sender
{
	activeFtp = sender;
	return self;
}

- setProgress:(long)pos :(long)len from:sender;
{
	if (sender == activeFtp)
	{
		if (pos == -1)
		{
			NXPoint thePoint = {8,8};
			[[NXApp appIcon] setContentView:defaultAppIconView];
			[defaultAppIconView display];
			[defaultAppIconView lockFocus];
			[[NXImage findImageNamed:"appicon"] composite:NX_SOVER toPoint:&thePoint]; 
			[defaultAppIconView unlockFocus];
			[[defaultAppIconView window] flushWindow];
		}
		else
		{
			[[NXApp appIcon] setContentView:progressIconView];
			[progressView setMinValue:0];
			if (len != -1)
			{
				[progressView setMaxValue:len];
				[progressView setFloatValue:pos*0.995];
				[fileProgressField setIntValue:pos];
				[fileLengthField setIntValue:len];
			}
			else
			{
				[progressView setMaxValue:0];
				[fileLengthField setStringValue:"???"];
			}
			[[NXApp appIcon] display];
		}
	}
	return self;
}

- (NXAtom) defaultUser;
{
	return NXUniqueString([defaultUserField stringValue]);
}

- (NXAtom) defaultPass;
{
	return NXUniqueString([defaultPassField stringValue]);
}

- (NXAtom) defaultPath;
{
	return NXUniqueString([defaultPathField stringValue]);
}

- (NXAtom) defaultLocalPath;
{
	return NXUniqueString([defaultLocalPathField stringValue]);
}

// help functions for regetPanel

- (int) showRegetPanelForFile:(const char *)name;
{
	[regetPanelHostField setStringValue:name];
	return [NXApp runModalFor:regetPanel];
}

- regetPanelButtonPressed:sender;
{
	if ([sender selectedCell])
	{
		[NXApp stopModal:[[sender selectedCell] tag]];
		[regetPanel close];
	}
	return self;
}

- ftpService: (id)pasteboard 
    userData:(const char *)userData 
    error:(char **)msg
{
    char *buffer, *data;
    int length;
    
    [pasteboard types];    // pretend to check the pasteboard types
    
    // read the ASCII data from the pasteboard
    if ([pasteboard readType:NXAsciiPboardType data:&data
        length:&length])
    {
        buffer = malloc(length+1);
        
        strncpy(buffer,data,length);
        buffer[length]='\0';
        
		parseHostAndFile(buffer);
        
        free(buffer);
		if (serviceHost)
		{
			id ftpHost;
			LOGF("host = %s,filename = %s",serviceHost,serviceFile);
	
			ftpHost = [self ftpHostForName:serviceHost];
			if ([browserList indexOf:ftpHost] == NX_NOT_IN_LIST)
			{
				[browserList addObject:ftpHost];
				[hostBrowser loadColumnZero];
			}
			if (serviceFile)
				[ftpHost setPath:serviceFile];
			[sessionList addObject:[ftpHost startSession]];
			[hostWindow close];
		}
		else
		{
			NXRunAlertPanel(NULL,"couldn't find host or file info in selection !",NULL,NULL,NULL);
		}
    
    }
    
    return self;
}


@end
