#include "Bdef.h"

int Smpath_bs(ctxt, scope, npaths)
BLACSCONTEXT  *ctxt;
char  scope;
int  npaths;
/*
 * Note that this routine has been rewritten to avoid a bug in the SUN
 * cc compiler.  This implementation is slightly less efficient than that
 * employed on other platforms.
 */
{
   void Ssend2d00();

   int pathlen;		/* the length of each path */
   int dist;	        /* the distance to the node closest to src on each path */
   int rdest, cdest;    /* row and col destination coordinates */
   int pdest;           /* part of dest calculation -- saves unneeded ops */
   int lastlong;	/* number of paths with extra node */
   int nrnodes;         /* number of receiving nodes ( = nnodes-1 ) */
   int Ng, nprow, npcol, myrow, mycol;
   int msgid;
   int i, iring;

   Mgridinfo(ctxt, Ng, nprow, npcol, myrow, mycol);
   if (npaths == FULLCON) npaths = Ng;
   if (npaths < 0)
   {
      iring = 0;
      npaths = -npaths;
   }
   else iring = 1;

   scope = Mlowcase(scope);
   switch(scope)
   {
   case 'r':
      if (npcol < 2) return(NORV);
      msgid = Mrid(ctxt);
      nrnodes = npcol - 1;
      if (npaths > nrnodes) npaths = nrnodes;
      pathlen = nrnodes / npaths;
      lastlong = (nrnodes % npaths) * (pathlen+1);  /* last node in long ring */

      if (iring)  /* paths are increasing rings */
      {
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
            Ssend2d00(ctxt, myrow, (mycol+dist)%npcol, msgid);
         do
	 {
            Ssend2d00(ctxt, myrow, (mycol+dist)%npcol, msgid);
	    dist += pathlen;
	 }
	 while(dist < npcol);
      }
      else             /* paths are decreasing rings */
      {
	 pdest = npcol + mycol;
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
            Ssend2d00(ctxt, myrow, (pdest-dist)%npcol, msgid);
         do
	 {
            Ssend2d00(ctxt, myrow, (pdest-dist)%npcol, msgid);
	    dist += pathlen;
	 }
	 while(dist < npcol);
      }
      break;
   case 'c':
      if (nprow < 2) return(NORV);
      msgid = Mcid(ctxt);
      nrnodes = nprow - 1;
      if (npaths > nrnodes) npaths = nrnodes;
      pathlen = nrnodes / npaths;
      lastlong = (nrnodes % npaths) * (pathlen+1);  /* last node in long ring */

      if (iring)  /* paths are increasing rings */
      {
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
            Ssend2d00(ctxt, (myrow+dist)%nprow, mycol, msgid);
         do
	 {
            Ssend2d00(ctxt, (myrow+dist)%nprow, mycol, msgid);
	    dist += pathlen;
	 }
	 while(dist < nprow);
      }
      else             /* paths are decreasing rings */
      {
	 pdest = nprow + myrow;
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
            Ssend2d00(ctxt, (pdest-dist)%nprow, mycol, msgid);
         do
	 {
            Ssend2d00(ctxt, (pdest-dist)%nprow, mycol, msgid);
	    dist += pathlen;
	 }
	 while(dist < nprow);
      }
      break;
   case 'a':
      if (Ng < 2) return(NORV);
      msgid = Maid(ctxt);
      pdest = ctxt->vIam;
      nrnodes = Ng - 1;
      if (npaths > nrnodes) npaths = nrnodes;
      pathlen = nrnodes / npaths;
      lastlong = (nrnodes % npaths) * (pathlen+1);  /* last node in long ring */

      if (iring)  /* paths are increasing rings */
      {
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
	 {
            i = (pdest+dist)%Ng ;       /* contains virtual destination node */
	    Mvpcoord(ctxt, i, rdest, cdest);
            Ssend2d00(ctxt, rdest, cdest, msgid);
         }
         do
	 {
            i = (pdest+dist)%Ng ;       /* contains virtual destination node */
	    Mvpcoord(ctxt, i, rdest, cdest);
            Ssend2d00(ctxt, rdest, cdest, msgid);
	    dist += pathlen;
	 }
	 while(dist < Ng);
      }
      else             /* paths are decreasing rings */
      {
	 pdest += Ng;
	 for (dist=1; dist < lastlong; dist += pathlen + 1)
	 {
            i = (pdest-dist)%Ng ;       /* contains virtual destination node */
	    Mvpcoord(ctxt, i, rdest, cdest);
            Ssend2d00(ctxt, rdest, cdest, msgid);
         }
         do
	 {
            i = (pdest-dist)%Ng ;       /* contains virtual destination node */
	    Mvpcoord(ctxt, i, rdest, cdest);
            Ssend2d00(ctxt, rdest, cdest, msgid);
	    dist += pathlen;
	 }
	 while(dist < Ng);
      }
      break;
   default:
      return(BADSCP);
   }
   return(0);
}
