/* Example of using RUNNER.
   Written by Tiggr <tiggr@es.ele.tue.nl> and Michael <michael@thi.nl>

   Copyright (C) 1994, 1995 Pieter J. Schoenmakers and Michael L.H. Brouwer.
   All rights reserved.

   This file is part of RUNNER.

   RUNNER is free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   RUNNER is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
   License for more details.

   You should have received a copy of the GNU Library General Public
   License along with RUNNER; see the file COPYING.LIB.  If not, write
   to the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
   MA 02111-1307, USA.

   $Id: example.m,v 1.2 1995/11/29 17:40:52 tiggr Exp $  */

#import <remote/NXConnection.h>
#import <remote/NXProxy.h>
#import <libc.h>
#import "runner.h"

#define REGISTERED_NAME  "App Noot Mies"

/* The Client and Server protocols only employ asynchronous messages.
   When running example several times, the order of the method
   invocations, as printed, can be tell:to:, beTold: and die, or
   tell:to:, die, beTold:.  */

@protocol Client

-(oneway void) beTold: (const char *) whatever;

@end

@protocol Server

-(oneway void) die;

-(oneway void) tell: (const char *) something to: (id <Client>) me;

@end

@interface Server: Object <Server>

-(void) run;

@end

@interface Client: Object <Client, TMProxyDeath>
{
  id <Server> server;
}

-(void) killServer;

@end

void
te_handler_2 (DPSTimedEntry te, double now, void *userData)
{
  struct timeval tv;

  gettimeofday (&tv, 0);
  printf ("%d.%06d timed entry 2\n", tv.tv_sec, tv.tv_usec);
} /* te_handler_2 */

void
te_handler_1 (DPSTimedEntry te, double now, void *userData)
{
  static DPSTimedEntry te2;
  struct timeval tv;

  gettimeofday (&tv, 0);
  printf ("%d.%06d timed entry 1\n", tv.tv_sec, tv.tv_usec);

  if (te2)
    {
      printf ("server: remove timed entry handler=2\n");
      DPSRemoveTimedEntry (te2);
      te2 = NULL;
    }
  else
    {
      printf ("server: add timed entry handler=2 period=0.25\n");
      te2 = DPSAddTimedEntry (0.25, te_handler_2, 0, 0);
    }
} /* te_handler_1 */

@implementation Server

-(void) run
{
  /* Register ourselves.  */
  NXConnection *c = [NXConnection registerRoot: self
		     withName: REGISTERED_NAME];

  if (!c)
    {
      /* Oops, something's wrong!  */
      LogError ("Can't register server");
    }
  else
    {
      /* Tell the connection how it is to communicate.  */
      [c runFromAppKit];

      /* Go for it!  */
      [[TMConnectionRunner sharedRunner] run];
    }
} /* -run */

-(oneway void) die
{
  printf ("-[Server die]\n");

  /* Shot!  */
  exit (0);
} /* -die */

-(oneway void) tell: (const char *) something to: (id <Client>) me
{
  printf ("-[Server tell:to:] %s %p\n", something, me);

  printf ("server: add timed entry handler=2 period=0.001\n");
  DPSAddTimedEntry (0.001, te_handler_2, 0, 0);

  /* Set the protocol, since this is the first time we hear something
     from this client.  */
  [(NXProxy *) me setProtocolForProxy: @protocol (Client)];

  /* Tell it what it wants.  */
  [me beTold: something];
} /* -tell:to: */

@end

@implementation Client

-init
{
  /* Get a proxy to the server.  */
  NXProxy *p = [NXConnection connectToName: REGISTERED_NAME];

  if (!p)
    {
      /* There's this problem we're having...  */
      LogError ("Can't find server");
      exit (0);
    }

  /* Avoid a synchronous RPC to discover the method signature for each
     of the methods we invoke at the server.  */
  [p setProtocolForProxy: @protocol (Server)];

  /* Make sure we are notified of our server's death.  */
  [[TMConnectionRunner sharedRunner] registerProxy: p forLocal: self];

  /* Tell this new connection how it is to perform its communication.  */
  [[p connectionForProxy] runFromAppKit];

  server = (id) p;
  return (self);
} /* -init */

-(void) killServer
{
  printf ("-[Client killServer]\n");

  /* Be polite...  */
  [server tell: "Farewell cruel world..." to: self];

  /* Shoot!  */
  [server die];
} /* -init */

-(oneway void) beTold: (const char *) whatever
{
  printf ("-[Client beTold:] %s\n", whatever);
} /* beTold: */

-(void) proxyDied: (id) proxy
{
  printf ("-[Client proxyDied: %p], server=%p\n", proxy, server);
  exit (0);
} /* -proxyDied: */

@end

int
main (int argc, char **argv)
{
  switch (fork ())
    {
    case -1:
      perror ("fork");
      break;

    case 0:
      printf ("server: add timed entry handler=1 period=2\n");
      DPSAddTimedEntry (2, te_handler_1, 0, 0);

      [(Server *) [[Server alloc] init] run];
      break;

    default:
      /* Give server time to register, and play with timed entries.  */
      sleep (8);

      [[[Client alloc] init] killServer];
      [[TMConnectionRunner sharedRunner] run];
      break;
    }

  return (0);
} /* main */
