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

#import <stdlib.h>
#import <string.h>
#import "UGDef.h"
#import "UGMethodDef.h"
#import "UGArgDef.h"
#import "IconView.h"

extern char *getAppName();

@implementation UGDef

static char TempString[1024];

+ initialize
 /* Set the version. This can be used in a later version to distinguish older
  * formats when unarchiving documents. 
  */
{
  [UGDef setVersion:3];
  return self;
}

- init
{
  inspector = nil;
  isEnvelopeHandler = NO;
  isADSwitch = NO;
  isData = NO;
  isOscg = NO;
  isSineROM = NO;
  hasLength = NO;
  isStorage = NO;
  nibFile = NULL;
  nameString = NULL;
  typeString = NULL;
  iconName = NULL;
  currMethod = 0;
  currArg = 0;
  methods = [[List alloc] init];
  arguments = [[List alloc] init];
  return self;
}

- free
/* Free any mess we created */
{
  return [super free];
}

- takeNameFrom:sender
{
  [self setName:(char *) [sender stringValue]];
  return self;
}

- takeNibFileFrom:sender
{
  [self setNibFile:(char *) [sender stringValue]];
  return self;
}

- takeTypeFrom:sender
{
  [self setTheType:(char *) [sender stringValue]];
  return self;
}

- takeIconFrom:sender
{
  [self setIconFile:(char *) [sender stringValue]];
  [self showIcon];
  return self;
}

- setName:(char *) aName
{
  int len;

  if (! aName || ! (len = strlen(aName)))
    {
      return self;
    }

  if (nameString)
    {
      NXZoneFree([self zone], nameString);
    }

  len += 10;  // for good measure!
  nameString = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  
  strcpy(nameString, aName);
  [theNameField setStringValue:nameString];
  [self updateDisplay];
  return self;
}

- (char *) getName
{
  return nameString;
}

- setMetaType:(int) aType
{
  metaType = aType;
  return self;
}

- (int) getMetaType
{
  return metaType;
}

- setNibFile:(char *) fileName
{
  int len;

  if (! fileName || ! (len = strlen(fileName)))
    {
      return self;
    }

  if (nibFile)
    {
      NXZoneFree([self zone], nibFile);
    }

  len += 10;  // for good measure!
  nibFile = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  strcpy(nibFile, fileName);
  [theNibField setStringValue:nibFile];
  [self updateDisplay];
  return self;
}

- (char *) getNibFile
{
  return nibFile;
}

- (char *) getType
{
  return typeString;
}

- (char *) getIconFile
{
  return iconName;
}

- (char *) getMethodFieldValue
{
  return (char *) [theMethodField stringValue];
}

- setTheType:(char *) aType
{
  int len;

  if (! aType || ! (len = strlen(aType)))
    {
      return self;
    }

  if (typeString)
    {
      NXZoneFree([self zone], typeString);
    }

  len += 10;  // for good measure!
  typeString = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  
  strcpy(typeString, aType);
  return self;
}

- setIconFile:(char *) anIcon
{
  int len;

  if (! anIcon || ! (len = strlen(anIcon)))
    {
      return self;
    }

  if (iconName)
    {
      NXZoneFree([self zone], iconName);
    }

  len += 10;  // for good measure!
  iconName = (char *) NXZoneCalloc([self zone], len, sizeof(char));
  
  strcpy(iconName, anIcon);
  return self;
}

- showIcon
{
  [theIconView showImageInFile:iconName];
  return self;
}

- editIcon:sender
{
  sprintf(TempString, "open %s.tiff", iconName);
  system(TempString);
  return self;
}

