#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSGarbageCollector.h>
#import <Foundation/NSString.h>
#import <objc/objc-auto.h>
#import <stdio.h>
#import <stdlib.h>
#import <stdint.h>
#import <string.h>
#import <unistd.h>

typedef struct {
  NSString *aString;
  __weak NSString *aWeakString;
  NSInteger anInteger;
} MYStructType;

MYStructType globalStructTypeArray[42];
id globalPtr;

void cleanStack(void);
void doWorkStuff(void);
void checkStuff(void);
void printElement(MYStructType *aStructType);
void doInitStuff(void);
void someInitFunc(MYStructType *aStructType, char *strongCString, char *weakCString);

int main(int argc, char *argv[]) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  BOOL gcEnabled = ([NSGarbageCollector defaultCollector] != NULL) ? YES : NO;
  if(gcEnabled == YES) { NSLog(@"GC is enabled, starting collector thread."); objc_startCollectorThread(); }
  
  doInitStuff();

  //globalStructTypeArray[23].aString = globalStructTypeArray[23].aString;
  //globalStructTypeArray[23].aWeakString = globalStructTypeArray[23].aWeakString;

  if(gcEnabled == YES) { objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE); }
  
  NSInteger x = 0;
  for(x = 0; x < 10; x++) {
    NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
    NSLog(@"Work, work, work..");
    doWorkStuff();
    cleanStack();
    if(gcEnabled == YES) { objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE); }
    [loopPool drain];
  }
  cleanStack();
  if(gcEnabled == YES) { objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE); }

  checkStuff();

  [pool drain];
  while(1) { sleep(1); }
  return(0);
}

void cleanStack(void) {
  char stackArray[64*1024];
  memset(stackArray, 0, 64*1024);
}

void doWorkStuff(void) {
  NSInteger x=0;
  NSMutableArray *array = [NSMutableArray array];
  for(x=0; x < 256; x++) { [array addObject:[NSString stringWithFormat:@"String #%ld", x]];  }
  if(globalPtr != NULL) { [globalPtr autorelease]; globalPtr = NULL; }
  globalPtr = [array retain];
  checkStuff();
}

void checkStuff(void) {
  printElement(&globalStructTypeArray[23]);
}

void printElement(MYStructType *ast) {
  NSString *s = ast->aString, *w = ast->aWeakString;
  NSLog(@"aStructType @ %p: aString %p, aWeakString %p, anInteger %ld", ast, s, w, ast->anInteger);
  NSLog(@"aStructType @ %p: aString '%@', aWeakString '%@'", ast, (s==NULL) ? @"<NULL>":s, (w==NULL) ? @"<NULL>":w);
}

void doInitStuff(void) {
  someInitFunc(&globalStructTypeArray[23], "A Strong NSString", "A Weak NSString");
}

void someInitFunc(MYStructType *aStructType, char *strongCString, char *weakCString) {
  NSString *strongString = [[NSString alloc] initWithCString:strongCString encoding:NSUTF8StringEncoding];
  NSString *weakString = [[NSString alloc] initWithCString:weakCString encoding:NSUTF8StringEncoding];

  printElement(aStructType);
  aStructType->aString = strongString;
  aStructType->aWeakString = weakString;
  printElement(aStructType);
}
