#include "Bdef.h"

int Stree_br(ctxt, scope, nbranches, rsrc, csrc)
BLACSCONTEXT  *ctxt;
char  scope;
int  nbranches;
int  rsrc;
int  csrc;
{
   void Ssend2d00();
   void Srecv2d00();

   int i, j;
   int mydist;          /* my distance from src */
   int destdist;	/* the distance of the destination node */
   int vsrc, rdest, cdest, nnodes;
   int Ng, nprow, npcol, myrow, mycol;
   int msgid;
   int info, rbufid;

   Mgridinfo(ctxt, Ng, nprow, npcol, myrow, mycol);
   scope = Mlowcase(scope);
   switch(scope)
   {
   case 'r':
      msgid = Mrid(ctxt);
      mydist = (npcol + mycol - csrc) % npcol;
      nnodes = npcol;
      break;
   case 'c':
      msgid = Mcid(ctxt);
      mydist = (nprow + myrow - rsrc) % nprow;
      nnodes = nprow;
      break;
   case 'a':
      vsrc = Mvkpnum(ctxt, rsrc, csrc);
      msgid = Maid(ctxt);
      mydist = (Ng + ctxt->vIam - vsrc) % Ng;
      nnodes = Ng;
      break;
   default:
      return(BADSCP);
   }


/*
 * Go up to first step of tree where I send data to other nodes
 */
   for (i=nbranches; i < nnodes; i *= nbranches);
   for (i /= nbranches; (mydist%i); i /= nbranches);

   Srecv2d00(ctxt, msgid);
/*
    *    Free send buffer, send from receive buff
 */
      rbufid = pvm_getrbuf();
      info = pvm_freebuf(pvm_setsbuf(rbufid));
      Mpvmerror(info, "pvm_freebuf", __LINE__, __FILE__);
/*
 * While I need to send data to others
 */
   switch(scope)
   {
   case 'r':
      while ( (i > 1) && !(mydist%i) )
      {
         i /= nbranches;
         j = 1;
         do
	 {
	    destdist = mydist + j*i;
	    if (destdist < nnodes)
               Ssend2d00(ctxt, myrow, (csrc+destdist)%nnodes,
                         msgid);
         }
         while(++j < nbranches);
      }
      break;
   case 'c':
      while ( (i > 1) && !(mydist%i) )
      {
         i /= nbranches;
         j = 1;
         do
         {
            destdist = mydist + j*i;
            if (destdist < nnodes)
               Ssend2d00(ctxt, (rsrc+destdist)%nnodes, mycol,
                         msgid);
         }
         while(++j < nbranches);
      }
      break;
   case 'a':
      while ( (i > 1) && !(mydist%i) )
      {
         i /= nbranches;
         j = 1;
         do
         {
            destdist = mydist + j*i;
            if (destdist < nnodes)
            {
               destdist = (vsrc+destdist) % Ng;
               Mvpcoord(ctxt, destdist, rdest, cdest);
               Ssend2d00(ctxt, rdest, cdest, msgid);
            }
         }
         while(++j < nbranches);
      }
      break;
   }
   pvm_setrbuf(rbufid);  /* restore buffer state */
   return(0);	/* error free return */
} /* end Stree_br */
