#include "io.hpp"
#include <limits.h>


#ifndef SIZE_MAX
    //#pragma message ( "SIZE_MAX undefined" )
    #define SIZE_MAX ((size_t)-1)
#endif


static void progress(off_t at, off_t max) {
    if (!max || max < 1000*1000) return;
    static int last_frac = -1;

    int frac = (int)((at * 10) / max); // 0-10
    if (frac == last_frac) {
        return;
    }
    last_frac = frac;

    static const char* P="############";
    printf("\r[%.*s%*s] %3d%%", frac, P, 10-frac, "", (int)frac*10);
    fflush(stdout);

    if (at >= max) {
        printf(" Done.\n");
        last_frac = -1;
    }
}


bool write_buffered(off_t len, int from, int to) {
    const off_t total = len;
    static char buf[4096];
    while (len) {
        progress(total-len, total);

        ssize_t rv = read(from, buf, MIN(len, (off_t)sizeof(buf)));
        if (rv == 0) {
            printf("\n");
            LOG("read() - 0");
            return false;
        } else if (rv == -1) {
            LOG_ERRNO("read()");
            printf("\n");
            return false;
        } else {
            len -= rv;
        }

        char* p = buf;
        while (rv) {
            ssize_t wrv = write(to, p, rv);
            if (wrv == 0) {
                printf("\n");
                LOG("write() - 0");
                return false;
            } else if (wrv == -1) {
                LOG_ERRNO("write()");
                printf("\n");
                return false;
            } else {
                rv -= wrv;
            }
        }

    }
    progress(total, total);
    return true;
}


/*bool write_unbuffered(off_t len, int from, int to) {
    bool noop = true;
    while (len) {
        size_t llen = MIN(len, (off_t)SIZE_MAX);
        ssize_t rv = sendfile(to, from, NULL, llen);
        if (rv == 0) { // ???
            LOG("sendfile() - 0");
            return false;
        } else if (rv == -1) { // don't check for EINTR etc here?
            if (errno == EINVAL && noop) {
                #if 0
                    LOG_ERRNO("switching to buffered io");
                #endif
                return write_buffered(len, from, to);
            }
            LOG_ERRNO("sendfile()");
            return false;
        } else {
            noop = false;
            len -= rv;
        }
    }
    return true;
}*/