/*
 * Copyright (c) 1992, The Geometry Center
 *                     University of Minnesota 
 *                     1300 South Second Street
 *                     Minneapolis, MN  55454
 *
 * email address: software@geom.umn.edu
 *
 * This software is copyrighted as noted above.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the authors, who may or may not act on them as they desire.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 *
 *     The National Science and Technology Research Center for
 *      Computation and Visualization of Geometric Structures
 */

/* Generated by Interface Builder */

#include <string.h>
#import <objc/objc.h>
#include <stdio.h>
#include "link_types.h"
#include "link_edit_types.h"
#include "link_edit_global.h"
#include "link.h"
#import "Distributor.h"
#import "Link.h"
#import "EditView.h"
#import "DisplayView.h"
#import <appkit/Panel.h>
#import <appkit/Slider.h>
#import <appkit/Matrix.h>
#import <appkit/Box.h>
#import <appkit/Cell.h>
#import <appkit/Application.h>
#import <appkit/SavePanel.h>
#import <appkit/OpenPanel.h>
#import <zone.h>
#import <mach.h>
#import "fileops.h"
#import <objc/List.h>
#import <appkit/NXBrowser.h>
#import "LinkCell.h"
#include <stdlib.h>
#include <memory.h>
#import <appkit/NXImage.h>
#import "LabelField.h"
#import "FullView.h"
#import <streams/streams.h>

@implementation Distributor

- init
{
  NXZone *zone;
  [super init];
  zone = [self zone];
  [NXApp loadNibSection:"Inspector.nib" owner:self withNames:NO fromZone:zone];
  linkx = 91; linky = 222;
  list = [[List allocFromZone:zone] init];
  isBrowserValid = YES;
  nextUntNum = 1;
  return self;
}

- appDidInit:sender
{
  [toolPanel removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK];
  [toolPanel orderFront:self];
  [toolPanel setFloatingPanel:YES];
  return self;
}
  
- New:sender
{
  char *title = (char *) malloc(13);
  sprintf(title, "Untitled %d", nextUntNum++);
  return [self NewTitle:sender :title];
}

- NewFromFile:(const char *) filename
{
  NXTypedStream *infile = NXOpenTypedStreamForFile(filename, NX_READONLY);
  id linkObj = NXReadObject(infile);
  [[[linkObj get_window] setTitle:makeTitle(filename)] display];
  NXCloseTypedStream(infile);
  [list addObject:linkObj];
  return linkObj;
}

- NewTitle:sender :(char *) title
{
  id link;
  NXZone *newZone;
  newZone = NXCreateZone(vm_page_size, vm_page_size, YES);
  link = [[Link allocFromZone:newZone] initTitle:title];
  [list addObject:link];
  isBrowserValid = NO;  
  if (browser)
    {
      [browser validateVisibleColumns];
      isBrowserValid = YES;
    }
  return link;
}

- open:sender
{
  const char * const *filenames;
  char *filename = NULL;
  const char *directory;
  char *ext;
  int success, i;
  char *extensions[5];
  id linkObj;
  id openpanel = [OpenPanel new];
  extensions[0] = EXT_LINKTOOL;
  extensions[1] = EXT_EDITOR;
  extensions[2] = EXT_MATRIX;
  extensions[3] = EXT_FORMAT;
  extensions[4] = NULL;

  [openpanel setTitle:"Open new links"];
  [openpanel allowMultipleFiles:YES];
  success = [openpanel runModalForTypes:extensions];
  if (!success) return self;
  filenames = [openpanel filenames];
  directory = [openpanel directory];
  i = -1;

  /* Loop through list of filenames, and open each one */

  while (filenames[++i] != NULL)
    {
      /* Prepend directory path */
      filename = (char *) malloc(strlen(filenames[i]) + strlen(directory) + 5);
      strcpy(filename, directory);
      strcat(filename, "/");
      strcat(filename, filenames[i]);
      /* Determine type of file based solely on extension */
      ext = strrchr(filename,'.')+1;

      if (strcmp(ext, EXT_FORMAT) == 0)     /* formatted pages */
	{
	  [self makeKeyFormatControls:self];
	  [self openFormat:(const char *) filename];
	}
      else if (strcmp(ext, EXT_LINKTOOL) == 0)   /* Linktool format */
	[[self NewFromFile:(const char *) filename]
       setFileInfo:(const char *) filename :FF_LINKTOOL]; 
      
      else
	{
	  /* Create new link object */
	  linkObj = [self NewTitle:self : makeTitle(filename)];
	  
	  if (strcmp(ext, EXT_EDITOR) == 0)          /* link_edit format */
	    [linkObj loadEditor:(const char *) filename];
	  else if (strcmp(ext, EXT_MATRIX) == 0)     /* matrix format */
	    [linkObj loadMatrix:(const char *) filename];
	}
      free (filename);
    }
  isBrowserValid = NO;  
  if (browser)
    {
      [browser validateVisibleColumns];
      isBrowserValid = YES;
    }
  return self;
}

