// decentralized scheduling using customized schedule type to
// randomize events that arrive on the scheduling mechanism for the same time.
// Problem: all events at time X are randomized, including events scheduled by both 
// and the ModelSwarm.  We only want the agent actions to be randomized, kept separate
// from ModelSwarm record keeping and so forth.
// pjrepeater4, by Marcus Daniels, adds a "bugSwarm" layer to address this problem.


#import <simtools.h>
#import <simtoolsgui/GUISwarm.h>
#import <objectbase/Swarm.h>

@interface Bug: Swarm
{
  id schedule;
}

- buildActions;
- (id <Activity>)activateIn: (id <Swarm>)swarmContext;
- scheduleSelfAt: (int) x;
- step;
@end

@implementation Bug
- scheduleSelfAt: (int) x
{
  [schedule at: x createActionTo: self message: M(step)];
  return self;
}

- buildActions
{
  [super buildActions];

  schedule = [Schedule createBegin: self];
  [schedule setAutoDrop: 1];
  schedule = [schedule createEnd];

  [schedule at: 0 createActionTo: self message: M(step)];
  
  return self;
}

- (id <Activity>)activateIn: (id <Swarm>)swarmContext
{
  [super activateIn: swarmContext];
  [schedule activateIn: self];
  return [self getActivity]; 
}

- step
{
  printf ("I'm %s, and the current time is %ld\n",
          [self getName], 
          getCurrentTime ());
  return self;
}
@end

@interface BugA: Bug
- step;
@end

@implementation BugA
- step
{
  [super step];
  [self scheduleSelfAt: getCurrentTime () + 1];

  return self;
}


@interface BugB: Bug
- step;
@end

@implementation BugB
- step
{
  [super step];
  [self scheduleSelfAt: getCurrentTime () + 5];
  return self;
}


@interface BugSwarm: Swarm
{
  id  bugA, bugB;
}
- buildObjects;
- buildActions;
- (id <Activity>)activateIn: (id <Swarm>)swarmContext;
@end

@implementation BugSwarm
- buildObjects
{
  [super buildObjects];

  bugA = [BugA create: self];
  bugB = [BugB create: self];

  [bugA buildObjects];
  [bugB buildObjects];

  return self;
}

- buildActions
{
  [super buildActions];

  [bugA buildActions];
  [bugB buildActions];

  return self;
}

- (id <Activity>)activateIn: (id <Swarm>)swarmContext
{
  [super activateIn: swarmContext];

  [bugA activateIn: self];
  [bugB activateIn: self];

  return [self getActivity];
}

@end

@interface ModelSwarm: Swarm
{
  id <Schedule> schedule;
  id <Swarm> bugSwarm;
}
- announcement;
- buildObjects;
- buildActions;
- activateIn: swarmContext;

@end

@implementation ModelSwarm

- announcement
{
  printf ("I'm model swarm, current time is %ld\n", getCurrentTime());
  return self;
}

- buildObjects
{
  id groupProto, syncScheduleProto;

  [super buildObjects];

  groupProto = [ConcurrentGroup customizeBegin: self];
  [groupProto setDefaultOrder: Randomized];
  // [groupProto setDefaultOrder: Sequential];
  groupProto = [groupProto customizeEnd];
  
  syncScheduleProto = [Schedule customizeBegin: self];
  [syncScheduleProto setConcurrentGroupType: groupProto];
  [syncScheduleProto setAutoDrop: 1];
  syncScheduleProto = [syncScheduleProto customizeEnd];
  
  bugSwarm = [BugSwarm createBegin: self];
  
  [bugSwarm setSynchronizationType: syncScheduleProto];
  bugSwarm = [bugSwarm createEnd];
  
  [bugSwarm buildObjects];
  return self;
}

- buildActions
{
  [super buildActions];

  [bugSwarm buildActions];
  schedule = [Schedule createBegin: self];
  [schedule setRepeatInterval: 1];
  schedule = [schedule createEnd];
  
  [schedule at: 0 createActionTo: self message: M(announcement)];
  return self;
}

- activateIn: swarmContext
{
  [super activateIn: swarmContext];
  [schedule activateIn: self];
  [bugSwarm activateIn: self];
  return [self getActivity];
}  
@end

@interface ObserverSwarm: GUISwarm
{
  id <Swarm> modelSwarm;
}
- buildObjects;
- buildActions;
- (id <Activity>)activateIn: (id <Swarm>)swarmContext;
@end

@implementation ObserverSwarm

- buildObjects
{
  [super buildObjects]; 
  
  modelSwarm = [ModelSwarm create: self];
  [controlPanel setStateStopped];
  [modelSwarm buildObjects];
  return self;
}  

- buildActions
{
  [super buildActions];
  [modelSwarm buildActions];
  return self;
}

- (id <Activity>)activateIn: (id <Swarm>)swarmContext
{
  [super activateIn: swarmContext];
  [modelSwarm activateIn: self];
  return [self getActivity];
}


int
main (int argc, const char **argv)
{
  id swarm;

  initSwarm (argc, argv);

  swarm = [ObserverSwarm create: globalZone];

  [swarm buildObjects];
  [swarm buildActions];
  [swarm activateIn: nil];
  [swarm go];
  
  return 0;
}

/* 
Local Variables: 
compile-command: "$SWARMHOME/bin/libtool-swarm --mode=link gcc -D_GNU_SOURCE -DAPPNAME=pjrepeater4 -o pjrepeater4 -Wall -Werror -g -Wno-import -I$SWARMHOME/include -I$SWARMHOME/include/swarm -L$SWARMHOME/lib/swarm pjrepeater4.m  -lswarm -lobjc" 
End: 
*/
