#include <unistd.h>
#import <Foundation/Foundation.h>

@interface MainLoop : NSObject<RunLoopEvents>
{
  NSFileHandle *fileHandle;
  NSString *prefix;
}
- (void)run;
- (void)close;
- (void)prompt;
- (NSString *)readFilename;
@end

@interface BackgroundReader : NSObject
{
  NSFileHandle *fileHandle;
}
- (void)runWithFilename: (NSString *)aFileName;
@end

@implementation BackgroundReader

- (void)dealloc
{
  [fileHandle release];
  [super dealloc];
}

- (void)runWithFilename: (NSString *)aFileName
{
  NSAutoreleasePool *pool = [NSAutoreleasePool new];
  NS_DURING
    {
      fileHandle =
	[[NSFileHandle fileHandleForReadingAtPath: aFileName] retain];
      if (fileHandle == nil)
	{
	  fputs("cannot be read\n", stdout);
	}
      else
	{
	  BOOL done = NO;
	  size_t size = 0;

	  sleep(1);
	  while (!done)
	    {
	      NSData *data = [fileHandle readDataOfLength: 4096];
	      if ([data length] == 0)
		{
		  done = YES;
		}
	      size += [data length];
	    }
	  fprintf(stdout, "%zd bytes read\n", size);
	  //[fileHandle closeFile];
	}
    }
  NS_HANDLER
    {
      NSLog(@"Exception in -runWithFilename: method: %@", localException);
    }
  NS_ENDHANDLER
  [pool release];
}

@end

@implementation MainLoop

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter]
    removeObserver: self
    name: NSThreadWillExitNotification
    object: nil];
  [fileHandle release];
  [prefix release];
  [super dealloc];
}

- (void)close
{
  fputs("[bye]\n", stdout);
  [[NSRunLoop currentRunLoop]
    removeEvent: 0 type: ET_RDESC forMode: NSDefaultRunLoopMode all: YES];
  [self release];
}

- (void)prompt
{
  fputs(GSDebugAllocationList(YES), stdout);
  fputs("> ", stdout);
  fflush(stdout);
}

- (NSString *)readFilename
{
  NSInteger n;
  char line[256];
  BOOL complete;

  if (!fgets(line, sizeof(line), stdin))
    {
      return nil;
    }

  n = strlen(line);
  complete = n > 0 && line[n-1] == '\n';
  if (complete)
    {
      line[n-1] = '\0';
    }

  NSString *string =
    [[NSString stringWithCString: line encoding: NSUTF8StringEncoding]
      stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
  if (prefix)
    {
      string = [prefix stringByAppendingString: string];
      [prefix release];
      prefix = nil;
    }
  if (!complete)
    {
      prefix = string;
      string = @"";
    }
  return string;
}

- (void)run
{
  fileHandle = [[NSFileHandle fileHandleWithStandardInput] retain];
  [[NSNotificationCenter defaultCenter]
    addObserver: self
    selector: @selector(prompt)
    name: NSThreadWillExitNotification
    object: nil];
  [[NSRunLoop currentRunLoop]
    addEvent: 0 type: ET_RDESC watcher: self forMode: NSDefaultRunLoopMode];
  [self retain];
  [self prompt];
  [[NSRunLoop currentRunLoop] run];
}

- (void)receivedEvent: (void *)data
		 type: (RunLoopEventType)type
		extra: (void *)extra
	      forMode: (NSString *)mode
{
  NSString *filename = [self readFilename];
  if (filename == nil || [filename isEqualToString: @"."])
    {
      [self close];
    }
  else if ([filename length] == 0)
    {
      [self prompt];
    }
  else
    {
      BackgroundReader *reader = [BackgroundReader new];
      [NSThread detachNewThreadSelector: @selector(runWithFilename:)
		toTarget: reader
		withObject: filename];
      [reader release];
    }
}

@end

int
main(int argc, char **argv)
{
  NSAutoreleasePool *pool = [NSAutoreleasePool new];
  GSDebugAllocationActive(YES);
  [[[MainLoop new] autorelease] run];
  [pool release];
  return 0;
}