- save:sender
{
  const char *filename;
  char *copyS;
  if ([formatCP isKeyWindow] || [formatWindow isKeyWindow])
    {
      [fullView save];
      return self;
    }
  filename = [currentLinkObj get_linkfile];
  if (filename == NULL)
    return [self saveAs:self];
  copyS = malloc(strlen(filename)+1);
  strcpy(copyS, filename);
  [self doSave:(const char *) copyS :[currentLinkObj get_linkfileType]];
  [browser validateVisibleColumns];
  free(copyS);
  return self;
}

- saveAs:sender
{
  const char *filename;
  id savepanel;
  int success;    /* For savepanel event loop, then actual save */
  int current_type;
  if ([formatCP isKeyWindow] || [formatWindow isKeyWindow])
    {
      [fullView saveAs];
      return self;
    }
  savepanel = [SavePanel new];
  [savepanel setAccessoryView:saveAccessory];
  [savepanel setTitle:"Save link"];
  [savepanel setPrompt:"File:"];
  current_type = [[formatRB selectedCell] tag];
  [savepanel setRequiredFileType:
   ( current_type == FF_LINKTOOL ) ?
   EXT_LINKTOOL :
   (( current_type == FF_EDITOR ) ?
    EXT_EDITOR :
    (( current_type == FF_MATRIX) ?
     EXT_MATRIX :
     (( current_type == FF_STRINGBEAN) ?
      EXT_STRINGBEAN : EXT_THREE_D)))];
      
  success = [savepanel runModal];         /* Run the save panel */
  filename = [savepanel filename];
  if (!success)
    {
      [currentLinkObj printMessage:"Save cancelled."];
      return self;
    }
  [self doSave:filename :(char) [[formatRB selectedCell] tag]];
  [browser validateVisibleColumns];
  return self;
}

- doSave:(const char *) filename :(char) file_type
{
  switch(file_type)
    {
    case FF_LINKTOOL:
      [currentLinkObj saveLinktool:filename];
      break;
    case FF_EDITOR:
      [currentLinkObj saveEditor:filename];
      break;
    case FF_MATRIX:
      [currentLinkObj saveMatrix:filename];
      break;
    case FF_STRINGBEAN:
      [currentLinkObj saveSB:filename];
      break;
    case FF_THREE_D:
      [currentLinkObj saveThreeD:filename];
      break;
    }
  [[currentLinkObj get_window] setTitle:makeTitle(filename)];
  [currentLinkObj setFileInfo :filename :file_type];
  return self;
}

- changeType:sender
{
  id savepanel = [SavePanel new];
  int type = [[sender selectedCell] tag];
  switch(type)
    {
    case FF_LINKTOOL:
      [savepanel setRequiredFileType:EXT_LINKTOOL];      
      break;
    case FF_EDITOR:
      [savepanel setRequiredFileType:EXT_EDITOR];
      break;
    case FF_MATRIX:
      [savepanel setRequiredFileType:EXT_MATRIX];
      break;
    case FF_STRINGBEAN:
      [savepanel setRequiredFileType:EXT_STRINGBEAN];
      break;
    case FF_THREE_D:
      [savepanel setRequiredFileType:EXT_THREE_D];
      break;
    }
  return self;
}

