/*  Controller.m --- Main controller object for the TextLab program.
**  Authors: Bruce Blumberg and Ali Ozer, NeXT Developer Support Group
**	8-14-90 Converted to 2.0 by Randy Nelson, NeXT Developer Training
**	Changed internal strings to external using NXStringTable
**	Removed outlet initializers
**	Removed 0.9 reference to Font Manager
**	9-7-90 Changed new method to use init, externally stored info panel
**
**	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.
*/

// Controller object is the central object in TextLab.  It manages the
// windows, open/save panels, and menu commands. 

#import "Controller.h"
#import "TextView.h"
#import <appkit/Application.h>
#import <objc/typedstream.h>
#import <objc/NXStringTable.h>
#import <appkit/FontManager.h>
#import <appkit/Font.h>

@implementation Controller

- init
{
  [super init];
  
  // get instances of support objects
  openReq = [OpenPanel new];
  saveReq = [SavePanel new];
  [self make2Windows];
  return self;
}


- infoPanel:sender
{
    if (infoPanel == nil) {
	[NXApp loadNibSection:"Info.nib" owner:self];
    }
    [infoPanel orderFront:sender];
    return self;
}

- showError: (const char *)errorMessage
{
  NXRunAlertPanel(NULL, errorMessage,
  		  [stringSet valueForStringKey:"OK"], NULL, NULL);
  return self;
}

// newTextView: is invoked in response to a new empty window request. It
// creates a new window containing a TextView. Note that we want new windows 
// to be offset from each other by some amount; hence the use of wRect.

#define ORIGX 0.0
#define ORIGY 0.0
// static NXRect wRect = {{ORIGX, ORIGY},{450.0,400.0}};
static NXRect sourceRect = {{120.0, 440.0},{800.0,300.0}};
static NXRect diagramRect = {{120.0, 100.0},{800.0,300.0}};

- make2Windows
{
    id diagramText;
    id sourceText;
    
    // diagramView = [self newTextView:self];
    diagramView = [[TextView alloc] initFrame:&diagramRect];
    // [[diagramView window] setDelegate:self];
    [[diagramView window] setTitle:"Diagram"];// replace "Untitled"  
    diagramText = [diagramView docView];
    [diagramText setFont:[Font  newFont:"IBMKlone" size:12.0 ]];
    
    [diagramText setDescentLine:0.0];
    [diagramText setLineHeight:36.0];
    [diagramText calcLine];    
  
    // sourceView = [self newTextView:self];
    sourceView = [[TextView alloc] initFrame:&sourceRect];
    [[sourceView window] setDelegate:self];
    [[sourceView window] setTitle:"SourceCode"];  // replace "Untitled"     

    sourceText = [sourceView docView];
    [sourceText selectText:self];
    [sourceText setDelegate:self]; // so we will get textDidGetKeys msg.
 
     return self;
}

- newTextView:sender
{
    //int i (int i);  /*counter*/
    id newTextView;
    NXOffsetRect(&sourceRect, 100.0, 100.0);
    if (sourceRect.origin.y < 0) {
    	sourceRect.origin.y = ORIGY;
	sourceRect.origin.x = ORIGX;
    }
    //for (i=1; i++);
    newTextView = [[TextView alloc] initFrame:&sourceRect];
    [[newTextView window] setDelegate:self];     
    [[newTextView window] setTitle:"SourceCode"/*,++i*/];  // replace "Untitled"     
    // return self;
    return newTextView;
}

// appAcceptsAnotherFile is an application delegate method which 
// returns whether it is OK for the application to try to open more files
// with the appOpenFile:type: method. TextLab can indeed open multiple
// windows, so we return YES.

-(BOOL) appAcceptsAnotherFile:sender
{
  return (YES);
}


// appOpenFile:type: is called to open the specified file. It is normally
// called by the Application object in response to open requests from the
// Workspace. Here we also route the open requests from the OpenPanel
// to this method (see openRequest:).

-(int) appOpenFile:(char *)fileName type:(char *)fileType
{
   return [self openFile:fileName];  
}

// openRequest: opens a new file. It puts up a open panel, and, if the user
// doesn't cancel, it reads the specified archive file. If the selected file
// is not a proper archive file, then openRequest: will complain.

- openRequest:sender
{
    const char *fileName;
    const char *const types[] = {[stringSet valueForStringKey:"extension"],
    				  "tl", NULL};

    if ([openReq runModalForTypes:types] && (fileName = [openReq filename])) {
	[self openFile:fileName];
    }
    else
	[self showError:[stringSet valueForStringKey:"errorOnOpenRequest"]];
    return self;
}

-(int) openFile:(const char *)fileName
{
   id win;
   NXTypedStream *typedStream;
   
    if(!(typedStream = NXOpenTypedStreamForFile(fileName,NX_READONLY))){
	[self showError:[stringSet valueForStringKey:"errorOnOpen"]];
	return NO;
    }
    else {
	win = NXReadObject(typedStream);
	NXCloseTypedStream(typedStream);
	[win setTitle:fileName];
	[win setDelegate:self];
        // [[win display] makeKeyAndOrderFront:self];
	[win display];
	[win makeKeyAndOrderFront:self];
	[self windowDidBecomeKey:win];  // don't know why, but need this
	                                // to get delegate notification
	[self saveRequest:self];
	return YES;
    } 
}


// saveRequest: saves the current window under its default name (found in
// the title bar). Note that if the title bar is empty or the default title
// is "SourceCode" then saveRequest: will put up a save panel, giving the user
// a chance to specify a real title.

