//  AnimView.m
// 1993 Christoph Marquardt
//  You may freely copy, distribute, and reuse the code in this program.
//  the author disclaims any warranty of any kind, expressed or  implied, as to its
//  fitness for any particular use.

#import <strings.h>
#import "AnimView.h"

void getFileFromPath(const char *thePath, char *thefile)
{
  int i,x,n,t=0,l;
  
  l = strlen(thePath)-1;
  for(i=l;i>=0;i--)
  	if(thePath[i] == '/') {
		i++;
		break;
	}
  for(x=i;x<l;x++)
  	if(thePath[x] == '.')
		break;
  for (n=i;n<x;n++)
  	thefile[t++]=thePath[n];
  thefile[t] = 0;
}

@implementation AnimView :View

- initFrame:(NXRect *)theFrame
{
  [super initFrame:(NXRect *)theFrame];
  Status = STOPPED;
  Frames = NULL;
  frameN = 0;
  numFrames = 0;
  fps = 25.0;
  return self;
}

- openAnim:(const char *)filename
{
  BOOL GoOn = YES;
  int n=10;
  int i=0;
  char theFile[300], name[100];
  NXSize theSize;
  const NXPoint thePoint = { 0.0, 0.0 };
  
  if (Status != STOPPED)
  	[self stopAnim:self];
  
  if (Frames != NULL) {
    	for(i=0;i<numFrames;i++)
  		[ Frames[i] free];
  	free(Frames);
	i=0;
  }
  Frames = (id *)malloc(n*sizeof(id));
  numFrames = 0;
  
  getFileFromPath(filename, name);
  [window setTitle:name];
  while(GoOn == YES) {
  	sprintf(theFile, "%s/%s.%d.tiff", filename, name, i+1);
	if (i == n) {
		n = n*2;
		Frames = realloc(Frames, n*sizeof(id));
	}
	Frames[i] = [NXImage allocFromZone:[self zone]];
	[Frames[i] initFromFile:theFile];
	if ( ![Frames[i] lockFocus] ) {
		GoOn = NO;
		numFrames = i;
	} else {
		[Frames[i] unlockFocus];
		i++;
	}
  }
  if (numFrames == 0) {
  	[Frames[0] free];
	free(Frames);
	NXRunAlertPanel(NULL,"Couldn't open %s.", NULL, NULL, NULL, theFile);
	return self;
  }
  [ Frames[0] getSize:&theSize];
  if (theSize.width != 0.0)
  	[window sizeWindow:theSize.width :theSize.height];
  // Showing first image of anim ...
  [self lockFocus];
  [Frames[0] composite:NX_COPY toPoint:&thePoint];
  [self unlockFocus];
  [window flushWindow];
  return self;
}

- playAnim:sender
{
  if (numFrames == 0)
  	return self;
  if ( [sender respondsTo:@selector(setState:)] )
  	playbutton = sender;
  else
  	playbutton = nil;
  if (Status == RUNNING)
  	[self stopAnim:self];
  if (Status == STOPPED)
  	frameN = 0;
  Status = RUNNING;
  timer = DPSAddTimedEntry(1/fps, &runOneStep, self, NX_BASETHRESHOLD);
  return self;
}

- stopAnim:sender
{
  if (Status == RUNNING) {
  	if (playbutton != nil)
  		[playbutton setState:NO];
  	DPSRemoveTimedEntry(timer);
  	Status = STOPPED;
  }
  if (Status == PAUSED) {
  	if (playbutton != nil)
  		[playbutton setState:NO];
	if (pausebutton != nil)
		[pausebutton setState:NO];
	Status = STOPPED;
  }
  return self;
}

- pauseAnim:sender
{
  if ( [sender respondsTo:@selector(setState:)] )
  	pausebutton = sender;
  else
  	pausebutton = nil;
  if (Status == PAUSED) {
  	Status = RUNNING;
  	timer = DPSAddTimedEntry(1/fps, &runOneStep, self, NX_BASETHRESHOLD);
	return self;
  }
  if (Status == RUNNING) {
  	DPSRemoveTimedEntry(timer);
	Status = PAUSED;
  }
  if (Status == STOPPED)
  	 if ( [sender respondsTo:@selector(setState:)] )
  		[sender setState:NO];
  return self;
}

- step:(double)timeNow;
{
  const NXPoint thePoint = { 0.0, 0.0 };
  
  if (frameN == numFrames)
  	frameN = 0;
  [self lockFocus];
  [Frames[frameN++] composite:NX_COPY toPoint:&thePoint];
  [self unlockFocus];
  [window flushWindow];
  return self;
}

- takeFramesPerSecond:sender
{
  fps = [sender floatValue];
  return self;
}
- setFramesPerSecond:(float)thefps
{
  fps = thefps;
  return self;
}
- (float)framesPerSecond
{
  return fps;
}

- free
{
  int i;
  if (Status == RUNNING)
  	DPSRemoveTimedEntry(timer);
  for(i=0;i<numFrames;i++)
  	[ Frames[i] free];
  free(Frames);
  return [super free];
}

// Delegate methods of window.

- windowWillMiniaturize:theW toMiniwindow:theMW
{
  if (numFrames != 0)
  	[window setMiniwindowImage:Frames[0]];
  if(Status == RUNNING) {
  	DPSRemoveTimedEntry(timer);
	Status = PAUSED;
  }
  return self;
}

// Pretty much a dummy function to invoke the step method.

void runOneStep (DPSTimedEntry timedEntry, double timeNow, void *data)
{
    [(id)data step:timeNow];
}

@end