- getNextWinLoc :(NXCoord *) x :(NXCoord *) y
{
  *x = linkx; *y = linky;
  linkx += 20; linky -= 20;
  return self;
}

/*** Inspector actions ***/

- showInspector:sender
{
  id newPanel;
  NXRect windowFrame;

  /* Determine the new panel to display */
  switch([sender get_mode])
    {
    case EDITOR:
      newPanel = editorInspector;
      break;
    case DISPLAYER:
      newPanel = displayerInspector;
      break;
    case CONWAY:
      newPanel = nonInspector;
      break;
    }
  
  /* Place panel left aligned with left of main window, underneath it */
  [[sender get_window] getFrame:&windowFrame];
  topLeftx = windowFrame.origin.x + windowFrame.size.width + 1;
  topLefty = windowFrame.origin.y + windowFrame.size.height;
  [newPanel moveTopLeftTo:topLeftx :topLefty];
  [newPanel orderFront:self];

  /* Get rid of old inpsector if it's up */
  if (inspectorOn && currentPanel != newPanel) [currentPanel close];

  inspectorOn = YES;
  currentPanel = newPanel;
  return self;
}

- switchInspectorTo: (char) mode
{
  id newPanel;
  if (!inspectorOn) return self;
  switch(mode)
    {
    case EDITOR:
      newPanel = editorInspector;
      break;
    case DISPLAYER:
      newPanel = displayerInspector;
      break;
    case CONWAY:
      newPanel = nonInspector;
      break;
    }
  if (newPanel == currentPanel)
    {
      [currentPanel display];
      return self;
    }
  [newPanel moveTopLeftTo:topLeftx :topLefty];
  [newPanel orderFront:self];
  inspectorOn = YES;
  if (currentPanel != newPanel) [currentPanel close];
  currentPanel = newPanel;
  return self;
}

/* Displayer inspector */

- redraw:sender
{
  [currentLinkObj doDraw:self];
  return self;
}

/*** Inspector settings ***/

/* Editor settings */

- updateESettings:sender
{
  int whichSetting;
  int value;
  id cell = [sender selectedCell];
  whichSetting = [cell tag];
  value = [cell state];
  switch(whichSetting)
    {
    case VERTICES:
      LinkSetVertices([currentLinkObj get_status], value);
      break;
    case RULERS:
      LinkSetRulers([currentLinkObj get_status], value);
      break;
    case ARROWS:
      LinkSetArrows([currentLinkObj get_status], value);
      break;
    case AXES:
      LinkSetAxes([currentLinkObj get_status], value);
      break;
    case ANCHOR_POINTS:
      LinkSetAnchors([currentLinkObj get_status], value);
      break;
    }
  [globalEditView lockFocus];
  [globalEditView clearScreen];
  [globalEditView ReDrawLinkTopWindow:[currentLinkObj get_status]];
  [globalEditView unlockFocus];
  return self;
}

/* Displayer settings */

/* Reads parameters from display inspector into obj's instance var's.
   Can be used to read parameters into displayView's var's, or linkObj's
   defaults */
- readParametersTo:(float **) values
{
  *values[0] = [ampSlider floatValue];
  *values[1] = [ampBSlider floatValue];
  *values[2] = [fffaSlider floatValue];
  *values[3] = [fffbSlider floatValue];
  *values[4] = [ppcSlider floatValue];
  *values[5] = [segMaxSlider floatValue];
  *values[6] = [segScaleSlider floatValue];
  *values[7] = [sepSlider floatValue];
  * (char *) values[8] = (char) [[textureRB selectedCell] tag];
  * (char *) values[9] = (char) [[redrawRB selectedCell] tag];
  * (char *) values[10] = (char) [rulersB state];
  * (char *) values[11] = (char) [arrowsB state];
  * (char *) values[12] = (char) [axesB state];
  * (char *) values[13] = (char) [verticesB state];
  * (char *) values[14] = (char) [anchorPointsB state];
  * (int *) values[15] = (int) [sparseSlider intValue];
  return self;
}

