/**************************************************
 * SynthBuilder
 * Copyright 1993 Nick Porcaro All Rights Reserved
 **************************************************/

#import <stdlib.h>
#import <string.h>
#import <objc/List.h>
#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <appkit/Control.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import "ViewController.h"
#import "DragView.h"
#import "UGDef.h"
#import "UGMethodDef.h"
#import "UGArgDef.h"
#import "NGDef.h"
#import "NGArgDef.h"
#import "NFDef.h"
#import "NFMethodDef.h"
#import "NFArgDef.h"
#import "Controller.h"
#import "Utilities.h"

#import "ElementController.h"
extern id savePanel;
extern id openPanel;
extern char *getSavePath(char *banner);
extern char *getOpenPath(char *banner);
extern char *getAppName();

@implementation ElementController

static char TempString[1024];

- awakeFromNib
{

  if (! theViewController)
    {
      theViewController = [[ViewController alloc] init];
      [theViewController setMultiView:theMultiView];
      [theViewController setDragView:theDragView];
      [theViewController setFocusLock:NO];
    }

  [theDragView setViewController:theViewController];

  if (! theUGList)
    {
      theUGList = [[List alloc] init];
    }

  if (! theNFList)
    {
      theNFList = [[List alloc] init];
    }

  if (! theNGList)
    {
      theNGList = [[List alloc] init];
    }


// Only do this to bootstrap  [self buildStandardUGDefs];

  [self readStandardDefs];
  [theViewController switchViewToNumber:1];
  [theController displayMainWindow];
  [theViewController setFocusLock:YES];
  return self;
}

- init
{
  [super init];
  return self;
}

- switchView:sender
{
  [theViewController switchView:sender];
  return self;
}

- displayInspector:sender
{
  [theViewController displayInspector:sender];
  return self;
}

- readStandardDefs
{
  [self readStandardUGDefs:self];
  [self readStandardNGDefs:self];
  [self readStandardNFDefs:self];
  return self;
}

- readStandardUGDefs:sender
{
  int len;
  char *dir;
  char *path;

  if ( ! (dir = [utilities getAppDir]))
    {
      return self;
    }

  len = strlen(dir) + 100;
  path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  sprintf(path, "%s/StandardUGDefs", dir);
  [self readUGDefs:path];
  NXZoneFree([self zone], path);
  return self;
}

- readStandardNGDefs:sender
{
  int len;
  char *dir;
  char *path;

  if ( ! (dir = [utilities getAppDir]))
    {
      return self;
    }

  len = strlen(dir) + 100;
  path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  sprintf(path, "%s/StandardNGDefs", dir);
  [self readNGDefs:path];
  NXZoneFree([self zone], path);
  return self;
}

- readStandardNFDefs:sender
{
  int len;
  char *dir;
  char *path;

  if ( ! (dir = [utilities getAppDir]))
    {
      return self;
    }

  len = strlen(dir) + 100;
  path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  sprintf(path, "%s/StandardNFDefs", dir);
  [self readNFDefs:path];
  NXZoneFree([self zone], path);
  return self;
}


- setUGList: aUGList
{
  theUGList = aUGList;
  return self;
}

- setNGList: aNGList
{
  theNGList = aNGList;
  return self;
}

- setNFList: aNFList
{
  theNFList = aNFList;
  return self;
}

- getUGList
{
  return theUGList;
}

- getNGList
{
  return theNGList;
}

- getNFList
{
  return theNFList;
}

- initViews
/* Call setNGList/setNFList/setUGList first  */
{

  [self initUGView];
  [self initNFView];
  [self initNGView];
  return self;
}

- initUGView
{
  [theViewController initView: 1 
                      list: theUGList
                     class: [UGDef class]
                     name: "Unit Generators"];
  return self;
}

- initNGView
{
  [theViewController initView: 2
                      list: theNGList 
                     class: [NGDef class]
                     name: "Note Generators"];
  return self;
}

- initNFView
{
  [theViewController initView: 3
                      list: theNFList 
                     class: [NFDef class]
                     name: "Note Filters"];
  return self;
}


