
#import "SchemeDelegate.h"

VScheme *vm = nil;


@implementation SchemeDelegate : NSObject 

- (void)applicationWillFinishLaunching:(NSNotification *)not
{
    // CREATE_AUTORELEASE_POOL(pool);
    NSMenu *menu, *info, *file, *scheme, *external, *env,
	*edit, *print, *services, *windows;

    //	Create the app menu
    menu = [NSMenu new];

    [menu addItemWithTitle: @"Info"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"File"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Edit"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Windows"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Scheme"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Environment"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Services"
	  action: NULL
	  keyEquivalent: @""];

    [menu addItemWithTitle: @"Hide"
	  action: @selector(hide:)
	  keyEquivalent: @"h"];

    [menu addItemWithTitle: @"Quit"
	  action: @selector(terminate:)
	  keyEquivalent: @"q"];

    // Create the scheme submenu
    scheme = [NSMenu new];
    [menu setSubmenu: scheme
	  forItem: [menu itemWithTitle: @"Scheme"]];

    [scheme addItemWithTitle: @"Reset"
	    action: @selector(reset:)
	    keyEquivalent: @"+"];

    [scheme addItemWithTitle: @"Evaluate"
	    action: @selector(evaluate:)
	    keyEquivalent: @"#"];

    [scheme addItemWithTitle: @"Evaluate external"
	    action:NULL
	    keyEquivalent: @""];

    external = [NSMenu new];
    [scheme setSubmenu: external
	    forItem: [scheme itemWithTitle: @"Evaluate external"]];
    [external addItemWithTitle: @"Add external"
	      action: @selector(addExternal:)
	      keyEquivalent: @""];


    // Create the environment submenu
    env = [NSMenu new];
    [menu setSubmenu: env
	  forItem: [menu itemWithTitle: @"Environment"]];

    [env addItemWithTitle: @"Up"
	 action: @selector(up:)
	 keyEquivalent: @""];

    [env addItemWithTitle: @"Down"
	 action: @selector(down:)
	 keyEquivalent: @""];

    // Create the info submenu
    info = [NSMenu new];
    [menu setSubmenu: info
	  forItem: [menu itemWithTitle: @"Info"]];

    [info addItemWithTitle: @"Info Panel..."
	  action: @selector(orderFrontStandardInfoPanel:)
	  keyEquivalent: @""];

/*  
    [info addItemWithTitle: @"Preferences..."
    action: NULL
    keyEquivalent: @""];
*/
    [info addItemWithTitle: @"Help"
	  action: @selector (orderFrontHelpPanel:)
	  keyEquivalent: @"?"];
    // RELEASE(info);

    // Create the file submenu
    file = [NSMenu new];
    [menu setSubmenu: file
	  forItem: [menu itemWithTitle: @"File"]];

    [file addItemWithTitle: @"Open Document"
	  action: @selector(openDocument:)
	  keyEquivalent: @"o"];

    [file addItemWithTitle: @"New Document"
	  action: @selector(newDocument:)
	  keyEquivalent: @"n"];

    [file addItemWithTitle: @"Save"
	  action: @selector(saveDocument:)
	  keyEquivalent: @"s"];

    [file addItemWithTitle: @"Save To..."
	  action: @selector(saveDocumentTo:)
	  keyEquivalent: @"t"];

    [file addItemWithTitle: @"Save As..."
	  action: @selector(saveDocumentAs:)
	  keyEquivalent: @"S"];

    [file addItemWithTitle: @"Save All"
	  action: @selector(saveDocumentAll:)
	  keyEquivalent: @""];

    [file addItemWithTitle: @"Revert to Saved"
	  action: @selector(revertDocumentToSaved:)
	  keyEquivalent: @"u"];

    [file addItemWithTitle: @"Close"
	  action: @selector(close)
	  keyEquivalent: @""];

    [file addItemWithTitle: @"Insert File..."
	  action: @selector(insertFile:)
	  keyEquivalent: @""];

    // RELEASE(file);

    // Create the edit submenu
    edit = [NSMenu new];
    [menu setSubmenu: edit
	  forItem: [menu itemWithTitle: @"Edit"]];

    [edit addItemWithTitle: @"Cut"
	  action: @selector(cut:)
	  keyEquivalent: @"x"];

    [edit addItemWithTitle: @"Copy"
	  action: @selector(copy:)
	  keyEquivalent: @"c"];

    [edit addItemWithTitle: @"Paste"
	  action: @selector(paste:)
	  keyEquivalent: @"v"];

    [edit addItemWithTitle: @"Delete"
	  action: @selector(delete:)
	  keyEquivalent: @""];
/*
  [edit addItemWithTitle: @"Undelete"
  action: NULL
  keyEquivalent: @""];
*/
    [edit addItemWithTitle: @"Select All"
	  action: @selector(selectAll:)
	  keyEquivalent: @"a"];
    // RELEASE(edit);

    // Create the windows submenu
    windows = [NSMenu new];
    [menu setSubmenu: windows
	  forItem: [menu itemWithTitle: @"Windows"]];

    [windows addItemWithTitle: @"Arrange"
	     action: @selector(arrangeInFront:)
	     keyEquivalent: @""];

    [windows addItemWithTitle: @"Miniaturize"
	     action: @selector(performMiniaturize:)
	     keyEquivalent: @"m"];

    [windows addItemWithTitle: @"Close"
	     action: @selector(performClose:)
	     keyEquivalent: @"w"];

    [windows addItemWithTitle: @"Close image windows"
	     action: @selector(closeImageWindows:)
	     keyEquivalent: @"W"];

    [windows addItemWithTitle: @"Close environment windows"
	     action: @selector(closeEnvWindows:)
	     keyEquivalent: @""];

    [NSApp setWindowsMenu: windows];
    // RELEASE(windows);

    // Create the service submenu
    services = [NSMenu new];
    [menu setSubmenu: services
	  forItem: [menu itemWithTitle: @"Services"]];

    [NSApp setServicesMenu: services];
    // RELEASE(services);

    [NSApp setMainMenu: menu];
    // RELEASE(menu);

    imageWindows = [NSMutableArray arrayWithCapacity:1];
    [imageWindows retain];

    envWindows = [NSMutableArray arrayWithCapacity:1];
    [envWindows retain];

    // RELEASE(pool);
}

