#include "file.h"
#include "viewer.h"
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

file_view_area_t view_area;

static int _file_get_size_of_first_line()
{
    int res = 0;
    for (int i = view_area.start; i < view_area.data_len; i++) {
        res++;
        if (view_area.buffer[i] == '\n') {
            return res;
        }
    }
    return view_area.data_len - view_area.start;
}

static void _file_find_start(uint32_t old_offset)
{
    old_offset -= 2;
    while (old_offset > view_area.offset) {
        if (view_area.buffer[old_offset - view_area.offset] == '\n') {
            view_area.start = old_offset - view_area.offset + 1;
            return;
        }
        old_offset--;
    }
    view_area.start = 0;
}

static inline int _file_remaining_size()
{
    return view_area.data_len - view_area.start;
}

static inline int _file_is_last_line_in_buf()
{
    return 1;
}

int _file_buf_flush()
{
    /* FIXME: for now we think that we have all file in our buffer */
    lseek(view_area.fd, view_area.offset, SEEK_SET);
    view_area.data_len = write(view_area.fd, view_area.buffer, view_area.data_len);
    return 0;
}

int _file_buf_reload(int offset_in_file)
{
    /* TODO: Get real file size */
    view_area.buf_len = 4000;
    view_area.buffer = (char*)malloc(view_area.buf_len);

    view_area.start = 0;
    view_area.offset = offset_in_file;
    view_area.was_changed = 0;
    lseek(view_area.fd, view_area.offset, SEEK_SET);
    view_area.data_len = read(view_area.fd, view_area.buffer, view_area.buf_len);
    if (view_area.data_len < 0) {
        return -1;
    }
    return 0;
}

int file_line_len(int offset)
{
    int res = 0;
    for (int i = offset; i < view_area.data_len; i++) {
        res++;
        if (view_area.buffer[i] == '\n') {
            return res;
        }
    }
    return view_area.data_len - view_area.start;
}

int file_line_len_backwards(int offset)
{

    int res = 1;
    for (int i = offset - 1; i >= view_area.offset; i--) {
        if (view_area.buffer[i] == '\n') {
            return res;
        }
        res++;
    }
    return offset;
}

int file_open(char* path)
{
    int n;
    if ((view_area.fd = open(path, O_RDWR)) < 0) {
        return -1;
    }

    _file_buf_reload(0);
    if (view_area.data_len < 0) {
        return -1;
    }

    viewer_display(view_area.buffer, view_area.start, _file_remaining_size());

    return view_area.fd;
}

void file_exit()
{
    close(view_area.fd);
}

/**
 * file_paste_char pastes and flush updates to disk.
 */
int file_paste_char(char c, int offset)
{
    view_area.was_changed = 1;
    view_area.data_len++;

    memmove(view_area.buffer + offset + 1, view_area.buffer + offset, view_area.data_len - offset - 1);
    view_area.buffer[offset] = c;
    viewer_cursor_next();
    viewer_display(view_area.buffer, view_area.start, _file_remaining_size());
}

/**
 * file_paste_char pastes and flush updates to disk.
 */
int file_save()
{
    if (view_area.was_changed) {
        _file_buf_flush();
    }
}

/**
 * Scroll functions update file buffer, to contain line scrolled to.
 */
int file_scroll_up()
{
    if (view_area.line == 0 || view_area.start == 0) {
        return -1;
    }
    view_area.line--;
    int old_offset_in_file = view_area.offset + view_area.start;
    int offset_in_file = view_area.offset + view_area.start - SCREEN_X;
    if (offset_in_file < 0) {
        offset_in_file = 0;
    }

    if (offset_in_file >= view_area.offset) {
        view_area.start = offset_in_file - view_area.offset;
        _file_find_start(old_offset_in_file);
        viewer_display(view_area.buffer, view_area.start, _file_remaining_size());
    } else {
        _file_buf_reload(offset_in_file);
        _file_find_start(old_offset_in_file);
        viewer_display(view_area.buffer, view_area.start, _file_remaining_size());
    }
}

int file_scroll_down()
{
    int line_size = _file_get_size_of_first_line();
    view_area.start += line_size;
    if (!_file_is_last_line_in_buf()) {
        _file_buf_reload(view_area.offset + view_area.start);
    }
    viewer_display(view_area.buffer, view_area.start, _file_remaining_size());
    view_area.line++;
}