/************  This monster was the original way that
 ************ "FakeUGs" were defined in the old program
 ****************************************************/
#define MAXCONNECTIONS 5
#define MAXNOTEPARAMETERS 9     /* The number of rows in the FakeUG inspector also */
#define MK_UG 0
#define CLM_UG 1
#define PP_UG 2          // A PatchParameter
#define CLAV_UG 3        // A clavier
#define MIDI_UG 4        // A midi input
#define NF_UG 5          // A note filter (users should be able to add these)

#define INT 0
#define DOUBLE 1
#define ENV 2
#define BOOLEAN 3
#define DSPDATUM 4
#define PARTIALS 5

typedef struct
{
  char *niceName;
  char *type;
  int  ugType;     // Type of UG
  char *iconName;
  BOOL isEnvelopeHandler;
  BOOL isADSwitch;
  BOOL isData;
  BOOL isOscg;
  BOOL isSineROM;
  BOOL hasLength;
  BOOL hasConstant;
  BOOL isStorage;
  struct
    {
      char *methodName;
      int x;
      int y;
      BOOL isOutput;
    } connection[MAXCONNECTIONS];
  struct
    {
      char *methodName;
      int argType;
      char *defaultArgValue;
    } noteParameters[MAXNOTEPARAMETERS];
} oldFakeUGInfoType;

/* The first connection is for the output. */
/* 
 * The methods are in order that the corresponding memory segments are in
 * in the name of the include file.
 */ 
/* 
 * Also, synthdata, and the relevant memory issues, have not been handled
 * yet, i.e. for delay, Oscgaf, and Oscgafi.
 */
