/*
 * pipe01.c
 * 
 * Copyright 2025 osboxes <osboxes@osboxes>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 * Version dinamica de padre que crea en abanico N hijos y mantiene
 * un pipe por cada hijo en donde le indica la fila de la matriz a
 * sumarizar y lee el resultado de cada hijo
 * 
 * forma de uso 
 * ./pipe01 5
 * crea 5 hijos en abanico para sumarizar filas de una matriz de totales
 * hijo1 suma fila 0 y asi sucesivamente
 * 
 * Igual que pipe01 pero ahora utilizo un solo pipe
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

// matriz con totales de ventas
double *totales = NULL;

void cargoVentas(double *,int);
void muestroVentas(double *,int);
double sumoVentas(double *,int);

typedef struct reg {
	int fila;
	double total;
} reg;

int main(int argc, char **argv) {
	if ( argc != 2 ) {
		printf("Forma de uso:\n./pipe01 N\nN=nro de hijos sumadores\n");
		return 1;
	}
	int i,nf = atoi(argv[1]);
	printf("(%d) soy proceso padre! matriz[%d][12]\n",getpid(),nf);
	if ( nf <= 0 ) {
		printf("numero de filas/hijos incorrecto (%d)\n",nf);
		return 2;
	}
	pid_t padre = getpid();
	// asigno matriz de double en forma dinamica
	totales = (double *) malloc(sizeof(double)*nf*12);
	memset(totales,0,sizeof(double)*nf*12);
	// lleno la matriz con totales de ventas
	cargoVentas(totales,nf*12);
	//muestroVentas(totales,nf);
	int p[2];
	pipe(p);
	// creo procesos
	for(i=0;i<nf;i++) {
		pid_t pid = fork();
		if ( pid == 0 ) break;
	}
	if ( getpid() != padre ) {
		// soy hijo i-esimo
		close(p[0]);
		reg res;
		res.fila = i;
		res.total = sumoVentas(totales,i);
		write(p[1],&res,sizeof(reg));
		close(p[1]);
		exit(i);
	} else {
		// soy padre, cierro extremo de escritura
		close(p[1]);
		double totsuchijo[nf],totsuc[nf];
		reg r[nf];
		for(i=0;i<nf;i++) read(p[0],&r[i],sizeof(reg));
		// soy padre, cierro extremo de lectura
		close(p[0]);
		for(i=0;i<nf;i++) totsuchijo[r[i].fila] = r[i].total;
		muestroVentas(totales,nf);
		for(i=0;i<nf;i++) totsuc[i] = sumoVentas(totales,i);
		for(i=0;i<nf;i++)
			printf("Total recibido hijo(%d)=%lf vs mi total=%lf\n",
				i,totsuchijo[i],totsuc[i]);
		// espero por finalizacion de todos los hijos
		while(wait(0) != -1);
	}
	return 0;
}

void cargoVentas(double *p,int n) {
	srand(time(NULL));
	int i;
	for(i=0;i<n;i++,p++) *p = (double) (rand()/100000.0);
}

void muestroVentas(double *matriz,int nf) {
	int s,m;
	for(s=0;s<nf;s++) {
		printf("%4d ",s);
		for(m=0;m<12;m++) {
			printf("%10.2lf",*matriz);
			matriz++;
		}
		printf("\n");
	}
}

double sumoVentas(double *m,int f) {
	double tot = 0.0;
	int mes;
	m+=f*12;
	for(mes=0;mes<12;mes++,m++) tot+=*m;
	return tot;
}


