/* 

  Modified by :
          Gary F. Desrochers (garyd@slate.mines.colorado.edu)
          Sean Kerstiens     (skerstie@slate.mines.colorado.edu)

  Created For:
          Colorado School of Mines.

  Last edited: 
          June 22,1992

*/
// This was obtained from NextDevelopers examples.
// The following header was kept for completness.
/*
        CommandScroll.m
	by Joe Freeman
        Subprocess Example, Release 2.0
        NeXT Computer, Inc.

	You may freely copy, distribute and reuse the code in this example.
	NeXT disclaims any warranty of any kind, expressed or implied, as to
	its fitness for any particular use.
*/
// This file was edited by Gary F.Desrochers and Sean Kerstiens.
// at Colorado School of Mines to create logo for the NeXT.

#import "CommandScroll.h"
#import <appkit/nextstd.h>
#import <appkit/Font.h>
#import <appkit/Text.h>

@implementation CommandScroll

- initFrame:(const NXRect *)frameRect
{	
    [super initFrame:frameRect];
    [self setVertScrollerRequired: YES];
    [self setBackgroundGray: NX_WHITE];
    return [self awake];
}

- awake
{    
    NXRect textRect;
    id theText;

    // The following section sets up the scrolling Text within the View Object.

    textRect.origin.x = textRect.origin.y = 0.0;
    [self getContentSize: &(textRect.size)];
    theText =
	[[Text alloc]
	    initFrame: &textRect  text:NULL alignment: NX_LEFTALIGNED];
    [theText notifyAncestorWhenFrameChanged:YES];
    [theText setHorizResizable:NO];
    [theText setVertResizable:YES];
    textRect.size.width = 0.0;
    [theText setMinSize:&(textRect.size)];
    [self getContentSize: &(textRect.size)];
    textRect.size.height = 1000000;
    [theText setMaxSize:&(textRect.size)];
    [[theText superview] setAutoresizeSubviews:YES];
    [[theText superview] setAutosizing: NX_HEIGHTSIZABLE | NX_WIDTHSIZABLE];
    [theText setCharFilter: NXFieldFilter];
    [theText setMonoFont:FALSE];

    //  Now make the new Text object the Views view.

    [self setDocView: theText];

    //  Set up the two types of fonts to be displayed within the window.

    userFont = [Font newFont:"Courier-Bold" size:13];

    //  For right now set the machineFont to something that makes our splash
    //  introduction look better. (and kinda centers it)

    machineFont = [Font newFont:"Ohlfs-Bold" size:8];

    //  Setting up global perameters.  Look in the .h file for dicription
   //   of these.

    lastTextCount = [docView textLength];
    sameLine = YES;

    //  Now add the splash introduction.

    [self appendString:"                                                        Welcome to NeXT LOGO\n                                      Derived from the Public Domain program by\n                                            Children's Museum/LSRHS LOGO\n"];

    //  Change the fonts to what we want for normal operation.

    userFont = [Font newFont:"Courier-Bold" size:13];
    machineFont = [Font newFont:"Ohlfs" size:12];

    //  Append our prompt to the Text object.

    [self appendString:"?"];
    return self;
}

- setDocView:anObject
{
    // Make an object the docView.
    [super setDocView:anObject];
    docView = anObject;
    [docView setDelegate:self];
    return self;
}

/*==========================================================
 *
 * New method for subclass
 *
 *==========================================================*/
 
- appendString:(char *)buffer
    // append the buffer to the end of the text object
{
    [docView setSel:[docView textLength] :0];
    [docView setSelFont:machineFont];
    [docView replaceSel:buffer];
    [docView scrollSelToVisible];
    lastTextCount = [docView textLength];
    return [docView setSelFont:userFont];
}

/*==========================================================
 *
 * Text Object Delegation
 *
 *==========================================================*/
 
- (BOOL)textWillChange:textObject 
    // moving the selection to the end before the change means the keys
    // the user hits will always appear at the end of the scroll view
{
    [docView setSel:[docView textLength] :0];
    [docView setSelFont:userFont];
    [docView scrollSelToVisible];
    lastTextCount = [docView textLength];
    return NO;
}

- textDidEnd:textObject endChar:(unsigned short)whyEnd  
// Get this on every Return if using NXFieldFilter
// really simplistic.  Assumes user does not type ahead
// Maybe later on this can be incorporated into the logo code itself.
// It would be nice if the ReadChar in the logo code was this.
{
    [docView setSel:[docView textLength] :0];
    [docView replaceSel: "\n"];
    [self textDidGetKeys:textObject isEmpty:FALSE];
    return [self textDidGetKeys:textObject isEmpty:FALSE];
}

- textDidGetKeys:textObject isEmpty:(BOOL)flag 
// Send each character as it is entered.
// The delta calculation is in case the user has backspaced.
// For the logo programs purposes, this needed to be expanded so that
// it passed the whole string to the lexical analyser and parser.
// It does this when a return key is pressed.
{	
    int	delta;		// the difference in this length from previous
    int	theLength;	// current length of text object
    char *theText, miniBuffer[2];
    BOOL mallocedTheText = NO;
    theText = miniBuffer;
    
    theLength = [docView textLength];
    delta = theLength - lastTextCount;
    if (delta > 0)
    {
        theText = (char *)malloc(delta + 1);
        mallocedTheText = YES;
	[docView
	    getSubstring:theText
	    start:([docView textLength]-delta)
	    length:delta];
	theText[delta] = '\0';

        // Make sure you only enter this code when a return key was pressed.
        // Maybe later on the string can check for white space and ? marks 
        // then remove them.  Also it would be nice to know the difference
        // between a enter and a return and then change the logo code so 
        // that it would be able to know the difference.

	if(theText[delta-1] == '\n')
	{
           lastTextCount = theLength;
	   if (delegate && [delegate respondsTo:@selector(userEntered:)])
	    [delegate perform:@selector(userEntered:) with:(void *)theText];
	    sameLine = NO;
        }
    }

    // Now what if the line is just getting started.  Well do the following.
    // Because we need that prompt.

    else if(sameLine != YES || delta < 0)
    { 
        theText = miniBuffer;
	strcpy(theText,"?");
	if (delegate && [delegate respondsTo:@selector(userEntered:)])
	    [delegate perform:@selector(userEntered:) with:(void *)theText];
        sameLine = YES;
    }

    // If we had a new text then remove it because we don't need to keep it.
    // We can get it anytime we want from DocView.

    if (mallocedTheText)
        free(theText);
    return self;
}

@end
