#include <desc.h>
#include <filewriter.h>
#include <path_defs.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <system.h>
#include <write_file.h>

int filewriter_init (struct filewriter* fw, const char* volume, const char* path, uint32_t flags) {
  memset (fw, 0, sizeof (*fw));
  strncpy (fw->volume, volume, VOLUME_MAX);
  strncpy (fw->path, path, PATH_MAX);
  fw->flags = flags;

  int ret;
  struct desc desc;

  if ((ret = volume_open (fw->volume)) < 0)
    return -FW_VOLUME_OPEN_ERROR;

  if ((fw->flags & FW_CREATE_FILE)) {
    if ((ret = create_file (fw->path)) < 0) {
      volume_close ();
      return -FW_CREATE_FILE_ERROR;
    }
  }

  if ((ret = describe (fw->path, &desc)) < 0) {
    volume_close ();
    return -FW_DESC_ERROR;
  }

  if (desc.type != FS_FILE)
    return -FW_NOT_FILE;

  fw->file_size = desc.size;
  fw->flags |= FW_OPEN;

  if ((fw->flags & FW_APPEND))
    fw->write_cursor = desc.size;

  return FW_OK;
}

int filewriter_fini (struct filewriter* fw) {
  if ((fw->flags & FW_OPEN)) {
    volume_close ();
    fw->flags &= ~FW_OPEN;
  }

  return FW_OK;
}

int filewriter_write (struct filewriter* fw, uint8_t* buffer, size_t buffer_size) {
  if (!(fw->flags & FW_OPEN))
    return -FW_VOLUME_NOT_OPENED;

  struct desc desc;
  int ret;

  if ((fw->flags & FW_APPEND)) {
    if ((ret = describe (fw->path, &desc)) < 0)
      return -FW_DESC_ERROR;

    fw->file_size = desc.size;
    fw->write_cursor = fw->file_size;
  }

  if (buffer_size > 0) {
    if (!(fw->flags & FW_APPEND) && !(fw->write_cursor + buffer_size <= fw->file_size))
      return -FW_CURSOR_OOB;

    uint32_t flags = (fw->flags & FW_APPEND) ? WF_APPEND : 0;
    if ((ret = write_file (fw->path, fw->write_cursor, buffer, buffer_size, flags)) < 0)
      return -FW_WRITE_ERROR;

    fw->write_cursor += buffer_size;
  }

  return FW_OK;
}