- takeOptionFrom:sender
{
  int theTag, theValue;

  theTag = [[sender selectedCell] tag];
  theValue = [[sender selectedCell] intValue];

  switch (theTag)
    {
    case (0):
      {
	(theValue ? [self setIsEnvelopeHandler: YES] : [self setIsEnvelopeHandler: NO]);
	 break;
      }
    case (1):
      {
	(theValue ? [self setIsADSwitch: YES] : [self setIsADSwitch: NO]);
	 break;
      }
    case (2):
      {
	(theValue ? [self setIsData: YES] : [self setIsData: NO]);
	 break;
      }
    case (3):
      {
	(theValue ? [self setIsOscg: YES] : [self setIsOscg: NO]);
	 break;
      }
    case (4):
      {
	(theValue ? [self setIsSineROM: YES] : [self setIsSineROM: NO]);
	 break;
      }
    case (5):
      {
	(theValue ? [self setHasLength: YES] : [self setHasLength: NO]);
	 break;
      }
    case (6):
      {
	(theValue ? [self setHasConstant: YES] : [self setHasConstant: NO]);
	 break;
      }
    case (7):
      {
	(theValue ? [self setIsStorage: YES] : [self setIsStorage: NO]);
	 break;
      }
    default:
      {
	; /* Nothing */
      }
    }

  return self;
}

- updateOptionSwitch
{
  id matrix;
  matrix = theOptionSwitch;

  [[matrix cellAt:0:0] setIntValue: (isEnvelopeHandler ? 1 : 0)];
  [[matrix cellAt:1:0] setIntValue: (isADSwitch ? 1 : 0)];
  [[matrix cellAt:2:0] setIntValue: (isData ? 1 : 0)];
  [[matrix cellAt:3:0] setIntValue: (isOscg ? 1 : 0)];
  [[matrix cellAt:4:0] setIntValue: (isSineROM ? 1 : 0)];
  [[matrix cellAt:5:0] setIntValue: (hasLength ? 1 : 0)];
  [[matrix cellAt:6:0] setIntValue: (hasConstant ? 1 : 0)];
  [[matrix cellAt:7:0] setIntValue: (isStorage ? 1 : 0)];
  return self;
}

- setIsEnvelopeHandler:(BOOL) val
{
  isEnvelopeHandler = val;
  return self;
}

- setIsADSwitch:(BOOL) val
{
  isADSwitch = val;
  return self;
}

- setIsData:(BOOL) val
{
  isData = val;
  return self;
}

- setIsOscg:(BOOL) val
{
  isOscg = val;
  return self;
}

- setIsSineROM:(BOOL) val
{ 
  isSineROM = val;
  return self;
}

- setHasLength:(BOOL) val
{
  hasLength = val;
  return self;
}

- setHasConstant:(BOOL) val
{
  hasConstant = val;
  return self;
}

- setIsStorage:(BOOL) val
{
  isStorage = val;
  return self;
}

- setIsMidi:(BOOL) val
{
  isMidi = val;
  return self;
}

- setIsClavier:(BOOL) val
{
  isClavier = val;
  return self;
}

- setIsPatchParameter:(BOOL) val
{
  isPatchParameter = val;
  return self;
}

- setIsNoteFilter:(BOOL) val
{
  isNoteFilter = val;
  return self;
}

- (BOOL) isEnvelopeHandler
{
  return isEnvelopeHandler;
}

- (BOOL) isADSwitch
{
  return isADSwitch;
}

- (BOOL) isData
{
  return isData;
}

- (BOOL) isOscg
{
  return isOscg;
}

- (BOOL) isSineROM
{
  return isSineROM;
}

- (BOOL) hasLength
{
  return hasLength;
}

- (BOOL) hasConstant
{
  return hasConstant;
}

- (BOOL) isStorage
{
  return isStorage;
}

- (BOOL) isMidi
{
 return isMidi;
}

- (BOOL) isClavier
{
 return isClavier;
}

- (BOOL) isPatchParameter
{
  return isPatchParameter;
}

- (BOOL) isNoteFilter
{
  return isNoteFilter;
}

- methods
{
  return methods;
}


- addNewMethod:(char *) aName
{
  UGMethodDef *aMethod;

  if (! aName)
    {
      return self;
    }

  aMethod = [[UGMethodDef alloc] init];
  [aMethod initUGDef:self];
  [aMethod setName:aName];
  [methods addObjectIfAbsent:aMethod];

  return aMethod;
}

- editNewMethod:sender
{
  [self addNewMethod:(char *) [sender stringValue]];
  currMethod = [methods count] - 1;
  [self updateDisplay];
  [self editMethod:currMethod];
  return self;
}