- (void)applicationDidFinishLaunching: (NSNotification *)not;
{
    vm = [[VScheme alloc] init];
    [vm setDelegate:self];

    [self makeStatisticsPanel];
    [self makeInterruptPanel];
    [self makeInterpreterWindow];

    // Make the DocumentController the delegate of the application, 
    // as this is the only way I know to bring it into the responder chain
    [NSApp setDelegate:[NSDocumentController sharedDocumentController]];
}

NSWindow *interpreterWindow = nil;


- makeInterpreterWindow
{
    NSWindow *window;
    NSScrollView *scrollView;
    SCMInteractive *textView;
    NSRect scrollViewRect = {{0, 0}, {470, 400}};
    NSRect winRect = {{250, 100}, {470, 400}};
    NSRect textRect;
    unsigned int style = NSTitledWindowMask | 
        NSMiniaturizableWindowMask | NSResizableWindowMask;

    // This is expected to be retained, as it would normaly come from a
    // nib file, where the owner would retain it.
    window = [[NSWindow alloc] initWithContentRect: winRect
                               styleMask: style
                               backing: NSBackingStoreRetained
                               defer: NO];
    [window setMinSize:NSMakeSize(300, 300)];
   
    scrollView = [[NSScrollView alloc] initWithFrame: scrollViewRect];
    [scrollView setHasHorizontalScroller: NO];
    [scrollView setHasVerticalScroller: YES]; 
    [scrollView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
    [[scrollView contentView] setAutoresizingMask: NSViewHeightSizable 
                              | NSViewWidthSizable];
    [[scrollView contentView] setAutoresizesSubviews:YES];

    // Build up the text network
    textRect = [[scrollView contentView] frame];
    textView = [[SCMInteractive alloc] initWithFrame: textRect];

    [textView setBackgroundColor: [NSColor whiteColor]];

    [textView setString:GSCHEME];
    [textView appendString:@"> "];
    [textView setFont:[NSFont userFixedPitchFontOfSize:12]];

    [textView setDelegate:vm];
    [textView setHorizontallyResizable: NO];
    [textView setVerticallyResizable: YES];
    [textView setMinSize: NSMakeSize(0, 0)];
    [textView setMaxSize: NSMakeSize(1E7, 1E7)];
    [textView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
    [[textView textContainer] 
        setContainerSize:NSMakeSize(textRect.size.width, 1e7)];


    [[textView textContainer] setWidthTracksTextView: YES];
    // Store the text view in an ivar
    intTextView = textView;

    [scrollView setDocumentView: textView];
    // RELEASE(textView);
    [window setContentView: scrollView];
    // RELEASE(scrollView);

    // Make the Document the delegate of the window
    [window setDelegate: self];

    [window setTitle:@"GScheme"];
    [window display];
    [window makeKeyAndOrderFront:nil];
    // Make the text view the first responder
    [textView placeCursorAtEnd];
    [window makeFirstResponder:textView];

    interpreterWindow = window;

    return self;
}

- makeStatisticsPanel
{
    NSPanel *panel;
    NSScrollView *scrollView;
    SCMInteractive *textView;
    NSRect scrollViewRect = {{0, 0}, {470, 400}};
    NSRect winRect = {{450, 75}, {470, 400}};
    NSRect textRect;
    unsigned int style = NSTitledWindowMask | 
        NSMiniaturizableWindowMask | NSResizableWindowMask;

    // This is expected to be retained, as it would normaly come from a
    // nib file, where the owner would retain it.
    panel = [[NSPanel alloc] initWithContentRect: winRect
                               styleMask: style
                               backing: NSBackingStoreRetained
                               defer: NO];
    [panel setMinSize:NSMakeSize(300, 300)];
   
    scrollView = [[NSScrollView alloc] initWithFrame: scrollViewRect];
    [scrollView setHasHorizontalScroller: NO];
    [scrollView setHasVerticalScroller: YES]; 
    [scrollView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
    [[scrollView contentView] setAutoresizingMask: NSViewHeightSizable 
                              | NSViewWidthSizable];
    [[scrollView contentView] setAutoresizesSubviews:YES];

    // Build up the text network
    textRect = [[scrollView contentView] frame];
    textView = [[NSTextView alloc] initWithFrame: textRect];

    [textView setBackgroundColor: [NSColor whiteColor]];

    [textView setString:GSCHEME];
    [textView setEditable:NO];
    [textView setFont:[NSFont userFixedPitchFontOfSize:12]];

    [textView setDelegate:vm];
    [textView setHorizontallyResizable: NO];
    [textView setVerticallyResizable: YES];
    [textView setMinSize: NSMakeSize(0, 0)];
    [textView setMaxSize: NSMakeSize(1E7, 1E7)];
    [textView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
    [[textView textContainer] 
        setContainerSize:NSMakeSize(textRect.size.width, 1e7)];


    [[textView textContainer] setWidthTracksTextView: YES];
    // Store the text view in an ivar
    statTextView = textView;

    [scrollView setDocumentView: textView];
    // RELEASE(textView);
    [panel setContentView: scrollView];
    // RELEASE(scrollView);

    // Make the Document the delegate of the panel
    [panel setDelegate: self];
    [panel setWorksWhenModal:NO];

    // Make the text view the first responder
    // [panel makeFirstResponder:textView];
    [panel setTitle:@"GScheme Statistics"];
    [panel display];
    [panel orderFront:nil];

    return self;
}

#define IPCWIDTH   100
#define IPCHEIGHT   30


- makeInterruptPanel
{
    interruptPanel = 
	[[NSPanel alloc]
	    initWithContentRect:NSMakeRect(0, 0, IPCWIDTH, IPCHEIGHT)
	    styleMask:NSBorderlessWindowMask
	    backing:NSBackingStoreBuffered
	    defer:NO];
    [interruptPanel setReleasedWhenClosed:NO];

    NSButton *stopper;
    stopper = [NSButton new];
    [stopper setTitle:@"Stop"];
    [stopper setTarget:vm];
    [stopper setAction:@selector(interrupt:)];

    [interruptPanel setContentView:stopper];

    return self;
}

- (NSPanel *)interruptPanel
{
    return interruptPanel;
}


- input:(NSString *)data
{
    [intTextView appendString:data];
    return self;
}

- output:(NSString *)data
{
    [intTextView appendString:data];
    [intTextView placeCursorAtEnd];
    return self;
}

- result:(id)item
{
    [intTextView appendString:@"\n"];
    [intTextView appendString:[VScheme valToString:item]];
    [intTextView appendString:@"\n> "];
    [intTextView placeCursorAtEnd];
    return self;
}

- statistics:(NSString *)stats
{
    NSString *sofar = [statTextView string];
    [statTextView
	replaceCharactersInRange:NSMakeRange([sofar length], 0)
	withString:stats];

    [statTextView placeCursorAtEnd];

    return self;
}

- reset:(id)sender
{
    [vm reset:self];

    [intTextView setString:GSCHEME];
    [intTextView appendString:@"> "];
    [intTextView placeCursorAtEnd];
    [[intTextView window] makeFirstResponder:intTextView];

    [statTextView setString:GSCHEME];
}

- addExternal:(id)sender
{
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];

    [openPanel setTitle:@"Add external"];
    [openPanel setAllowsMultipleSelection:NO];
    [openPanel setPrompt:@"File:"];
    [openPanel setCanChooseDirectories:NO];

    if([openPanel 
	   runModalForTypes:
	       [NSArray arrayWithObject:@"scm"]]==NSOKButton){
	[[sender menu] addItemWithTitle:[openPanel filename]
		       action:@selector(evaluateExternal:)
		       keyEquivalent: @""];
    }

    return self;
}

extern VScheme *vm;
extern NSWindow *interpreterWindow;

extern int errno;

- evaluateExternal:(id)sender
{
    SCMInteractive *intView = 
        [[interpreterWindow contentView] documentView];
    NSString *suffix = [intView getSuffix];

    if([suffix length]>0){
        [intView appendString:@"\n> "];
    }

    NSString *progstr;
    if((progstr = 
	[NSString stringWithContentsOfFile:[sender title]])==nil){
	NSString *msg = @"Load failed";
	if(errno){
	    char *estr = strerror(errno);
	    msg = [msg stringByAppendingFormat:@": %s", estr];
	}

        NSRunAlertPanel(@"Error", msg, @"Ok", nil, nil);	
	return self;
    }

    BOOL res = [vm processString:progstr mode:MODE_EVALUATE];
    if(res==NO){
        NSRunAlertPanel(@"Error", [vm errmsg], 
                        @"Ok", nil, nil);
    }
    else{
        [interpreterWindow makeKeyAndOrderFront:self];
    }

    return self;
}


- imageWindow:(NSWindow *)window
{
    [imageWindows addObject:window];
    [window setDelegate:self];
    return self;
}

- envWindow:(NSWindow *)window
{
    [envWindows addObject:window];
    [window setDelegate:self];
    return self;
}

- (void)windowWillClose:(NSNotification *)aNotification
{
    NSWindow *win = [aNotification object];

    if([imageWindows containsObject:win]==YES){
        [imageWindows removeObject:win];
    }
    else if([envWindows containsObject:win]==YES){
        [envWindows removeObject:win];
    }
}

- closeImageWindows:(id)sender
{
    NSArray *cwins = [NSArray arrayWithArray:imageWindows];
    [cwins makeObjectsPerformSelector:@selector(close)];
    return self;
}

- closeEnvWindows:(id)sender
{
    NSArray *cwins = [NSArray arrayWithArray:envWindows];
    [cwins makeObjectsPerformSelector:@selector(close)];
    return self;
}

@end
