#include "buffer.h"
#include <iostream>
#include <fstream>

Buffer::Buffer()
{
	buffer = nullptr;
	size = 0;
	taken = 0;
}

Buffer::Buffer(size_t size)
{
	this->size = size;
	this->buffer = new uint8_t[size];
}

Buffer::~Buffer()
{
	if (buffer)	delete[] buffer;
}

bool Buffer::resize(size_t new_size)
{
	if (size >= new_size) return true;
	uint8_t* new_buffer = (uint8_t*)realloc(buffer, new_size);
	if (!new_buffer)
	{
		printf_s("Error resizing buffer\n");
		return false;
	}
	buffer = new_buffer;
	size = new_size;
	return true;
}

int Buffer::add_end(uint8_t* data, size_t data_size)
{
	if (taken + data_size > size)
		if (!resize(size + data_size)) return -1;

	memcpy_s(buffer + taken, size - taken, data, data_size);
	taken += data_size;
	return taken - data_size;
}

int Buffer::add_middle(uint8_t* data, size_t data_size, size_t index)
{
	if (taken + data_size > size)
		if (!resize(size + data_size)) return -1;
	memmove_s(buffer + index + data_size, size - index - data_size, buffer + index, taken - index);
	memcpy_s(buffer + index, size - index, data, data_size);
	taken += data_size;
	return index;
}

void Buffer::remove_fast(uint8_t* data, size_t data_size)
{
	int64_t index = data - buffer;
	if (index < 0 || index > taken || index + data_size > taken)
	{
		printf_s("Error removing from buffer\n");
		return;
	}
	memmove_s(buffer + index, size - index, buffer + index + data_size, taken - index - data_size);
	taken -= data_size;
}

void Buffer::remove(size_t index, size_t data_size)
{
	if (index + data_size > taken)
	{
		printf_s("Error removing from buffer\n");
		return;
	}
	memmove_s(buffer + index, size - index, buffer + index + data_size, taken - index - data_size);
	taken -= data_size;
}

size_t Buffer::find(uint8_t* data, size_t data_size)
{
	for (size_t i = 0; i < taken; i++)
		if (memcmp(buffer + i, data, data_size) == 0)
			return i;

	return -1;
}

void Buffer::remove(uint8_t* data, size_t data_size)
{
	size_t index = find(data, data_size);
	if (index == -1)
	{
		printf_s("Error removing from buffer\n");
		return;
	}
	remove(index, data_size);
}

bool Buffer::save_to_file()
{
	std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
	if (!file.is_open())
	{
		printf_s("Error saving file\n");
		return false;
	}
	file.write((char*)this->buffer, this->taken);
	file.close();
	return true;
}

bool Buffer::save_to_file(std::string file_path)
{
	this->file_path = file_path;
	return save_to_file();
}

bool Buffer::load_from_file()
{
	std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
	if (!file.is_open()) return false;

	file.seekg(0, std::ios::end);

	size_t file_size = file.tellg();
	resize(file_size);

	file.seekg(0, std::ios::beg);
	file.read((char*)buffer, size);

	if (file)
		taken = file_size;
	else
		taken = file.gcount();

	file.close();
	return true;
}

bool Buffer::load_from_file(std::string file_path)
{
	this->file_path = file_path;
	return load_from_file();
}