- switchMethod:sender
/* Change the method being displayed on the inspector */
{
  int button;
  int num_methods;

  num_methods = [methods count];
  if (num_methods <= 0)
    {
      [self updateDisplay];
      return self;
    }

  /* button = -1 for top, 1 for botton */
  button = [[sender selectedCell] tag];
  currMethod += button;

  if (currMethod < 0)
    {
      currMethod = num_methods - 1;
    }
  else if (currMethod == num_methods)
    {
      currMethod = 0;
    }

  [self updateDisplay];
  return self;
}

- editCurrentMethod:sender
{
  [self editMethod:currMethod];
  return self;
}

- removeCurrentMethod:sender
{
  int count;

  count = [methods count];
  if (count > 0)
    {
      id anObj = [methods objectAt:currMethod];
      [anObj closeInspector];
      [methods removeObject:anObj];
      currMethod = 0;
    }

  [self updateDisplay];
  return self;
}

- editMethod:(int) meth_num
{
  [[methods objectAt:meth_num] edit];
  return self;
}

- arguments
{
  return arguments;
}

- addNewArg:(char *) aName
{
  UGArgDef *anArg;

  if (! aName)
    {
      return self;
    }

  anArg = [[UGArgDef alloc] init];
  [anArg initUGDef:self];
  [anArg setName:aName];
  [arguments addObjectIfAbsent:anArg];
  return anArg;
}

- editNewArg:sender
{
  [self addNewArg:(char *) [sender stringValue]];
  currArg = [arguments count] - 1;
  [self updateDisplay];
  [self editArg:currArg];
  return self;
}

- switchArg:sender
/* Change the Arg being displayed on the inspector */
{
  int button;
  int num_args;

  num_args = [arguments count];
  if (num_args <= 0)
    {
      [self updateDisplay];
      return self;
    }

  /* button = -1 for top, 1 for botton */
  button = [[sender selectedCell] tag];
  currArg += button;

  if (currArg < 0)
    {
      currArg = num_args - 1;
    }
  else if (currArg == num_args)
    {
      currArg = 0;
    }

  [self updateDisplay];
  return self;
}

- editCurrentArg:sender
{
  [self editArg:currArg];
  return self;
}

- removeCurrentArg:sender
{
  int count;
  count = [arguments count];
  if (count > 0)
    {
      id anObj = [arguments objectAt:currArg];
      [anObj closeInspector];
      [arguments removeObject:anObj];
      currArg = 0;
    }

  [self updateDisplay];
  return self;
}

- editArg:(int) arg_num
{
  [[arguments objectAt:arg_num] edit];
  return self;
}

- edit
{
  [self updateDisplay];
  [inspector makeKeyAndOrderFront:self];  
  [self showIcon];
  return self;
}

- closeInspector
{
  if (inspector)
    {
      [inspector performClose:self];
    }
  return self;
}

- addHelp:sender
{
  NXRunAlertPanel(getAppName(), 
		  "Only if you scream loud enough",
		  NULL, NULL, NULL);
  return self;
}

- updateDisplay
{
  int count, ival;

  if (!inspector)
    {
      [NXApp loadNibSection:"UGDef.nib" owner:self withNames:YES];
    }

  [theNameField setStringValue: nameString];
  [inspector setTitle:nameString];

  [theTypeField setStringValue: typeString];
  [theNibField setStringValue: nibFile];
  [theIconField setStringValue: iconName];
  [self updateOptionSwitch];

  count = [methods count];
  if (count <= 0)
    {
      ival = 0;
      [theMethodField setStringValue:"None"];
    }
  else
    {
      ival = currMethod + 1;
      [theMethodField setStringValue:(char *) [[methods objectAt:currMethod] getName]];
    }

  [methodCountField setIntValue:count];
  [methodIndexField setIntValue:ival];

  count = [arguments count];
  if (count <= 0)
    {
      [theArgField setStringValue:"None"];
      ival = 0;
    }
  else
    {
      ival = currArg + 1;
      [theArgField setStringValue:(char *) [[arguments objectAt:currArg] getName]];
    }

  [argCountField setIntValue:count];
  [argIndexField setIntValue:ival];

  return self;
}

