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

/* EnvDelegate.m
 * Nick Porcaro, independent work Summer 1993
 */

#import <stdlib.h>
#import <math.h>
#import <stddef.h>
#import <string.h>
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/Panel.h>
#import <musickit/Envelope.h>
#import "EnvDelegate.h"
#import "EnvController.h"
#import "FakeUG.h"
#import "PatchParam.h"
#import "FakeSynthPatch.h"
#define EOS '\0'

extern char *getAppName();

@implementation EnvDelegate

- init
{
  envString = NULL;
  [NXApp loadNibSection:"EnvelopeEd.nib" owner:self withNames:YES];
  thePatchParam = nil;
  theFakeUG = nil;
  return self;
}  

- closeInspector
{
  [envWindow performClose:self];  
  return self;
}

- free
{

  if (envController)
    {
      [envController removeEnvelope:self];
      [envController free];
    }

  return [super free];
}

- setFakeUG:aFakeUG ArgNum: (int) argnum
{
  theFakeUG = aFakeUG;
  theArgNum = argnum;
  return self;
}

- setPatchParameter:aPP
{
  thePatchParam = aPP;
  return self;
}

- (BOOL) hasFakeUG
{
  if (theFakeUG)
    return YES;
  else
    return NO;
}

- displayWindow:(char *) title
{
  [self envelope];  // Make sure we have it 
  [envWindow setTitle:title];
  [envWindow makeKeyAndOrderFront:self];
  return self;
}

- closeWindow
{
  [envWindow close];
  return self;
}

- (char *) envelopeToText
{
  int i, count;
  double *x, *y;
  unsigned int env_size;
  int stick;
  BOOL do_stick = NO;

  /* Do something to the envelope so the File's Owner
   * object can do something cool with it
   */
  [self envelope];   /* Get the damn thing */
  if (! envelope)
    {
      NXRunAlertPanel(getAppName(), 
		      "Unexpected NULL envelope", NULL, NULL, NULL);
      return NULL;
    }

  if (envString)
    {
      NXZoneFree([self zone], envString);
      envString = NULL;
    }

  count = [envelope pointCount];
  if (count <= 0)
    {
      return NULL;
    }

  x = [envelope xArray];
  y = [envelope yArray];
  stick = [envelope stickPoint];
  if (stick != MAXINT)
    {
      do_stick = YES;
    }

  if (! (x && y) )
    {
      return NULL;
    }
  
  /* The max a coordinate of an envelope can be is %03.5 = 9 characters
   * add a comma and paren for each coordinate (make it 4 to be safe)
   * Then we have 9+5 = 14 characters for each coordinate
   * or 28 characters for each point
   */
  env_size = count * 28 + 256; /* add 256 for extra fudge */
  envString = (char *) NXZoneCalloc([self zone], env_size, sizeof(char));
  if (! envString)
    {
      NXRunAlertPanel(getAppName(), 
		      "Grave danger -- malloc error", 
		      NULL, NULL, NULL);
      return NULL;
    }

  strcpy(envString, "");
  for (i=0; i<count; i++)
    {
      sprintf(envString, "%s(%4.4f, %f)",
	      envString, x[i], y[i]);
      if (do_stick && (stick == i))
	{
	  strcat(envString, "|");
	}
    }

  return envString;
}

- textToEnvelope: (char *) aString
{
  int i, j;
  int pointCount = 0;
  int stickPoint = -1;
  double *xArray, *yArray, *smoothingArray;
  id newEnv;

  if (! aString)
    {
      return nil;
    }

  for (i=0; aString[i] != '\0'; i++)
    {
      if (aString[i]=='|')
	{
	  stickPoint = pointCount-1;
	}
      if (aString[i]=='(')
	pointCount++;
    }

  if (pointCount <= 0)
    {
      return nil;
    }

  xArray = (double *) NXZoneCalloc([self zone], pointCount, sizeof(double));
  yArray = (double *) NXZoneCalloc([self zone], pointCount, sizeof(double));
  smoothingArray =  (double *) NXZoneCalloc([self zone], pointCount, sizeof(double));
  
  j=0;
  for (i=0; i<pointCount; i++)
    {
      xArray[i] = yArray[i] = 0.0;
      smoothingArray[i] = 1.0;
      while (aString[j]!='(') 
	{
	  j++;
	}
      sscanf(aString+j, "(%lf,%lf,%lf)",
	     &xArray[i], &yArray[i], &smoothingArray[i]);
      j++;
    }

  newEnv = [[[Envelope alloc] init]
            setPointCount: pointCount
	    xArray: xArray
	    orSamplingPeriod: 1.0
	    yArray: yArray
	    smoothingArray: smoothingArray
	    orDefaultSmoothing: 1.0
	    ];

  if (stickPoint != -1)
    {
      [newEnv setStickPoint:stickPoint];
    }
  
  return newEnv;
}

- envelope
{
  envelope = [envController envelope];
  return envelope;
}

- sendEnvelope
/* Whenever the envelope is redrawn,
 * this method is called by EnvelopeView:drawSelf
 */
{
  if (theFakeUG)
    {
      /* Get the latest envelope and
       * send it to the fake UG
       */
      [[theFakeUG getSP] enableNoteOff:NO];
      [theFakeUG setArg:theArgNum WithEnvelope:[self envelope]];
    }
  else if (thePatchParam)
    {
      [thePatchParam setMapEnvelope:[self envelope]];
    }
  else
    {
      ; /* Do nothing */
    }
  return self;
}


- envController
{
  return envController;
}

- envelopeRemoved
{
  envelope = nil;
  if (theFakeUG)
    {
      [theFakeUG clearArgEnvelope:theArgNum];

      /* If there is an envelope there, send it */
      if ([self envelope])
	{
	  [self sendEnvelope];
	}
    }
  else if (thePatchParam)
    {
      [thePatchParam clearMapEnvelope];
    }
  return self;
}

- envelopeAdded
{
  [self sendEnvelope];
  return self;
}

- willAddEnvelope
{
  if (theFakeUG)
    {
      [theFakeUG willAddEnvelope:theArgNum];
    }
  return self;
}

- willRemoveEnvelope
{
  if (theFakeUG)
    {
      [theFakeUG willRemoveEnvelope:theArgNum];
    }
  return self;
}

- willSplitView
{
  if (theFakeUG)
    {
      [[theFakeUG getSP] enableNoteOff:NO];
    }
  return self;
}

@end

