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

#define READ_BUF_SIZE 4096
#define LINE_BUF_SIZE 4096

static void write_all(int fd, const char *buf, size_t len)
{
    while (len > 0) {
        ssize_t n = write(fd, buf, len);
        if (n < 0) {
            if (errno == EINTR) continue;
            _exit(1);
        }
        buf += n;
        len -= (size_t)n;
    }
}

static int flush_result(const char *word, long total)
{
    char buf[LINE_BUF_SIZE + 64];
    int n = snprintf(buf, sizeof(buf), "%s %ld\n", word, total);
    if (n < 0) return -1;
    write_all(STDOUT_FILENO, buf, (size_t)n);
    return 0;
}

static void log_usage(const char *progname)
{
    char buf[256];
    int n = snprintf(buf, sizeof(buf),
                     "Uso: %s <partition_index>\n", progname);
    if (n > 0) write_all(STDERR_FILENO, buf, (size_t)n);
}

int main(int argc, char *argv[])
{
    char rbuf[READ_BUF_SIZE];
    char line[LINE_BUF_SIZE];
    char current_word[LINE_BUF_SIZE];
    size_t line_len = 0;
    long current_total = 0;
    int has_current = 0;
    int partition_index = -1;
    ssize_t nread;

    if (argc != 2) {
        log_usage(argv[0]);
        return 1;
    }

    partition_index = atoi(argv[1]);

    current_word[0] = '\0';

    while ((nread = read(STDIN_FILENO, rbuf, sizeof(rbuf))) > 0) {
        ssize_t i;
        for (i = 0; i < nread; ++i) {
            char c = rbuf[i];
            if (c == '\n') {
                if (line_len > 0) {
                    char word[LINE_BUF_SIZE];
                    int count = 0;

                    line[line_len] = '\0';
                    if (sscanf(line, "%s %d", word, &count) == 2) {
                        if (!has_current) {
                            strcpy(current_word, word);
                            current_total = count;
                            has_current = 1;
                        } else if (strcmp(current_word, word) == 0) {
                            current_total += count;
                        } else {
                            if (flush_result(current_word, current_total) < 0) return 1;
                            strcpy(current_word, word);
                            current_total = count;
                        }
                    }
                    line_len = 0;
                }
            } else {
                if (line_len + 1 < sizeof(line)) line[line_len++] = c;
            }
        }
    }

    if (nread < 0) return 1;

    if (line_len > 0) {
        char word[LINE_BUF_SIZE];
        int count = 0;
        line[line_len] = '\0';
        if (sscanf(line, "%s %d", word, &count) == 2) {
            if (!has_current) {
                strcpy(current_word, word);
                current_total = count;
                has_current = 1;
            } else if (strcmp(current_word, word) == 0) {
                current_total += count;
            } else {
                if (flush_result(current_word, current_total) < 0) return 1;
                strcpy(current_word, word);
                current_total = count;
            }
        }
    }

    if (has_current) {
        if (flush_result(current_word, current_total) < 0) return 1;
    }

    {
        char buf[128];
        int n = snprintf(buf, sizeof(buf),
                         "[WordCount:reduce] Reduced partition %d.\n",
                         partition_index);
        if (n > 0) write_all(STDERR_FILENO, buf, (size_t)n);
    }

    return 0;
}
