#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char * argv[]) 
{
    int delay = 0;
    if (argc == 2) {
        delay = atoi(argv[1]);
    }

    int pipes[2]; // pipes[0] = read, pipes[1] = write
    int pid;

    pipe(pipes);

    pid = fork();

    if (pid == -1) {
        fprintf(stderr, "fork() failed\n");
        exit(1);
    }
    
    if (pid == 0) {
        fprintf(stdout, "child: waiting for %d seconds\n", delay);
        sleep(delay);

        fprintf(stdout, "child: sending \"Hello\" on pipe\n");

        write(pipes[1], "Hello", strlen("Hello"));
        exit(0);
    } else {
        fprintf(stdout, "parent: waiting to read from pipe\n");

        // Build a set of FDs that are waiting for a read
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(pipes[0], &readfds);

        // Set a timeout of 5 seconds
        struct timeval timeout;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        // select() on the read pipe
        int ret = select(pipes[0]+1, &readfds, NULL, NULL, &timeout);

        if (ret == -1) {
            perror("select");
        } else if (ret) {
            // Select returns the number of file descriptors that are ready
            if (FD_ISSET(pipes[0], &readfds)) {
                char * buffer = (char*)malloc(sizeof(char)*100);
                read(pipes[0], buffer, 100);

                fprintf(stdout, "parent: received \"%s\"\n", buffer);
                free(buffer);
            } else {
                fprintf(stderr, "select returned 1, but pipes[0] was not set\n");
            }
        } else {
            // ret == 0 implies timeout occurred
            fprintf(stderr, "parent: no data to be read after timeout\n");
        }

        waitpid(pid, NULL, 0);
    }   

    return 0;
}