- writeParametersFrom:(float **) values
{
  [ampSlider setFloatValue:*values[0]];
  [ampText setFloatValue:  *values[0]];
  [ampBSlider setFloatValue:*values[1]];
  [ampBText setFloatValue:  *values[1]];
  [fffaSlider setFloatValue:  *values[2]];
  [fffaText setFloatValue:  *values[2]];
  [fffbSlider setFloatValue:  *values[3]];
  [fffbText setFloatValue:  *values[3]];
  [ppcSlider setFloatValue:  *values[4]];
  [ppcText setFloatValue:  *values[4]];
  [segMaxSlider setFloatValue:  *values[5]];
  [segMaxText setFloatValue:  *values[5]];
  [segScaleSlider setFloatValue:  *values[6]];
  [segScaleText setFloatValue:*values[6]];
  [sepSlider setFloatValue:  *values[7]];
  [sepText setFloatValue:*values[7]];
  [textureRB selectCellWithTag:(int) *(char *) values[8]];
  [redrawRB selectCellWithTag: (int) *(char *)values[9]];
  [rulersB setState:(int) *(char *)values[10]];
  [arrowsB setState:(int) *(char *)values[11]];
  [axesB setState:(int) *(char *)values[12]];
  [verticesB setState:(int) *(char *)values[13]];
  [anchorPointsB setState:(int) *(char *)values[14]];
  [sparseSlider setIntValue: * (int *) values[15]];
  [sparseText setIntValue: * (int *) values[15]];
  if (inspectorOn) [self switchInspectorTo:[currentLinkObj get_mode]];
  return self;
}

- (char) getRedrawType
{
  return (char) [[redrawRB selectedCell] tag];
}

/*** Tools managing methods ***/

- setTool:sender
{
  [currentLinkObj setEditorMode:[[sender selectedCell] tag]];
  return self;
}

- selectIfNecessary:(int) emode
{
  if ([[toolMatrix findCellWithTag:emode] state]) return self;
  [toolMatrix selectCellWithTag:emode];
  return self;
}


/******* Delegate methods (for inspector panels) *********/

- windowDidMove:sender
{
  NXRect winLoc;
  [sender getFrame:&winLoc];
  topLeftx = winLoc.origin.x;
  topLefty = winLoc.origin.y + winLoc.size.height;
  return self;
}

- windowWillClose:sender
{
  inspectorOn = NO;
  return self;
}

- windowDidResignKey:sender
{
  [self readParametersTo:[currentLinkObj get_parameters]];
  [currentLinkObj inactivateKeyEq];
  return self;
}

- windowDidBecomeKey:sender
{
  [currentLinkObj activateKeyEq];
  return self;
}

- applyToAll:sender
{
  return self;
}

- revert:sender
{
  return self;
}

- setDefaults:sender
{
  return self;
}

- Print:sender
{
  if ([formatCP isKeyWindow] || [formatWindow isKeyWindow])
    [fullView printPSCode:self];
  else
    [currentLinkObj print];
  return self;
}

- Quit:sender
{
  int button;
  button = NXRunAlertPanel(NULL, "Do you really want to quit?",
			   "Quit", "Certainly not", "Huh?");
  if (button == NX_ALERTALTERNATE)
    return self;
  if (button == NX_ALERTOTHER)
    {
      button = NXRunAlertPanel("Alert again", "I said, do you really want to quit?",
			       "Oh, sure, let's quit", "Nah, not now", NULL);
      if (button == NX_ALERTALTERNATE)
	return self;
    }
  [NXApp terminate:self];
  return self;
}

/*** Formatting methods ***/

- openFormat:(const char *) filename
{
  NXStream *stream = NXMapFile(filename, NX_READONLY);
  NXTypedStream *tstream = NXOpenTypedStream(stream, NX_READONLY);
  [fullView openList:tstream :filename];
  NXCloseTypedStream(tstream);
  NXCloseMemory(stream, NX_FREEBUFFER);
//  [fullViewBox setContentView:fullView];
  [formatWindow display];
  return self;
}
  

