#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>

struct delemem
{
    int niz[12];
    int size;
};

struct poruka
{
    long mtype;
    int func;
    //int pid;
}; 

struct glav_rad
{
    
    int niz[3];
    int n;
};

struct radnim
{
    long mtype;
    int niz[4];
    int f;
};

int suma(int *niz,int size)
{
    int suma = 0;
    for(int i=0;i<size;i++)
    {
        suma += niz[i];
    }
    return suma;
}
int proizvod(int *niz,int size)
{
    int proizvod = 1;
    for(int i=0;i<size;i++)
    {
        proizvod *= niz[i];
    }
    return proizvod;
}
int minimum(int *niz,int size)
{
    int p = niz[0];
    for(int i=1;i<size;i++)
    {
        if(p<niz[i])
        {
            p = niz[i];
        }
    }
    return p;
}
int maximum(int *niz,int size)
{
    int p = niz[0];
    for(int i=1;i<size;i++)
    {
        if(p>niz[i])
        {
            p = niz[i];
        }
    }
    return p;
}



int main()
{
    key_t msg_key = ftok("glavni_cvor.c",1);
    key_t shm_key = ftok("glavni_cvor.c",2);
    key_t sem_key = ftok("glavni_cvor.c",3);

    key_t msg_rad_key = ftok("glavni_cvor.c",4);
    //mora jos jedna deljena memorija
    key_t shm_rad_key = ftok("glavni_cvor.c",5);

    int msg_id = msgget(msg_key,IPC_CREAT|0666);
    int shm_id = shmget(shm_key,sizeof(struct delemem),IPC_CREAT|0666);
    int sem_id = semget(sem_key,3,IPC_CREAT|0666);
    int msg_rad_id = msgget(msg_rad_key,IPC_CREAT|0666);
    int shm_rad_id = shmget(shm_rad_key,sizeof(struct glav_rad),IPC_CREAT|0666);

    struct delemem *dm = (struct delemem*)shmat(shm_id,NULL,0);

    struct glav_rad *gr = (struct glav_rad*)shmat(shm_rad_id,NULL,0);
    gr->n = 0;
    struct poruka p;
    struct poruka odgovor;
    odgovor.mtype = 2;
    semctl(sem_id,0,SETVAL,1);//pristup glavnom procesu
    semctl(sem_id,1,SETVAL,1);//jedan po jedan
    semctl(sem_id,2,SETVAL,0);//radni cvorovi
    struct radnim r;
    r.mtype = 1;
    struct sembuf P0 = {0,-1,0};
    struct sembuf V0 = {0,1,0};
    //struct sembuf P1 = {1,-1,0};
    //struct sembuf V1 = {1,-1,0};
    struct sembuf P2 = {2,-3,0};
    //struct sembuf V2 = {2,1,0};

    while(1)
    {
        printf("Glavni cvor: ceka zahtev od korisnika.\n");
        msgrcv(msg_id,&p,sizeof(p) - sizeof(long),1,0);

        semop(sem_id,&P0,1);//smanjujemo semafor ulazim u rad glavnog cvora
        int br = 0;
        for(int i=0;i<4;i++)
        {
            r.niz[br] = dm->niz[i];
            br++;
            r.f = p.func;
            msgsnd(msg_rad_id,&r,sizeof(r) - sizeof(long),0);

        }
        br = 0;
        for(int i=4;i<8;i++)
        {
            r.niz[br+i] = dm->niz[br+i];
            br++;
            r.f = p.func;
            msgsnd(msg_rad_id,&r,sizeof(r) - sizeof(long),0);
        }
        br = 0;
        for(int i=8;i<12;i++)
        {
            r.niz[br+i] = dm->niz[br+i];
            br++;
            r.f = p.func;
            msgsnd(msg_rad_id,&r,sizeof(r) - sizeof(long),0);
        }
        printf("Glavni cvor: ceka da svi radni cvorovi zavrse operacije.\n");
        semop(sem_id,&P2,1);
        //izvrsavanje operacije
        if(p.func == 0)
        {
            printf("Glavni cvor: Korisnik je trazio sumu brojeva.\n");
            odgovor.func = suma(gr->niz,gr->n+1);
            
        }
        else if (p.func == 1)
        {
            printf("Glavni cvor: Korisnik je trazio proizvod brojeva.\n");
            odgovor.func = proizvod(gr->niz,gr->n+1);
            
        }
        else if (p.func == 2)
        {
            printf("Glavni cvor: Korisnik je trazio minimum brojeva.\n");
            odgovor.func = minimum(gr->niz,gr->n+1);
            
        }
        else
        {
            printf("Glavni cvor: Korisnik je trazio maximum brojeva.\n");
            odgovor.func = maximum(gr->niz,gr->n+1);
            
        }
        msgsnd(msg_id,&r,sizeof(odgovor) - sizeof(long),0);

        semop(sem_id,&V0,1);//proces se zavrsio

    }

    shmdt(dm);
    shmdt(gr);
    return 0;
}