// MC# Examples
// Interaction inside a set of asynchronous/distributed processes
// in accordance with the "all to all" principle
//   Usage:   all2all.exe <number of processes>
//
using System;
class   BDChannel   {
 
 public handler  Receive object()  & channel Send ( object obj )  {
     return  ( obj );
  }
}

class  All2all   {

 public static void Main (String[] args)   {

  int  i;

  // N is a number of processes
 
  int  N = System.Convert.ToInt32 ( args [ 0 ] );

  All2all a2a = new All2all();
  DistribProcess dproc = new DistribProcess();

  //   Run the processes
 
  for ( i = 0; i < N; i++ )
    dproc.Start ( i, a2a.sendBDC, a2a.sendStop );
 
  //   Receive the (BD)channels from the processes
 
  BDChannel[] bdchans                = new BDChannel [ N ];
  BDChannel[] interact_bdchans = new BDChannel [ N ];
 
  for ( i = 0; i < N; i++ )
    a2a.getBDC ? ( bdchans, interact_bdchans );

  //   Send a (BD)channel array to every process
 
  for ( i = 0; i < N; i++ )
     bdchans [ i ].Send ! ( interact_bdchans );

  //   Receive the stop signals from the processes
   
  for ( i = 0; i < N; i++ )
    a2a.getStop ? ();
 }
 public handler getBDC void( BDChannel[] bdchans, BDChannel[]   
                                                interact_bdchans )
       & channel sendBDC ( int i, BDChannel bdc, BDChannel interact_bdc )
 {
    bdchans [ i ]          = bdc;
    interact_bdchans [ i ] = interact_bdc;
 }
 public handler  getStop void() & channel  sendStop() {
   return;
 }
}

class DistribProcess   {

 public async Start(int  myNumber, channel(int,BDChannel,BDChannel) sendBDC,
                               channel () sendStop )
{    
  int   i;
  BDChannel  bdc                = new BDChannel();
  BDChannel  interact_bdc = new BDChannel();
 
  sendBDC ! ( myNumber, bdc, interact_bdc );

  BDChannel[]   interact_bdchans  =  (BDChannel[]) bdc.Receive ? ();

  //   Send message to other processes
 
  for  ( i = 0; i < interact_bdchans.Length; i++ )
   if  ( i != myNumber )
     interact_bdchans[i].Send ! ( myNumber );

  //   Receive messages from the other processes
  //   (here it is possible to use  interact_bdchans [ myNumber ] channel )
  //
 
  for  ( i = 0; i < interact_bdchans.Length - 1; i++ )
    Console.WriteLine ( myNumber + " <- " + interact_bdc.Receive ? () );

  //   Send stop signal
 
  sendStop ! ();

 }

}