- write:(NXTypedStream *) stream
{
  [super write:stream];
  NXWriteTypes(stream, "i", &metaType);
  NXWriteTypes(stream, "*", &nibFile);
  NXWriteTypes(stream, "*", &nameString);
  NXWriteTypes(stream, "*", &typeString);
  NXWriteTypes(stream, "*", &iconName);
  NXWriteTypes(stream, "c", &isEnvelopeHandler);
  NXWriteTypes(stream, "c", &isADSwitch);
  NXWriteTypes(stream, "c", &isData);
  NXWriteTypes(stream, "c", &isOscg);
  NXWriteTypes(stream, "c", &isSineROM);
  NXWriteTypes(stream, "c", &hasLength);
  NXWriteTypes(stream, "c", &hasConstant);
  NXWriteTypes(stream, "c", &isStorage);
  NXWriteTypes(stream, "c", &isMidi);
  NXWriteTypes(stream, "c", &isClavier);
  NXWriteTypes(stream, "c", &isPatchParameter);
  NXWriteTypes(stream, "c", &isNoteFilter);
  NXWriteTypes(stream, "@", &methods);
  NXWriteTypes(stream, "@", &arguments);
  NXWriteTypes(stream, "i", &currMethod);
  NXWriteTypes(stream, "i", &currArg);
  return self;
}

- read:(NXTypedStream *) stream
{
  int version;
  id anAppKitObj;

  [super read:stream];
  version = NXTypedStreamClassVersion(stream, "UGDef");
  if (version == 3)
    {
      NXReadTypes(stream, "i", &metaType);
      NXReadTypes(stream, "*", &nibFile);
      NXReadTypes(stream, "*", &nameString);
      NXReadTypes(stream, "*", &typeString);
      NXReadTypes(stream, "*", &iconName);
      NXReadTypes(stream, "c", &isEnvelopeHandler);
      NXReadTypes(stream, "c", &isADSwitch);
      NXReadTypes(stream, "c", &isData);
      NXReadTypes(stream, "c", &isOscg);
      NXReadTypes(stream, "c", &isSineROM);
      NXReadTypes(stream, "c", &hasLength);
      NXReadTypes(stream, "c", &hasConstant);
      NXReadTypes(stream, "c", &isStorage);
      NXReadTypes(stream, "c", &isMidi);
      NXReadTypes(stream, "c", &isClavier);
      NXReadTypes(stream, "c", &isPatchParameter);
      NXReadTypes(stream, "c", &isNoteFilter);
      NXReadTypes(stream, "@", &methods);
      NXReadTypes(stream, "@", &arguments);
      NXReadTypes(stream, "i", &currMethod);
      NXReadTypes(stream, "i", &currArg);
    }
  else
    {
      NXReadTypes(stream, "i", &metaType);
      NXReadTypes(stream, "*", &nibFile);
      NXReadTypes(stream, "*", &nameString);
      NXReadTypes(stream, "*", &typeString);
      NXReadTypes(stream, "*", &iconName);
      NXReadTypes(stream, "c", &isEnvelopeHandler);
      NXReadTypes(stream, "c", &isADSwitch);
      NXReadTypes(stream, "c", &isData);
      NXReadTypes(stream, "c", &isOscg);
      NXReadTypes(stream, "c", &isSineROM);
      NXReadTypes(stream, "c", &hasLength);
      NXReadTypes(stream, "c", &hasConstant);
      NXReadTypes(stream, "c", &isStorage);
      NXReadTypes(stream, "c", &isMidi);
      NXReadTypes(stream, "c", &isClavier);
      NXReadTypes(stream, "c", &isPatchParameter);
      NXReadTypes(stream, "c", &isNoteFilter);
      NXReadTypes(stream, "@", &methods);
      NXReadTypes(stream, "@", &arguments);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "@", &anAppKitObj);
      NXReadTypes(stream, "i", &currMethod);
      NXReadTypes(stream, "i", &currArg);
    }


  return self;
}

@end

