// Paul Johnson July 13, 2000
// pjrepeater5.m. In the interest of personal enlightenment and
// education, consider introducing a single "masterSchedule" that all
// agents can put their actions on.  The customization of the schedule
// object occurs in the bugSwarm level.  Note we have a usave of
// "ConcurrentGroup" rather than the customization steps used in the
// previous example.

// We (Marcus Daniels and I) are not recommending the approach here,
// just illustrating it.  pjrepeater4.m showed the best way to design
// these decentralized schedules of swarms in swarms.

//Marcus said, and I agree, "Here's how to configure the shared
//masterSchedule. In some cases it may be easier to look at the
//emergent structure of dynamic schedules if there is a shared,
//e.g. xfprint (masterSchedule).

//But, generally, I think it is better to have schedules in the agents
//themselves.  That way it is more "agent-based" and modular.

// decentralized scheduling using customized schedule type to
// randomize events that arrive on the scheduling mechanism for the
// same time.

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

@interface Bug: Swarm
{
 id schedule;
}

- buildActions;
- scheduleSelfAt: (timeval_t)x;
- setSchedule: sch;
- step;
@end

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

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

- setSchedule: sch
{
  schedule= sch;
  return self;
}


- 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;
  id masterSchedule;
  id bugSwarmSchedule;
}
- buildObjects;
- buildActions;
- (id <Activity>)activateIn: (id <Swarm>)swarmContext;
@end

@implementation BugSwarm
- buildObjects
{
  [super buildObjects];

  {
    id groupProto;
    
    groupProto = [ConcurrentGroup customizeBegin: self];
    [groupProto setDefaultOrder: Randomized];
    groupProto = [groupProto customizeEnd];
    
    masterSchedule = [Schedule createBegin: self];
    // [masterSchedule setConcurrentGroupType: groupProto];
    [masterSchedule setAutoDrop: YES];
    masterSchedule = [masterSchedule createEnd];
  }

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

  [bugA buildObjects];
  [bugB buildObjects];

  [bugA setSchedule: masterSchedule];
  [bugB setSchedule: masterSchedule];

  return self;
}

- buildActions
{
  [super buildActions];
 
  [masterSchedule at: 0  createActionTo: bugA message: M(step)];
  [masterSchedule at: 0  createActionTo: bugB message: M(step)];
  return self;
}

- (id <Activity>)activateIn: (id <Swarm>)swarmContext
{
  [super activateIn: swarmContext];
  [masterSchedule 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
{
  [super buildObjects];
  
  bugSwarm = [BugSwarm create: self];
  [bugSwarm buildObjects];
  return self;
}

- buildActions
{
  [super buildActions];

  [bugSwarm buildActions];
  schedule = [Schedule create: self setRepeatInterval: 1];
  [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;
  id displaySchedule;

}
- 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];

   displaySchedule = [Schedule create: self setRepeatInterval: 1];
   [displaySchedule at: 0 createActionTo: actionCache message:
M(doTkEvents)];

  return self;
}

- (id <Activity>)activateIn: (id <Swarm>)swarmContext
{
  [super activateIn: swarmContext];
  [modelSwarm activateIn: self];
  [displaySchedule 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=pjrepeater5 -o pjrepeater5 -Wall -Werror -g -Wno-import -I$SWARMHOME/include \
  -I$SWARMHOME/include/swarm -L$SWARMHOME/lib/swarm pjrepeater5.m  -lswarm -lobjc" 
End: 

*/
