#include "file.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "error.h"

u8 *sw_file_load(char *path, u32 *out_size) {
	FILE *fil;
	u32 len;
	u8 *data;

	fil = fopen(path, "rb");
	if(!fil) {
		sw_error("Can't load file at \"%s\"", path);
	}
	fseek(fil, 0, SEEK_END);
	len = ftell(fil);
	fseek(fil, 0, SEEK_SET);
	data = malloc(len);
	fread(data, 1, len, fil);
	fclose(fil);

	*out_size = len;
	return data;
}

struct sw_filebuffer *sw_filebuffer_create(u32 size) {
	struct sw_filebuffer *buf;

	buf = malloc(sizeof(struct sw_filebuffer));
	buf->_data = malloc(size);
	buf->size = size;
	buf->pos = 0;

	return buf;
}

struct sw_filebuffer *sw_filebuffer_load(char *path) {
	struct sw_filebuffer *buf;
	u32 size;
	u8 *data;

	data = sw_file_load(path, &size);
	buf = sw_filebuffer_create(size);
	buf->_data = data;

	return buf;
}

void sw_filebuffer_destroy(struct sw_filebuffer *buf) {
	free(buf->_data);
	free(buf);
}

void sw_filebuffer_read(struct sw_filebuffer *buf, void *dst, u32 count) {
	if(buf->pos + count > buf->size) {
		sw_error("read past buffer");
	}
	memcpy(dst, buf->_data + buf->pos, count);
	buf->pos += count;
}

/* fwrite helpers */

void sw_fwrite_u8(FILE *fil, u8 val) {
	fwrite(&val, 1, 1, fil);
}

void sw_fwrite_i8(FILE *fil, i8 val) {
	fwrite(&val, 1, 1, fil);
}

void sw_fwrite_u16(FILE *fil, u16 val) {
	fwrite(&val, 1, 2, fil);
}

void sw_fwrite_i16(FILE *fil, u16 val) {
	fwrite(&val, 1, 2, fil);
}

void sw_fwrite_u32(FILE *fil, u32 val) {
	fwrite(&val, 1, 4, fil);
}

void sw_fwrite_i32(FILE *fil, u32 val) {
	fwrite(&val, 1, 4, fil);
}

void sw_fwrite_u64(FILE *fil, u64 val) {
	fwrite(&val, 1, 8, fil);
}

void sw_fwrite_i64(FILE *fil, u64 val) {
	fwrite(&val, 1, 8, fil);
}

void sw_fwrite_f32(FILE *fil, f32 val) {
	fwrite(&val, 1, 4, fil);
}

void sw_fwrite_f64(FILE *fil, f64 val) {
	fwrite(&val, 1, 8, fil);
}

void sw_fwrite_bool(FILE *fil, bool val) {
	fwrite(&val, 1, 1, fil);
}

void sw_fwrite_str_nozero(FILE *fil, char *str) {
	fwrite(str, strlen(str), 1, fil);
}

void sw_fwrite_str_zero(FILE *fil, char *str) {
	fwrite(str, strlen(str), 1, fil);
	sw_fwrite_u8(fil, 0);
}

/* TODO: implement checks that string not too long? */

void sw_fwrite_str_prefix8(FILE *fil, char *str) {
	u8 size = strlen(str);
	sw_fwrite_u8(fil, size);
	fwrite(str, size, 1, fil);
}

void sw_fwrite_str_prefix16(FILE *fil, char *str) {
	u16 size = strlen(str);
	sw_fwrite_u16(fil, size);
	fwrite(str, size, 1, fil);
}

void sw_fwrite_str_prefix32(FILE *fil, char *str) {
	u32 size = strlen(str);
	sw_fwrite_u32(fil, size);
	fwrite(str, size, 1, fil);
}