- saveRequest:sender
{
    const char *fileName;
    const char *const types[2] = {[stringSet valueForStringKey:"extension"],
    				  NULL};
    
    id curWin = [NXApp mainWindow];
    [saveReq setRequiredFileType:types[0]];
    
    if (curWin == nil) 
	[self showError:[stringSet valueForStringKey:"errorOnSaveRequest"]];
    else {
	// Check to see if the current window is titled and the title is not
	// "Untitled". If so, save the file, else put up a save panel...
	fileName = [curWin title];
	
	printf("setString returns: %s\n", [stringSet valueForStringKey:"SourceCode"]);
	printf("setString returns: %s\n", [stringSet valueForStringKey:"Diagram"]);
    
        if (strcmp (fileName, [stringSet valueForStringKey:"Diagram"])) {
	   if (strcmp (fileName, [stringSet valueForStringKey:"SourceCode"]))
	      [self saveWindow:curWin inPath:fileName];
	   else 
	      [self saveInRequest:sender];
           }
        else
           [self showError:[stringSet valueForStringKey:"errorOnDiagramSave"]];
    }
    [curWin setDocEdited:NO];
    return self;
}

// saveInRequest: gives the user a chance to save the current window
// under a new name. 

- saveInRequest:sender
{
    const char *fileName;
    const char *const types[2] = {[stringSet valueForStringKey:"extension"],
    				  NULL};
    id		curWin;
    
    curWin = [NXApp mainWindow];
    [saveReq setRequiredFileType:types[0]];

    if (curWin == nil) 
	[self showError:[stringSet valueForStringKey:"errorOnSaveIn"]];
    else {
        fileName = [curWin title];
	if (strcmp (fileName, [stringSet valueForStringKey:"Diagram"])){ 
         // Get a file name from the user; use title of the window as default.
	 if (([saveReq runModalForDirectory:[stringSet valueForStringKey:"dot"]
						      file:[curWin title]]) &&
	      (fileName = [saveReq filename])) 
	    [self saveWindow:curWin inPath:fileName];}
         else {
	   [self showError:[stringSet valueForStringKey:"errorOnDiagramSave"]];
}
}
    [curWin setDocEdited:NO];
    return self;
}


// saveWindow writes a window out the archive file whose name is specified
// by the second argument. The title of the current window is also set 
// accordingly. 

- saveWindow:(id)win inPath:(const char *)name
{	
    NXTypedStream *typedStream;
    
    [win setTitle:name];
    typedStream = NXOpenTypedStreamForFile(name,NX_WRITEONLY);
    NXWriteRootObject(typedStream,win);
    NXCloseTypedStream(typedStream);
    return self;
}

// Printing is rather simple; just send printPSCode: to the text view
// you wish to print. The print panel will automatically pop up and unless
// the user cancels the printout the text view will be printed.

- printRequest:sender
{
    id curText = [[[NXApp mainWindow] contentView] docView];

    if (curText == nil) [self showError:[stringSet
    				    valueForStringKey:"errorOnPrintRequest"]];
    else {
	[[[NXApp printInfo] setHorizCentered:NO] setVertCentered:NO];
        [curText printPSCode:self];
    }
    return self;
}

// closeRequest closes the current window by simulating a click on the
// closebutton. A check should probably be added to give the user the 
// option of saving the window before closing

- closeRequest:sender
{
   id curWin = [NXApp mainWindow];
   
   if ([curWin isDocEdited])
   [self saveRequest:self];
   else
   [[NXApp mainWindow] performClose:sender];
   return self;
}

-showActionDiagram:sender
{
    [self writeSourceToTmp];
    //  [theDiagrammer formatDiagram];
    system("adroff -g tmpAdroffSource tmpAdroffDiagram");
    [self readDiagToWindow2];
    return self;
}

-writeSourceToTmp
{
    NXStream *stream;
    id sourceText;
    const char *fileName = "tmpAdroffSource";
    
    system("cp  /dev/null     tmpAdroffSource");
    sourceText = [sourceView docView];
    stream = NXMapFile(fileName, NX_WRITEONLY);       
    NXSeek(stream,0, NX_FROMSTART);  
    [sourceText writeText:stream];
    NXFlush(stream);
    NXSaveToFile(stream,fileName);
    NXCloseMemory(stream,NX_FREEBUFFER);
    return self;
}

- readDiagToWindow2
{
    NXStream *stream;
    id               diagText;
   
    const char *fileName = "tmpAdroffDiagram";

    diagText = [diagramView docView];
    stream = NXMapFile(fileName, NX_READONLY);       
    NXSeek(stream,0, NX_FROMSTART);  
    [diagText readText:stream];
    // NXFlush(stream);
    // NXSaveToFile(stream,fileName);
    NXCloseMemory(stream,NX_FREEBUFFER);
    return self;
}

/*
 * Delegate method for the document Text object. We use this method
 * to detect when the text in the window is modified.
 */
- textDidGetKeys:textObject isEmpty:(BOOL)flag 
{
    id curWin = [NXApp mainWindow];
    // id curWin = [NXApp keyWindow];
    //  if (![[sourceView window] isDocEdited]) 
    if (![curWin isDocEdited]) 
    {
    	[curWin setDocEdited:YES];
    }
    return NO;
}

- windowDidBecomeKey:sender
{
     id sourceText;
     sourceView = [sender contentView];
     sourceText = [[sourceView docView] setDelegate:self];
     // [sourceText setSel:(int)0 :(int)0];
     [sender becomeMainWindow];
     return self;
}

// Called just before the window closes.
- windowWillClose:sender
{
   id curWin = [NXApp mainWindow];
   
   if ([curWin isDocEdited]){
      [self saveRequest:self]; 
      }
   return self;
}

@end