const oldFakeUGInfoType oldFakeUGInfo[] = 
{
/***************************************
Explanation of initialization for AllPass1UG:

type = Allpass1UG
iconName = allpass1
isEnvelopeHandler = isADSwitch = isData = isOscg = isSineROM = hasLength = hasConstant = NO

connection struct:
    methodName1 = setOutput: x1 = 28 x2 = 15
    methodName2 = setInput: x1 = 28 x2 = 15

noteParameters struct:
    methodName1 = setBB0 argType1 = DOUBLE
    defaultArgValue  = "0"

The number of connection and noteParameters 
is obtainable by finding out how many are non-NULL

***********************************/
  {"Allpass Filter", "Allpass1UG", MK_UG, "allpass1", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput:", 28, 42, NO}},
     {{"setBB0:", DOUBLE, "0"}}
  },
  {"Add2", "Add2UG", MK_UG, "add2", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
	{"setInput1:", 15, 42, NO},
	{"setInput2:", 40, 42, NO}},
     {}
  },
  {"Envelope", "AsympUG", MK_UG, "asymp", YES, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {{"setRate:", DOUBLE, "0"},
	{"setReleaseXScale:", DOUBLE, "0"},
	{"setTargetVal:", DOUBLE, "0"},
	{"setT60:", DOUBLE, "0"},
	{"setEnvelope: ...", ENV, ""}}
  },
  {"Constant", "ConstantUG", MK_UG, "constant", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {{"setConstant:", DOUBLE, "1.00"}}
  },
  {"Delay", "DelayUG", MK_UG, "delay", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 51, 28, YES},
	{"setInput:", 3, 28, NO},
	{"setDelayMemory:", 27, 28, NO}},
     {{"adjustLength:", INT, "0"}}
  },
  {"Dswitch", "DswitchUG", MK_UG, "dswitch", NO, YES, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
	{"setInput1:", 15, 42, NO},
	{"setInput2:", 40, 42, NO}},
     {{"setDelaySamples:", INT, "0"},
	{"setScale1:", DOUBLE, "0"}}
  },
  {"Dswitcht", "DswitchtUG", MK_UG, "dswitcht", NO, YES, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
	{"setInput1:", 15, 42, NO},
	{"setInput2:", 40, 42, NO}},
     {{"setDelayTicks:", INT, "0"},
	{"setScale1:", DOUBLE, "0"},
	{"setScale2:", DOUBLE, "0"}}
  },
  {"Interpolator", "InterpUG", MK_UG, "interp", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
	{"setInput1:", 17, 42, NO},
	{"setInput2:", 36, 42, NO},
	{"setInterpInput:", 26, 42, NO}},
     {}
  },
  {"Mult/add2", "Mul1add2UG", MK_UG, "mul1add2", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput1:", 15, 42, NO},
      {"setInput2:", 27, 42, NO},
      {"setInput3:", 40, 42, NO}},
     {}
  },
  {"Mult2", "Mul2UG", MK_UG, "mul2", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput1:", 15, 42, NO},
      {"setInput2:", 40, 42, NO}},
     {}
  },
  {"One pole filter", "OnepoleUG", MK_UG, "onepole", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput:", 28, 42, NO}},
     {{"setA1:", DOUBLE, "0"},
      {"setB0:", DOUBLE, "0"}}
  },
  {"One zero filter", "OnezeroUG", MK_UG, "onepole", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput:", 28, 42, NO}},
     {{"setB0:", DOUBLE, "0"},
      {"setB1:", DOUBLE, "0"}}
  },
  {"Osc", "OscgUG", MK_UG, "oscg", NO, NO, NO, YES, NO, NO, NO, NO,
     {{"setOutput:", 27, 15, YES},
	{"setTable:", 27, 29, NO}},
     {{"setInc:", INT, "0"},
	{"setFreq:", DOUBLE, "440.0"},
	{"setAmp:", DOUBLE, "0.5"},
	{"setPhase:", DOUBLE, "0.0"}}
  },
  {"Osc freq/amp", "OscgafUG", MK_UG, "oscgaf", NO, NO, NO, YES, NO, NO, NO, NO,
     {{"setOutput:", 27, 15, YES},
	{"setAmpInput:", 17, 43, NO},
	{"setIncInput:", 42, 43, NO},
	{"setTable:", 27, 29, NO}},
     {{"setIncScaler:", INT, "0"},   /* checked */
	{"setPhase:", DOUBLE, "0"},  /* checked */
	{"setIncRatio:", DOUBLE, "1.0"}}
  },
  {"Osc interp/freq/amp", "OscgafiUG", MK_UG, "oscgafi", NO, NO, NO, YES, NO, NO, NO, NO,
     {{"setOutput:", 27, 15, YES},
	{"setAmpInput:", 17, 43, NO},
	{"setIncInput:", 42, 43, NO},
	{"setTable:", 27, 29, NO}},
     {{"setIncScaler:", INT, "0"},
	{"setPhase:", DOUBLE, "0"},
	{"setIncRatio:", DOUBLE, "1.0"}}
  },
  {"Speaker A", "Out1aUG", MK_UG, "out1a", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setInput:", 28, 48, NO}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Speaker B", "Out1bUG", MK_UG, "out1b", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setInput:", 28, 48, NO}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Stereo Out", "Out2sumUG", MK_UG, "out2sum", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setInput:", 28, 48, NO}},
     {{"setBearing:", DOUBLE, "0"},  /* checked */
      {"setLeftScale:", DOUBLE, "1.0"}, /* checked */
      {"setRightScale:", DOUBLE, "1.0"}}
  },
  {"Scale", "ScaleUG", MK_UG, "scale", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 51, 28, YES},
      {"setInput:", 3, 28, NO}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Scale add2", "Scl1add2UG", MK_UG, "scl1add2", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput1:", 15, 42, NO},
      {"setInput2:", 40, 42, NO}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Scale2 add2", "Scl2add2UG", MK_UG, "scl2add2", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
      {"setInput1:", 15, 42, NO},
      {"setInput2:", 40, 42, NO}},
     {{"setScale1:", DOUBLE, "1.0"},
      {"setScale2:", DOUBLE, "1.0"}}
  },
  {"S Noise", "SnoiseUG", MK_UG, "snoise", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 27, 15, YES}},
     {}
  },
  {"U Noise", "UnoiseUG", MK_UG, "unoise", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 27, 15, YES}},
     {}
  },
  {"Constant PatchPoint", "Constantpp", MK_UG, "constantpp", NO, NO, YES, NO, NO, NO, YES, NO,
     {{"", 27, 29, YES}},
     {{"setToConstant", DSPDATUM, "1.0"}}
  },
  {"Partials", "Partials", MK_UG, "partials", NO, NO, YES, NO, NO, YES, NO, NO,
     {{"", 27, 29, YES}},
     {{"length", INT, "0"},
	{"partials", PARTIALS, "0"}}
  },
  {"Sine ROM", "SineROM", MK_UG, "sinerom", NO, NO, YES, NO, YES, NO, NO, NO,
     {{"", 27, 29, YES}},
     {}
  },
  {"Memory", "Storage", MK_UG, "storage", NO, NO, YES, NO, NO, YES, YES, YES,
     {{"", 27, 29, YES}},
     {{"length:", INT, "300"},
      {"setToConstant:", DSPDATUM, "1000"}}
  },
  {"Table Lookup", "TablookUG", MK_UG, "tablelookup", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutputAout:", 27, 15, YES},		// the output is on the bottom.
         {"setInputAinv:", 27, 42, NO},		// the input is on the top.
	 {"setAddressAtablook:",27, 30, NO}},	// the table is the center one	
     {{"setTableSize:", INT, "0"}}
  },
  {"Digital In A", "In1aUG", MK_UG, "in1a", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Digital In B", "In1bUG", MK_UG, "in1b", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {{"setScale:", DOUBLE, "1.0"}}
  },
  {"Biquad filter", "BiquadUG", MK_UG, "biquad", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES},
	{"setInput:", 28, 42, NO}},
     {
	{"setA1:", DOUBLE, "0.5"},
	{"setA2:", DOUBLE, "0.5"},
	{"setB1:", DOUBLE, "0.5"},
	{"setB2:", DOUBLE, "0.5"},
	{"setComplexPolesRadius:", DOUBLE, "0.5"},     /* Sorry only one argument for now */
	{"setComplexZerosRadius:", DOUBLE, "0.5"},     /* Sorry only one argument for now */
	{"setComplexPolesFrequency:", DOUBLE, "0.5"},  /* Sorry only one argument for now */
	{"setComplexZerosFrequency:", DOUBLE, "0.5"},  /* Sorry only one argument for now */
	{"setGain:", DOUBLE, "1.0"},                  /* I hope the default is reasonable */
	{"setFirstDelayedSample:", DOUBLE, "0"},    /* I hope the default is reasonable */
	{"setSecondDelayedSample:", DOUBLE, "0"}    /* I hope the default is reasonable */
     }
  },
  {"Patch Parameter", "PatchParameter", PP_UG, "PatchParameter", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setInput:", 28, 42, NO}},
     {}
  },
  {"Clavier", "Clavier", CLAV_UG, "Clavier", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {}
  },
  {"MIDI IN-A", "MIDI-A", MIDI_UG, "MIDI-A", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {}
  },
  {"MIDIIN-B", "MIDI-B", MIDI_UG, "MIDI-B", NO, NO, NO, NO, NO, NO, NO, NO,
     {{"setOutput:", 28, 15, YES}},
     {}
  }
};

