#import "grid.h"
#import <activity.h>
#import <activity/Activity.h>

#define __USE_FIXED_PROTOTYPES__   // for gcc headers
#include <stdio.h>

extern BOOL respondsTo( id, SEL );  // from defobj

static BOOL trace( id anActivity );

static id newTurtle( void )
{
  id          aTurtle;
  static int  ycoord;

  aTurtle = [GridTurtle create: globalZone];
  [aTurtle move: ++ycoord];
  return aTurtle;
}

int main(void)
{
  id   aZone, aList, aTurtle;
  id   emptyActions1, emptyActions2;
  id   moveAndPrint, moveActions, printActions;
  id   printRelative, printRepeat, startSchedule;
  id   swarm, swarmActivity, status;
  int  i;

  initModule( grid );
  initModule( activity );

  aZone = [Zone create: globalZone];
  aList = [List create: aZone];

  for ( i = 0; i < 10; i++ ) {
    aTurtle = [GridTurtle create: aZone];
    [aTurtle turn: -1];
    [aTurtle move: i * 10];
    [aTurtle turn: 1];
    [aList addLast: aTurtle];
  }

  moveActions = [ActionGroup create: aZone];
  for ( i = 0; i < 10; i++ ) {
    if ( i % 2 )
      [moveActions
        createActionTo: [aList atOffset: i] message: M(move:) : (id)10 ];
  }

  printActions = [ActionGroup create: aZone];
  for ( i = 0; i < 10; i++ ) {
    [printActions createActionTo: [aList atOffset: i] message: M(print)];
  }

  moveAndPrint = [Schedule createBegin: aZone];
  [moveAndPrint setRepeatInterval: 10];
  moveAndPrint = [moveAndPrint createEnd];

  [moveAndPrint at: 0 createAction: moveActions];
  [moveAndPrint at: 0 createAction: printActions];

  emptyActions1 = [ActionGroup create: aZone];
  emptyActions2 = [ActionGroup create: aZone];

  printRelative = [Schedule createBegin: aZone];
  [printRelative setRelativeTime: 1];
  printRelative = [printRelative createEnd];

  [printRelative at: 0 createActionTo: newTurtle() message: M(print)];
  [printRelative at: 4 createAction: emptyActions1];
  [printRelative at: 4 createActionTo: newTurtle() message: M(print)];
  [printRelative at: 9 createActionTo: newTurtle() message: M(print)];

  printRepeat = [Schedule createBegin: aZone];
  [printRepeat setRepeatInterval: 10];
  printRepeat = [printRepeat createEnd];

  [printRepeat at: 0 createActionTo: newTurtle() message: M(print)];
  [printRepeat at: 1 createActionTo: newTurtle() message: M(print)];

  startSchedule = [Schedule create: aZone];
  [startSchedule at: 1 createActionTo: printRepeat
                  message: M(activateIn:) : nil];

  [startSchedule at: 2 createActionTo: newTurtle() message: M(print)];
//[startSchedule at: 2 createAction: emptyActions2];

  [startSchedule at: 2 createActionTo: printRelative
                 message: M(activateIn:) : nil];
  [startSchedule at: 18 createActionTo: printRelative
                 message: M(activateIn:) : nil];
  [startSchedule at: 21 createActionTo: printRelative
                 message: M(activateIn:) : nil];
  [startSchedule at: 34 createActionTo: printRelative
                 message: M(activateIn:) : nil];

  [startSchedule at: 5 createActionTo: newTurtle() message: M(print)];
  [startSchedule at: 12 createActionTo: newTurtle() message: M(print)];
  [startSchedule at: 18 createActionTo: newTurtle() message: M(print)];
  [startSchedule at: 10 createActionTo: newTurtle() message: M(print)];
  [startSchedule at: 20 createActionTo: newTurtle() message: M(print)];

  swarm = [GenericSwarm create: aZone];
  _activity_trace = trace;
  swarmActivity = [swarm activateIn: nil];
  [startSchedule activateIn: swarmActivity];

  while ( (status = [swarmActivity run]) != Stopped && status != Completed );
  printf( "run return status: %s\n", [status getName] );
  return 0;
}

static BOOL trace( id anActivity )
{
  id         swarmActivity;
  int        level;
  timeval_t  currentTime = 999999;

  for ( swarmActivity = anActivity, level = 0;
        ! respondsTo( swarmActivity, @selector( getMergingActivities ) );
        swarmActivity = [swarmActivity getOwnerActivity], level++ );

  currentTime   = getCurrentTime();
  if ( [anActivity getStatus] == Running ) {
    printf( "at time: %u, level %d, %s, %s\n",
             currentTime, level,
             [[anActivity createIDString: scratchZone] getC],
          [[[anActivity getCurrentAction] createIDString: scratchZone] getC] );
  } else {
    printf( "at time: %u, level %d, %s is %s\n",
             currentTime, level,
             [[anActivity createIDString: scratchZone] getC],
             [[anActivity getStatus] getName] );
  }
  if ( currentTime < 100 ) return 0;
  ((Activity_c *)anActivity)->status = Stopped;
  return 1;
}
