#import "Autorelease.h"
#import <appkit/appkit.h>

static id autoreleasePool = nil;
static void gc_handler(DPSTimedEntry tag, double now, void *userData);

@implementation AutoreleaseObject

- init
{
   [super init];
   
   retainCount = 1;

   return self;
}

- incrementRetainCount
{
   retainCount++;
   return self;
}

- decrementRetainCount
{
   retainCount--;
   return self;
}

- (unsigned int) retainCount
{
   return retainCount;
}

- free
{
   if([self retainCount] > 1)
   {

      NXLogError("Free called for instance 0x%X of class %s with retainCount of %d!",
		 self, [self name], retainCount);
      return nil;
   }
//   NXLogError("Free called for instance 0x%X of class %s.", self, [self name]);
   return [super free];
}

@end

@implementation  Object (AutoreleaseCategory)

- autorelease
{
   if(!autoreleasePool)
   {
      autoreleasePool = [[List alloc] init]; 
      /*
       * Kick off a "garbage collector" for the list. Make the period, every 0.0 seconds
       * so it does it the first chance it gets (I remove the handler in the handler) and
       * set the threshold to NX_BASETHRESHOLD so that it isn't called during modal sessions
       * since this would mean that a alert panal might cause garbage collection which we don't 
       * want to happen.
       */
      DPSAddTimedEntry(0.0, gc_handler, (void *)0, NX_BASETHRESHOLD);
   }

   [autoreleasePool addObject: self];
   return self;
}


- (void) release
{
   unsigned int cnt = [(AutoreleaseObject *)self retainCount];

   if(!cnt)
       NXLogError("Release called for instance 0x%X of class %s with retainCount of 0!",
		  self, [self name]);
   else
   {
      if(cnt == 1)
	  [self free];
      else
	  [(AutoreleaseObject *)self decrementRetainCount];
   }
}

- retain
{
   [(AutoreleaseObject *)self incrementRetainCount];
   return self;
}

- dealloc
{
   return [self free];
}

@end

static void gc_handler(DPSTimedEntry tag, double now, void *userData)
{
   int x, cnt;
   id (*objectAt)(id,SEL,int);

   DPSRemoveTimedEntry(tag);		     /* only call this once */

   if(!autoreleasePool)
       return;

   /*
    * Can't use List's makeObjectsPerform: since it traveres the list
    * in reverse order. The objects may have been autoreleased in a specific order...
    */
   cnt = [autoreleasePool count];
   if(cnt)
   {
      objectAt =  (id (*)(id,SEL,int))[autoreleasePool methodFor: @selector(objectAt:)];
      for(x = 0; x < cnt; x++)
	  [objectAt(autoreleasePool,@selector(objectAt:),x) release];
   }
   
   [autoreleasePool free];
   autoreleasePool = nil;
}