#define NUM_UG_DEFS sizeof(oldFakeUGInfo)/sizeof(oldFakeUGInfoType)

- buildStandardUGDefs
/* This is legacy code that hopefully can go away real soon!
 * Call setUGList first 
 */
{
  int i, j;
  id aDef, aMethod, anArg;
  
  for (i=0; i<NUM_UG_DEFS; i++)
    {
      if (oldFakeUGInfo[i].ugType == MK_UG)
	{
	  aDef = [[UGDef alloc] init];
	  [theUGList addObject:aDef];
	  [aDef setMetaType:MK_UG];
	  [aDef setNibFile:"FakeUG.nib"];  /* Change if you dare */
	}
      else if (oldFakeUGInfo[i].ugType == PP_UG)
	{
	  aDef = [[UGDef alloc] init];
	  [theNFList addObject:aDef];
	  [aDef setMetaType:PP_UG];
	  [aDef setNibFile:"PatchParam.nib"];
          [aDef setIsPatchParameter:YES];
	}
      else if (oldFakeUGInfo[i].ugType == NF_UG)
	{
	  aDef = [[UGDef alloc] init];
	  [theNFList addObject:aDef];
	  [aDef setMetaType:NF_UG];
	  [aDef setNibFile:"NoteFilter.nib"];
          [aDef setIsNoteFilter:YES];
	}
      else if (oldFakeUGInfo[i].ugType == MIDI_UG)
	{
	  aDef = [[UGDef alloc] init];
	  [theNGList addObject:aDef];
	  [aDef setMetaType:MIDI_UG];
	  [aDef setNibFile:""];
          [aDef setIsMidi:YES];
	}
      else if (oldFakeUGInfo[i].ugType == CLAV_UG)
	{
	  aDef = [[UGDef alloc] init];
	  [theNGList addObject:aDef];
	  [aDef setMetaType:CLAV_UG];
	  [aDef setNibFile:"Clavier.nib"];
          [aDef setIsClavier:YES];
	}
      else
	{
	  aDef = nil;
	  printf("barf fart splat\n");
	}

      [(UGDef *) aDef setName:oldFakeUGInfo[i].niceName];
      [aDef setTheType:oldFakeUGInfo[i].type];
      [aDef setIconFile:oldFakeUGInfo[i].iconName];
      [aDef setIsEnvelopeHandler:oldFakeUGInfo[i].isEnvelopeHandler];
      [aDef setIsADSwitch:oldFakeUGInfo[i].isADSwitch];
      [aDef setIsData:oldFakeUGInfo[i].isData];
      [aDef setIsOscg:oldFakeUGInfo[i].isOscg];
      [aDef setIsSineROM:oldFakeUGInfo[i].isSineROM];
      [aDef setHasLength:oldFakeUGInfo[i].hasLength];
      [aDef setHasConstant:oldFakeUGInfo[i].hasConstant];
      [aDef setIsStorage:oldFakeUGInfo[i].isStorage];

      for (j=0; j<MAXCONNECTIONS; j++)
	{
	  if (oldFakeUGInfo[i].connection[j].methodName)
	    {
	      aMethod = [aDef addNewMethod:oldFakeUGInfo[i].connection[j].methodName];
	      [aMethod setIsOutput:oldFakeUGInfo[i].connection[j].isOutput];
	      [aMethod setXCoord:oldFakeUGInfo[i].connection[j].x];
	      [aMethod setYCoord:oldFakeUGInfo[i].connection[j].y];
	    }
	}
      
      for (j=0; j<MAXNOTEPARAMETERS; j++)
	{
	  if (oldFakeUGInfo[i].noteParameters[j].methodName)
	    {
	      anArg = [aDef addNewArg:oldFakeUGInfo[i].noteParameters[j].methodName];
	      [anArg setArgType:oldFakeUGInfo[i].noteParameters[j].argType];
	      [anArg setDefaultValue:oldFakeUGInfo[i].noteParameters[j].defaultArgValue];
	    }
	}

      printf("Added: %s icon: %s (index: %d)\n", [aDef getName], [aDef getIconFile], i);
    }
  

  return self;
}

