#include "mpi.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFSIZE    256*1024
#define CMDSIZE    80
/* The maximum path len can be tricky to determine.  We use
   a default value that will work for this application. */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

void makehostlist(char *, const char *, int *);

int main(int argc, char *argv[])
{
    int      num_hosts, mystatus, allstatus, done, numread;
    int      infd, outfd;
    char     outfilename[MAXPATHLEN], controlmsg[CMDSIZE];
    char     buf[BUFSIZE];
    char     soft_limit[20];
    MPI_Info hostinfo;
    MPI_Comm pcpworkers, all_processes;

    MPI_Init(&argc, &argv);

    makehostlist(argv[1], "targets", &num_hosts);
    MPI_Info_create(&hostinfo);
    MPI_Info_set(hostinfo, "file", "targets");
    sprintf(soft_limit, "0:%d", num_hosts);
    MPI_Info_set(hostinfo, "soft", soft_limit);
    MPI_Comm_spawn("pcp-spawn-worker", MPI_ARGV_NULL, num_hosts,
                   hostinfo, 0, MPI_COMM_SELF, &pcpworkers,
		   MPI_ERRCODES_IGNORE);
    MPI_Info_free(&hostinfo);
    MPI_Intercomm_merge(pcpworkers, 0, &all_processes);
strcpy(outfilename, argv[3]);
if ((infd = open(argv[2], O_RDONLY)) == -1) {
  fprintf(stderr, "input %s does not exist\n", argv[2]);
  sprintf(controlmsg, "exit");
  MPI_Bcast(controlmsg, CMDSIZE, MPI_CHAR, 0, all_processes);
  MPI_Finalize();
  return -1 ;
} else {
  sprintf(controlmsg, "ready");
  MPI_Bcast(controlmsg, CMDSIZE, MPI_CHAR, 0, all_processes);
}
MPI_Bcast(outfilename, MAXPATHLEN, MPI_CHAR, 0,
          all_processes);
if ((outfd = open(outfilename, O_CREAT|O_WRONLY|O_TRUNC,
	S_IRWXU)) == -1)
  mystatus = -1;
else
  mystatus = 0;
MPI_Allreduce(&mystatus, &allstatus, 1, MPI_INT, MPI_MIN,
              all_processes);
if (allstatus == -1) {
  fprintf(stderr, "Output file %s could not be opened\n",
          outfilename);
  MPI_Finalize();
  return 1 ;
}
    /* at this point all files have been successfully opened */
    done = 0;
    while (!done) {
        numread = read(infd, buf, BUFSIZE);
	MPI_Bcast(&numread, 1, MPI_INT, 0, all_processes);
	if (numread > 0) {
	    MPI_Bcast(buf, numread, MPI_BYTE, 0, all_processes);
	    write(outfd, buf, numread);
	}
	else {
	    close(outfd);
	    done = 1;
	}
    }
    MPI_Comm_free(&pcpworkers);
    MPI_Comm_free(&all_processes);
    MPI_Finalize();
    return 0;
}

/* Create the host list from the named argument and return the number.
   Write the host list to the file fname.  The list is a comma-separated
   set of host names.
   The intent is that this could provide ways to indicate a range of names.
   For example: node37-node42 could be used to indicate node37,node38,node39,
   node40,node41,node42.
*/
void makehostlist(char *list, const char* fname, int *nfound)
{
    char *p;
    char tmpname[MAXPATHLEN];
    FILE *fp;
    fp = fopen(fname, "w");
    if (!fp) {
	fprintf(stderr,"Could not open file %s\n", fname);
        MPI_Abort(MPI_COMM_WORLD,1);
    }
    while (*list) {
	p = list;
	while (*p && *p != ',') {
	    tmpname[p-list] = *p;
	    p++;
	}
	tmpname[p-list] = 0;
	fprintf(fp,"%s\n",tmpname);
	p++;
	list = p;
    }
    fclose(fp);
}