// America-- a thread safe way of dealing with the window server....
// (The threads only think they can get away with whatever they want...
//  but it must get sent to an instance of America [the governing object]
//  for approval)

#import "America.h"
#import <stdio.h>
#import <appkit/Matrix.h>
#import <appkit/TextField.h>
#import <appkit/Application.h>
#import <appkit/Form.h>
#import <sys/message.h>

static America *sf;
@implementation America
- fieldThread:(int)fnum
{
  int i,max=201;
  fieldUpdatePkt updatePkt;
  static int goober;

  // thanks to SortingInAction for this stuff...
  // modifications from hell by b.bum & a.swift (it hurt bad!)
  updatePkt._header.msg_remote_port = updatePort;
  updatePkt._header.msg_simple = TRUE; // no ports or out-of-line data
  updatePkt._header.msg_size = sizeof(fieldUpdatePkt);
  updatePkt._header.msg_local_port = PORT_NULL;
  updatePkt._header.msg_type = MSG_TYPE_NORMAL;
  updatePkt._type.msg_type_name = MSG_TYPE_INTEGER_32;
  updatePkt._type.msg_type_size = sizeof(MSG_TYPE_INTEGER_32)*8;
  updatePkt._type.msg_type_number = 2;
  updatePkt._type.msg_type_inline = TRUE;// no out-of-line data will be passed
  updatePkt._type.msg_type_longform = FALSE;
  updatePkt._type.msg_type_deallocate = FALSE;

  // set the fieldNum for the messages... this is used to grab the field
  // with a tag of (fnum) in the update method over in the main event thread
  updatePkt.fieldNum=fnum;
  
  for(i=0;i<max;i++){

    // only show ever fifth number-- this could be used as a tolerance as to
    // how often the thread REALLY wants to update the screen for those
    // especially heavy CPU usage times...
    if(!(i%5)){
      updatePkt.fieldValue=i;
      if (SEND_SUCCESS !=
	  (goober=msg_send((msg_header_t *) &updatePkt, MSG_OPTION_NONE, 0))){
	mutex_lock(printM);
	fprintf(stderr, "error %d\n", goober);
	mutex_unlock(printM);
      }
      cthread_yield();
    }
  }
  return self;
}

// c function wrapper
void thread_field(int fnum)
{
  [sf fieldThread:fnum];
}

// method to do the actual update when received on the port
- updateReceived:(fieldUpdatePkt *) pkt
{
  [fields setIntValue:pkt->fieldValue at:pkt->fieldNum];
  return self;
}

// c function wrapper
static void do_update(fieldUpdatePkt *pkt,id self)
{
  [self updateReceived:pkt];
}

// start the threads and let it rip
- start:sender
{
  int i=0;
  int count=5; // this is hardwired and shouldn''t be....
  
  for(i=0;i<count;i++)
    cthread_detach(cthread_fork((cthread_fn_t)thread_field, (any_t)i));

  return self;
}

- init
{
  printM=mutex_alloc();
  lockM=mutex_alloc();
  sf=self;

  port_allocate(task_self(), &updatePort);
  DPSAddPort(updatePort,
	       (DPSPortProc) do_update,
	       sizeof(fieldUpdatePkt),
	       (void *)self,
	       NX_MODALRESPTHRESHOLD+1);
  return self;
}
@end
