#define _GNU_SOURCE

#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <err.h>
#include <sys/types.h>
#include "../lpi.h"

void usage(void);

int
main(int argc, char *argv[])
{
    int     fd, i, nread, num, whence;
    char    buf[BUFSIZ + 1];
    off_t   offset;
    mode_t  fileMode;

    offset = 0;
    fileMode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH);  //rwxr-xr-w

    if (argc < 3 || strcmp(argv[1], "--help") == 0)
        usage();

    if ((fd = open(argv[1], O_RDWR, fileMode)) == -1)
        err(EXIT_FAILURE, "%s", argv[1]);

    for (i = 2; i < argc; i++) {
        switch (argv[i][0]) {
        case 's':
        case 'c':
        case 'e':
            if ((errno = toLongLong(&argv[i][1], (long long *) &offset)) != 0)
                err(EXIT_FAILURE, "toLongLong");

            switch (argv[i][0]) {
            case 's':
                whence = SEEK_SET;
                break;
            case 'c':
                whence = SEEK_CUR;
                break;
            case 'e':
                whence = SEEK_END;
                break;
            default:
                usage();
                /* unreachable */
                break;
            }
            if (lseek(fd, offset, whence) == -1)
                err(EXIT_FAILURE, "lseek");
            break;
        case 'w':
            if (write(fd, &argv[i][1], strlen(&argv[i][1])) == -1)
                err(EXIT_FAILURE, "write");
            break;
        case 'r':
            if ((errno = toInt(&argv[i][1],  &num)) != 0)
                err(EXIT_FAILURE, "toInt");
            if (num > sizeof(buf) - 1)
                errx(EXIT_FAILURE, "buffer is too small");

            if ((nread = read(fd, buf, num)) == -1)
                err(EXIT_FAILURE, "read");
            if (nread > 0) {
                buf[nread] = '\0';
                printf("%s\n", buf);
            }
            break;
        default:
            usage();
            /* unreachable */
            break;
        }
    }



    exit(EXIT_SUCCESS);
}

void
usage(void)
{
    errx(EXIT_FAILURE, "usage: %s file (s|c|e{offset} r{bytes}  w{text})*",
            program_invocation_short_name);
    /* unreachable */
}