- makeKeyFormatControls:sender
{
  id linkCell = [[LinkCell alloc] myInit:"" :NULL];
  if (browser == NULL)
    {
      [NXApp loadNibSection:"Formatter.nib" owner:self
     withNames:NO fromZone:[self zone]];
      [browser setCellClass:[LinkCell class]];
      [browser setCellPrototype:linkCell];
    }
  [formatCP makeKeyAndOrderFront:self];
  [formatWindow makeKeyAndOrderFront:self];
  [browser validateVisibleColumns];
  return self;
}

- deleteMeFromList:link
{
  isBrowserValid = NO;
  [list removeObject:link];
  if (browser)
    {
      [browser validateVisibleColumns];
      isBrowserValid = YES;
    }
  return self;
}

- getNewList:(float) sideLength :(id *) imagelist :(id *) labellist
{
  int count = [list count], i;
  id cell, link, image;
  NXStream *stream;
  id newlist = [[List alloc] init];
  id lablist = [[List alloc] init];
  LabelField *label;
  BOOL oldION;

  oldION = inspectorOn;
  inspectorOn = NO;
  [fStatusPanel orderFront:self];
  [fStatusPanel display];
  for (i=0; i<count; i++)
    {
      NXSize size;
      BOOL loadReturn;
      cell = [browser getLoadedCellAtRow:i inColumn:0];
      if ([cell isHighlighted] == NO) continue;

      [fStatusText setStringValue:[cell stringValue]];
      [fStatusPanel display];
      [fStatusPanel flushWindow];
      NXPing();
      /* Draw link to stream */
      link = [cell link];
//      [[link get_window] makeKeyWindow];
      [link makeLinkActive];
      stream = NXOpenMemory(NULL, 0, NX_READWRITE);
      [link drawToStream:stream];
      NXSeek(stream, 0, NX_FROMSTART);
      
      /* Create NXImage from drawing */
      size.width = size.height = sideLength;
      image = [[NXImage alloc] initSize:&size];
      [image setDataRetained:YES];
      [image setScalable:YES];
      loadReturn = [image loadFromStream:stream];
      NXCloseMemory(stream, NX_FREEBUFFER);

      /* Make label */
      label = [[LabelField alloc] init];
      [label->textField setStringValue:[cell stringValue]];

      [newlist addObject:image];
      [lablist addObject:label];

      [link makeLinkInactive];
    }
  [fStatusPanel close];
  inspectorOn = oldION;
  *imagelist = newlist;
  *labellist = lablist;
  return self;
}

/* Browser delegate methods */

- (BOOL) browser:callingDude columnIsValid:(int) columnDude
{
  return isBrowserValid;
}

- (int) browser:sender fillMatrix:matrix inColumn:(int)column
{
  id browserCell, link, linkCell = [LinkCell new];
  char *title, *hallsOfMedicine;
  unsigned int i, count = [list count];
  [matrix setCellClass:[LinkCell class]];
  [matrix setPrototype:linkCell];
  for (i=0; i < count; i++)
    {
      link = [list objectAt:i];
      [matrix insertRowAt:0];
      browserCell = [matrix cellAt:0:0];
      hallsOfMedicine = (char *) [link get_linkfile];
      if (hallsOfMedicine == NULL)
	hallsOfMedicine = (char *) [[link get_window] title];
      else
	hallsOfMedicine = strrchr(hallsOfMedicine, '/') + 1;
      title = (char *) malloc(strlen(hallsOfMedicine)+1);
      strcpy(title, hallsOfMedicine);
      [browserCell myInit:title :link];
      [browserCell setLeaf:YES];
      [browserCell setLoaded:YES];
    }
  [linkCell free];
  [formatCP display];
  return count;
}

/****** Info panel joy ******/

- showInfo:sender
{
  if (infoPanel == NULL)
    [NXApp loadNibSection:"Info.nib" owner:self withNames:NO fromZone:[self zone]];
  [infoPanel makeKeyAndOrderFront:self];
  return self;
}



@end
