#include "file_handle.h"
#include <algorithm>
#define READ_DATA_SIZE 1024
namespace engineapi {
	FileHandle& FileHandle::Open(FILE_OP _op, bool is_binarry)
	{
		op = _op;
		string file_path = RealPath();
		switch (op)
		{
		case engineapi::FILE_OP::READ:
		{
			vfile = std::ifstream(file_path, is_binarry ? std::ios::binary : 0);
			if (!Reader().is_open()) {
				return *this;
			}
			break;
		}
		case engineapi::FILE_OP::WRITE:
			vfile = std::ofstream(file_path, is_binarry ? std::ios::binary : 0);
			break;
		case engineapi::FILE_OP::APPEND:
			vfile = std::ofstream(file_path, is_binarry ? std::ios::app | std::ios::binary : std::ios::app);
			break;
		default:
			break;
		}
		flag = FileFlag::File_Success | (is_binarry ? FileFlag::File_Binary : 0);
		return *this;
	}
	int FileHandle::Read(void* data, int size)
	{
		auto& fi = Reader();
		if (!fi) {
			return -1;
		}
		fi.read((char*)data, size);
		return fi.gcount();
	}
	string FileHandle::ReadUntil(const string& token)
	{
		auto& fi = Reader();
		size_t cur = fi.tellg();
		fi.seekg(0, std::ios::end);
		size_t size = (size_t)fi.tellg() - cur;
		fi.seekg(cur);
		size_t buffer_size = READ_DATA_SIZE;
		string buffer;
		char chunk[READ_DATA_SIZE];
		while (buffer_size < size) {
			fi.read(chunk, READ_DATA_SIZE);
			buffer.append(chunk, READ_DATA_SIZE);
			size_t offset = buffer_size > READ_DATA_SIZE ? buffer_size - READ_DATA_SIZE - token.size() : 0;
			size_t it = buffer.substr(offset).find(token);
			if (it != std::string::npos) {
				buffer_size = offset + it;
				buffer.resize(buffer_size);
				fi.seekg(cur + buffer_size + token.size());
				return buffer;
			}
			buffer_size += READ_DATA_SIZE;
		}
		return buffer;
	}
	vector<char> FileHandle::ReadUntil(const vector<char>& token)
	{
		auto& fi = Reader();
		size_t cur = fi.tellg();
		fi.seekg(0, std::ios::end);
		size_t size = (size_t)fi.tellg() - cur;
		fi.seekg(cur);
		size_t buffer_size = READ_DATA_SIZE;
		vector<char> buffer(buffer_size);
		while (buffer_size < size) {
			fi.read(buffer.data(), READ_DATA_SIZE);
			size_t offset = buffer_size > READ_DATA_SIZE ? buffer_size - READ_DATA_SIZE - token.size() : 0;
			auto it = std::search(buffer.begin() + offset, buffer.end(), token.begin(), token.end());
			if (it != buffer.end()) {
				buffer_size += it - buffer.end();
				buffer.resize(buffer_size);
				fi.seekg(cur + buffer_size + token.size());
				return buffer;
			}
			buffer_size += READ_DATA_SIZE;
			buffer.insert(buffer.end(), READ_DATA_SIZE, 0);
		}
		return buffer;
	}
	void FileHandle::Write(const char* data,size_t size)
	{
		Writer().write(data, size);
	}
}