- oldUGTypeToUGDef: (int) old_index
/* This converts an index into the old table
 * into a UGDef.  It does this by getting the type
 * name corresponding to old_index from theUGList
 */
{
  char *old_type;
  int i;

  if (old_index >= NUM_UG_DEFS)
    {
      NXRunAlertPanel(getAppName(), "Invalid index on attempt to convert", NULL, NULL, NULL);
      return nil;
    }

  if (! theUGList)
    {
      NXRunAlertPanel(getAppName(), "theUGList is nil", NULL, NULL, NULL);
      return nil;
    }

  old_type = oldFakeUGInfo[old_index].type;
  if (! old_type)
    {
      NXRunAlertPanel(getAppName(), "old_type is NULL", NULL, NULL, NULL);
      return nil;
    }

  for (i=0; i<[theUGList count]; i++)
    {
      if (strcmp(old_type, [[theUGList objectAt:i] getType]) == 0)
	{
	  return [theUGList objectAt:i];
	}
    }

  return nil;
    
}


- writeUGDefs:sender
{
  char *file;

  sprintf(TempString, "%s Save Unit Generator Defs", getAppName());
  file = getSavePath(TempString);
  if (! file)
    {
      return self;
    }

  [self writeDefsFrom:theUGList To:file];
  return self;
}

