#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <sys/utsname.h>
#include <string.h>
#define BUFSIZE 256 /* Maximal length of node name*/
#define PLENGTH 2560
#define HOST 0

static int nparams;
static int host, get=0, target, indicator, indicat;
static char lam[]="LAM", mpich[]="MPICH", mpich_p4[]="MPICH_P4", lam63[]="LAM6.3",
  hcc[]="$MPIDIR/bin/hcc ",
  mpicc[]="$MPCHOME/bin/mpi_cc ",
  mpichdirlib[]="-L$MPILIB/ ", /* or $MPIDIR/lib ? */
  lamdirlib[]="";

int main(int argc, char **argv)
{
  char buf[BUFSIZE], curpar[BUFSIZE], curpar_host[BUFSIZE];
  char vasya[BUFSIZE];
  char pgfile[BUFSIZE], pgfile1[BUFSIZE];
  char params[PLENGTH], params_host[PLENGTH], *point;
  char myname[BUFSIZE];
  char name[BUFSIZE], extent[BUFSIZE];
  int i, j;
  FILE *fp, *fdef, *finput;
  char *mpctopo, *mpcload, *whichmpi, *cc, *dirlib;
  struct utsname node_info;

  buf[0]='\0';
  curpar[0]='\0';
  curpar_host[0]='\0';
  params[0]='\0';
  params_host[0]='\0';
  myname[0]='\0';
  name[0]='\0';
  extent[0]='\0';
  vasya[0]='\0';
  uname(&node_info);
  strcpy(myname, node_info.nodename);
  nparams=argc;
  whichmpi=getenv("WHICHMPI");
  if(whichmpi==NULL)
    {
      whichmpi=lam;
      printf("mpcload: WHICHMPI not defined (LAM selected).\n");
    }
  if(strcmp(whichmpi,lam)&&strcmp(whichmpi,lam63)&&strcmp(whichmpi,mpich)&&strcmp(whichmpi,mpich_p4))
    {
      printf("mpcload: unsupported MPI implementation %s\n", whichmpi);
      exit(-1);
    }

  if(argc<1)
    {
      printf("mpcload: usage --> mpcload <argument-list>\n");
      exit(-1);
    }
  mpctopo=getenv("MPCTOPO");
  if(mpctopo==NULL)
    {
      printf("mpcload: MPCTOPO not defined.\n");
      exit(-1);
    }  
  mpcload=getenv("MPCLOAD");
  if(mpcload==NULL)
    {
      printf("mpcload: MPCLOAD not defined\n");
      exit(-1);
    }  
  strcpy(buf, mpctopo);
  strcat(buf, "/log/current");
  if((finput=fopen(buf, "r"))!=NULL)
      fscanf(finput, "%s", name);
  else
    {
      printf("mpcload: no opened machine.\n");
      exit(-1);
    }
  
  for(i=1; argv[i]!=NULL; i++)
    if(strcmp(argv[i], "-het")==0)
      {
        get=i;
        break;
      }
  for(i=1; argv[i]!=NULL; i++)
    if(strcmp(argv[i], "-host")==0)
      {
        int iii;
        
        for(iii=1; argv[iii]!=NULL; iii++)
          if(strcmp(argv[iii], "-c")==0)
            {
              printf("mpcload: incompatible options '-host' and '-c'\n");
              exit(-1);
            }
        host=i;
        break;
      }
  for(i=1; argv[i]!=NULL; i++)
    if(strcmp(argv[i], "-o")==0)
      {
        target=i+1;
        break;
      }
  if(target==0)
    {
      printf("mpcload: executable's name not specified.\n");
      exit(-1);
    }

  strcpy(vasya, mpctopo);
  strcat(vasya, "/MPCshemazagruzki.vasya");

  fp=fopen(vasya, "w");
  if(fp==NULL)
    {
      printf("mpcload: cannot create a working file in %s\n", mpctopo);
      exit(-1);
    }
  strncpy(buf, "", BUFSIZE);
  strcpy(buf, mpctopo);
  strcat(buf, "/");
  strcat(buf, name);
  strcat(buf, ".def");
  if((fdef=fopen(buf, "r"))==NULL)
    {
      printf("mpcload: can not open file %s.\n         Is machine \'%s\' created?\n",
             buf, name);
      fclose(fp);
      remove(vasya);
      exit(-1);
    }
  if(!strcmp(whichmpi,lam) || !strcmp(whichmpi,lam63))
    {
      cc=hcc;
      dirlib=lamdirlib;
    }
  else if(!strcmp(whichmpi,mpich))
    {
      cc=mpicc;
      dirlib=mpichdirlib;
    }
  else if(!strcmp(whichmpi,mpich_p4))
    {
      cc=mpicc;
      dirlib=mpichdirlib;
      
      strncpy(pgfile, "", BUFSIZE);
      strcpy(pgfile, mpctopo);
      strcat(pgfile, "/");
      strcat(pgfile, name);
      strcat(pgfile, ".p4");
      strncpy(pgfile1, "", BUFSIZE);
      strcpy(pgfile1, mpctopo);
      strcat(pgfile1, "/");
      strcat(pgfile1, name);
      strcat(pgfile1, ".p41");
    }
  
  if(host && get)
    {
      strcpy(params,cc);
      strcpy(params_host,cc);
      if(getenv("HCCFLAGS"))
        {
          strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
          strcat(params_host, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
        }
      else
        {
          strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
          strcat(params_host, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
        }
      for(i=1; i<argc; i++)
        {
          if(i==host && !strcmp(whichmpi,mpich))
            strcat(params_host, " -host");
          if(i!=host && i!=get)
            if(argv[i][0]!='-' && i!=target)
              if((point=strstr(argv[i], "."))==NULL)
                {
                  printf("mpcload: wrong file name \'%s\'\n", argv[i]);
                  fclose(fp);
                  remove(vasya);
                  exit(-1);
                }
              else
                {
                  indicator++;
                  if(i<host)
                    {
                      strncpy(curpar, "", BUFSIZE);
                      strncpy(curpar, argv[i], point-argv[i]);
                      if(argv[i][0]!='/')
                        strcat(curpar, "_node");
                      strcat(curpar, point);
                      if(argv[i][0]!='/')
                        strcat(params, " $MPCLOAD/");
                      else
                        strcat(params, " ");
                      strcat(params, curpar);
                    }
                  strncpy(curpar, "", BUFSIZE);
                  strncpy(curpar, argv[i], point-argv[i]);
                  if(argv[i][0]!='/')
                    strcat(curpar, "_host");
                  strcat(curpar, point);
                  if(argv[i][0]!='/')
                    strcat(params_host, " $MPCLOAD/");
                  else
                    strcat(params, " ");
                  strcat(params_host, curpar);
                  if(indicator==1)
                    {
                      strcat(params_host, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params_host, dirlib);
                      strcat(params, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params, dirlib);
                    }
                }
            else
              if(i==target)
                {
                  if(i<host)
                    {
                      strcat(params, " $MPCLOAD/");
                      strcat(params, argv[i]);
                    }
                  strcat(params_host, " $MPCLOAD/");
                  strcat(params_host, argv[i]);
                  strcat(params_host, " -I$MPCHOME/h");
                  strcat(params, " -I$MPCHOME/h");
                }
              else
                {
                  if(i<host)
                    {
                      strcat(params, " ");
                      strcat(params, argv[i]);
                    }
                  strcat(params_host, " ");
                  strcat(params_host, argv[i]);
                }
        }
      //strcat(params_host, " -lmpi -lm");
      //strcat(params, " -lmpi -lm");
      strcat(params_host, " -lm");
      strcat(params, " -lm");
      j=0;
      while(fscanf(fdef, "%s", buf)==1)
        {
          if(j==0)
            if(strcmp(myname, buf))
              {
                printf("mpcload: You can load a program in machine \'%s\'\n", name);
                printf("         only from host \'%s\'.  Sorry. Bye!\n", buf);
                fclose(fp);
                remove(vasya);
                exit(-1);
              }
            else
              if(!strcmp(whichmpi,lam63))
                fprintf(fp,"-np 1 -s n%d n%d %s %s\n", j, j, "mpcld", params_host);
              else
                fprintf(fp,"%s -c 1 -s n%d n%d -- %s\n", "mpcld", j, j, params_host);
          else
            if(!strcmp(whichmpi,lam63))
              fprintf(fp,"-np 1 -s n%d n%d %s %s\n", j, j, "mpcld", params);
            else
              fprintf(fp,"%s -c 1 -s n%d n%d -- %s\n", "mpcld", j, j, params);
          j++;
        }
      fclose(fp);
      strcpy(buf, mpcload);
      strcat(buf, "/MPCzyuzya.5");
      fp=fopen(buf, "w");
      if(fp==NULL)
        {
          printf("mpcload: cannot create a working file in directory %s.\n", mpcload);
          exit(-1);
        }
      if(!strcmp(whichmpi,mpich_p4))
        fprintf(fp, "$MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/mpcld && $MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/gather %s && rm $MPCTOPO/MPCshemazagruzki.vasya", pgfile, pgfile1, name);        
      else if(!strcmp(whichmpi,lam) || !strcmp(whichmpi,lam63))
        fprintf(fp, "$MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.vasya && $MPCHOME/bin/postload && $MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.vasya");
      else if(!strcmp(whichmpi,mpich))
        fprintf(fp, "cp $MPCTOPO/%s.def $MPIDIR/util/machines/machines.%s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/mpcld %s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/gather %s && rm $MPIDIR/util/machines/machines.%s && rm $MPCTOPO/MPCshemazagruzki.vasya", name, name, name, j, params_host, name, j, name, name);
    }
  else if(host && !get)
    {
      strcpy(params,cc);
      strcpy(params_host,cc);
      if(getenv("HCCFLAGS"))
        {
          strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
          strcat(params_host, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
        }
      else
        {
          strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
          strcat(params_host, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
        }
      for(i=1; i<argc; i++)
        {
          if(i==host && !strcmp(whichmpi,mpich))
            strcat(params_host, " -host");
          if(i!=host && i!=get)
            if(argv[i][0]!='-' && i!=target)
              if((point=strstr(argv[i], "."))==NULL)
                {
                  printf("mpcload: wrong file name \'%s\'\n", argv[i]);
                  fclose(fp);
                  remove(vasya);
                  exit(-1);
                }
              else
                {
                  indicator++;
                  if(i<host)
                    {
                      strncpy(curpar, "", BUFSIZE);
                      strncpy(curpar, argv[i], point-argv[i]);
                      if(argv[i][0]!='/')
                        strcat(curpar, "_node");
                      strcat(curpar, point);
                      if(argv[i][0]!='/')
                        strcat(params, " $MPCLOAD/");
                      else
                        strcat(params, " ");
                      strcat(params, curpar);
                    }
                  strncpy(curpar, "", BUFSIZE);
                  strncpy(curpar, argv[i], point-argv[i]);
                  if(argv[i][0]!='/')
                    strcat(curpar, "_host");
                  strcat(curpar, point);
                  if(argv[i][0]!='/')
                    strcat(params_host, " $MPCLOAD/");
                  else
                    strcat(params, " ");
                  strcat(params_host, curpar);
                  if(indicator==1)
                    {
                      strcat(params_host, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params_host, dirlib);
                      strcat(params, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params, dirlib);
                    }
                }
          else
            if(i==target)
              {
                if(i<host)
                  {
                    strcat(params, " $MPCLOAD/");
                    strcat(params, argv[i]);
                  }
                strcat(params_host, " $MPCLOAD/");
                strcat(params_host, argv[i]);
                strcat(params_host, " -I$MPCHOME/h");
                strcat(params, " -I$MPCHOME/h");
              }
            else
              {
                if(i<host)
                  {
                    strcat(params, " ");
                    strcat(params, argv[i]);
                  }
                strcat(params_host, " ");
                strcat(params_host, argv[i]);
              }
        }
      //strcat(params_host, " -lmpi -lm");
      //strcat(params, " -lmpi -lm");
      strcat(params_host, " -lm");
      strcat(params, " -lm");
      j=0;
      while(fscanf(fdef, "%s", buf)==1)
        {
          if(j==0)
            if(strcmp(myname, buf))
              {
                printf("mpcload: You can load a program in machine \'%s\'\n", name);
                printf("         only from host \'%s\'.  Sorry. Bye!\n", buf);
                fclose(fp);
                remove(vasya);
                exit(-1);
              }
            else
              if(!strcmp(whichmpi,lam63))
                fprintf(fp,"-np 1 -s h n%d %s %s\n", j, "mpcld", params_host);
              else
                fprintf(fp,"%s -c 1 -s h n%d -- %s\n", "mpcld", j, params_host);
          else
            if(!strcmp(whichmpi,lam63))
              fprintf(fp,"-np 1 -s h n%d %s %s\n", j, "mpcld", params);
            else
              fprintf(fp,"%s -c 1 -s h n%d -- %s\n", "mpcld", j, params);
          j++;
        }
      fclose(fp);
      strcpy(buf, mpcload);
      strcat(buf, "/MPCzyuzya.5");
      fp=fopen(buf, "w");
      if(fp==NULL)
        {
          printf("mpcload: cannot create a working file in directory %s.\n", mpcload);
          exit(-1);
        }
      if(!strcmp(whichmpi,mpich_p4))
        fprintf(fp, "$MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/mpcld && $MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/gather %s && rm $MPCTOPO/MPCshemazagruzki.vasya", pgfile, pgfile1, name);        
      else if(!strcmp(whichmpi,lam) || !strcmp(whichmpi,lam63))
        fprintf(fp, "$MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.vasya && $MPCHOME/bin/postload && $MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.vasya");
      else if(!strcmp(whichmpi,mpich))
        fprintf(fp, "cp $MPCTOPO/%s.def $MPIDIR/util/machines/machines.%s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/mpcld %s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/gather %s && rm $MPIDIR/util/machines/machines.%s && rm $MPCTOPO/MPCshemazagruzki.vasya", name, name, name, j, params_host, name, j, name, name);
    }
  else if(!host && get) 
    {
      strcpy(params,cc);
      if(getenv("HCCFLAGS"))
        strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
      else
        strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
      for(i=1; i<argc; i++)
        if(i!=host && i!=get)
          if(argv[i][0]!='-')
            {
              if(argv[i][0]!='/')
                strcat(params, " $MPCLOAD/");
              else
                strcat(params, " ");
              strcat(params, argv[i]);
              if(strstr(argv[i], ".")!=NULL)
                {
                  indicator++;
                  if(indicator==1)
                    {
                      strcat(params, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params, dirlib);
                    }
                }
              if(i==target)
                strcat(params, " -I$MPCHOME/h");                 
            }
          else
            {
              strcat(params, " ");
              strcat(params, argv[i]);
            }            
      //strcat(params, " -lmpi -lm");
      strcat(params, " -lm");
      j=0;
      while(fscanf(fdef, "%s", buf)==1)
        {
          if(j==0)
            {
              if(strcmp(myname, buf))
                {
                  printf("mpcload: You can load a program in machine \'%s\'\n", name);
                  printf("         only from host \'%s\'.  Sorry. Bye!\n", buf);
                  exit(-1);
                }
              else
                if(!strcmp(whichmpi,lam63))
                  fprintf(fp,"-np 1 -s n%d n%d %s %s\n", j, j, "mpcld", params);
                else
                  fprintf(fp,"%s -c 1 -s n%d n%d -- %s\n", "mpcld", j, j, params);
            }
          else
            if(!strcmp(whichmpi,lam63))
              fprintf(fp,"-np 1 -s n%d n%d %s %s\n", j, j, "mpcld", params);
            else
              fprintf(fp,"%s -c 1 -s n%d n%d -- %s\n", "mpcld", j, j, params);
          j++;
        }
      fclose(fp);
      strcpy(buf, mpcload);
      strcat(buf, "/MPCzyuzya.5");
      fp=fopen(buf, "w");
      if(fp==NULL)
        {
          printf("mpcload: cannot create a working file in directory %s.\n", mpcload);
          exit(-1);
        }
      if(!strcmp(whichmpi,mpich_p4))
        fprintf(fp, "$MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/mpcld && $MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/gather %s && rm $MPCTOPO/MPCshemazagruzki.vasya", pgfile, pgfile1, name);        
      else if(!strcmp(whichmpi,lam) || !strcmp(whichmpi,lam63))
        fprintf(fp, "$MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.vasya && $MPCHOME/bin/postload && $MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.vasya");
      else if(!strcmp(whichmpi,mpich))
        fprintf(fp, "cp $MPCTOPO/%s.def $MPIDIR/util/machines/machines.%s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/mpcld %s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/gather %s && rm $MPIDIR/util/machines/machines.%s && rm $MPCTOPO/MPCshemazagruzki.vasya", name, name, name, j, params, name, j, name, name);
    }
  else 
    {
      strcpy(params,cc);
      if(getenv("HCCFLAGS"))
        strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 $HCCFLAGS ");
      else
        strcat(params, "1>$MPCLOAD/mpcload.log 2>&1 -O2 ");
      for(i=1; i<argc; i++)
        if(i!=host && i!=get)
          if(argv[i][0]!='-')
            {
              if(argv[i][0]!='/')
                strcat(params, " $MPCLOAD/");
              else
                strcat(params, " ");
              strcat(params, argv[i]);
              if(strstr(argv[i], ".")!=NULL)
                {
                  indicator++;
                  if(indicator==1)
                    {
                      strcat(params, " $MPCHOME/lib/mpcrts.o $MPCHOME/lib/mpctopo.o ");
                      strcat(params, dirlib);
                    }
                }
              if(i==target)
                strcat(params, " -I$MPCHOME/h");                 
            }
          else
            {
              strcat(params, " ");
              strcat(params, argv[i]);
            }            
      //strcat(params, " -lmpi -lm");
      strcat(params, " -lm");
      j=0;
      while(fscanf(fdef, "%s", buf)==1)
        {
          if(j==0)
            if(strcmp(myname, buf))
              {
                printf("mpcload: You can load a program in machine \'%s\'\n", name);
                printf("         only from host \'%s\'.  Sorry. Bye!\n", buf);
                exit(-1);
              }
            else
              if(!strcmp(whichmpi,lam63))
                fprintf(fp,"-np 1 -s h n%d %s %s\n", j, "mpcld", params);
              else
                fprintf(fp,"%s -c 1 -s h n%d -- %s\n", "mpcld", j, params);
          else
            if(!strcmp(whichmpi,lam63))
              fprintf(fp,"-np 1 -s h n%d %s %s\n", j, "mpcld", params);
            else
              fprintf(fp,"%s -c 1 -s h n%d -- %s\n", "mpcld", j, params);
          j++;
        }
      fclose(fp);
      strcpy(buf, mpcload);
      strcat(buf, "/MPCzyuzya.5");
      fp=fopen(buf, "w");
      if(fp==NULL)
        {
          printf("mpcload: cannot create a working file in directory %s.\n", mpcload);
          exit(-1);
        }
      if(!strcmp(whichmpi,mpich_p4))
        fprintf(fp, "$MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/mpcld && $MPIDIR/bin/mpirun -p4pg %s $MPCHOME/bin/gather %s && rm $MPCTOPO/MPCshemazagruzki.vasya", pgfile, pgfile1, name);        
      else if(!strcmp(whichmpi,lam) || !strcmp(whichmpi,lam63))
        fprintf(fp, "$MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.vasya && $MPCHOME/bin/postload && $MPIDIR/bin/mpirun -w $MPIFLAGS $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.mitya && rm $MPCTOPO/MPCshemazagruzki.vasya");
      else if(!strcmp(whichmpi,mpich))
        fprintf(fp, "cp $MPCTOPO/%s.def $MPIDIR/util/machines/machines.%s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/mpcld %s && $MPIDIR/bin/mpirun -arch %s -np %d $MPCHOME/bin/gather %s && rm $MPIDIR/util/machines/machines.%s && rm $MPCTOPO/MPCshemazagruzki.vasya", name, name, name, j, params, name, j, name, name);
    }
  exit(0);
}