- writeNFDefs:sender
{
  char *file;

  sprintf(TempString, "%s Save Note Filter Defs", getAppName());
  file = getSavePath(TempString);
  if (! file)
    {
      return self;
    }

  [self writeDefsFrom:theNFList To:file];
  return self;
}

- writeNGDefs:sender
{
  char *file;

  sprintf(TempString, "%s Save Note Generator Defs", getAppName());
  file = getSavePath(TempString);
  if (! file)
    {
      return self;
    }

  [self writeDefsFrom:theNGList To:file];
  return self;
}

- writeDefsFrom: aList To:(char *) aFile
{
  NXTypedStream *ts;

  if (! aFile || ! aList)
    {
      return nil;
    }

  ts = NXOpenTypedStreamForFile(aFile, NX_WRITEONLY);
  NXWriteRootObject(ts, aList);
  NXCloseTypedStream(ts);
  return self;
}

- readUGDefsFromMenu:sender
{
  char *file;
  file = getOpenPath("Load Unit Generators");
  if (! file)
    {
      return self;
    }

  [self readUGDefs:file];
  return self;
}

- readNGDefsFromMenu:sender
{
  char *file;
  file = getOpenPath("Load Note Generators");
  if (! file)
    {
      return self;
    }

  [self readNGDefs:file];
  return self;
}

- readNFDefsFromMenu:sender
{
  char *file;

  file = getOpenPath("Load Note Generators");
  if (! file)
    {
      return self;
    }

  [self readNFDefs:file];
  return self;
}

- readUGDefs:(char *) file
{
  id aList;

  aList = [self readDefsFrom:file];
  if (aList)
    {
      [theUGList freeObjects];
      [theUGList free];
    }

  theUGList = aList;
  [self initUGView];
  [theViewController switchViewToNumber:1];
  return self;
}

- readNGDefs:(char *) file
{
  id aList;

  aList = [self readDefsFrom:file];
  if (aList)
    {
      [theNGList freeObjects];
      [theNGList free];
    }

  theNGList = aList;
  [self initNGView];
  [theViewController switchViewToNumber:2];
  return self;
}

- readNFDefs:(char *) file
{
  id aList;

  aList = [self readDefsFrom:file];
  if (aList)
    {
      [theNFList freeObjects];
      [theNFList free];
    }

  theNFList = aList;
  [self initNFView];
  [theViewController switchViewToNumber:3];
  return self;
}

static int defCompare(const void *def1, const void *def2)
{
  return strcmp([*(id *)def1 getName],[*(id *)def2 getName]);
}

- (List *) readDefsFrom: (char *) file
{
  NXTypedStream *ts;

  List *aList = nil;

  if (! file)
    {
      return nil;
    }

  ts = NXOpenTypedStreamForFile(file, NX_READONLY);
  if (! ts)
    {
      sprintf(TempString, "Error cannot open file: %s", file);
      NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
      return nil;
    }
      
  aList = NXReadObject(ts);
  NXCloseTypedStream(ts);

  if (! aList)
    {
      printf("ElementController nil list\n");
      return nil;
    }
  else
    {
      /* Sort the List and return it */
      [utilities sortList:aList sortFunction:defCompare];
      return aList;
    }
}

@end


