#include <string>

#include <errno.h>
#include <dirent.h>

#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

#include "Utils.h"

#include "FileSystem.h"

namespace khofmann
{
	rapidjson::Value readFile(const char* path, rapidjson::Document::AllocatorType& alloc)
	{
		FILE* file = fopen(path, "r");
		if (file)
		{
			fseek(file, 0, SEEK_END);
			long fsize = ftell(file);
			fseek(file, 0, SEEK_SET);

			char* string = (char*)calloc(sizeof(char), fsize + 1);
			fread(string, fsize, 1, file);
			fclose(file);

			rapidjson::Value retVal(string, alloc);
			free(string);
			return retVal;
		}

		int err = errno;
		log(stderr, "Error loading file %s: ERRNO %i\n", path, err);
		return rapidjson::Value("", alloc);
	}

	void writeFile(const char* path, rapidjson::Value &contents)
	{
		rapidjson::StringBuffer strbuf;
		rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
		contents.Accept(writer);

		FILE* file = fopen(path, "w");
		if (file)
		{
			fwrite(strbuf.GetString(), sizeof(char), strbuf.GetSize(), file);
			fclose(file);
			return;
		}
		int err = errno;
		log(stderr, "Error saving file %s: ERRNO %i\n", path, err);
	}

	/// <param name="alloc">Allocator</param>
	void enumerateDir(const char* path, rapidjson::Value& files, rapidjson::Document::AllocatorType& alloc)
	{
		DIR* d = opendir(path);
		if (d)
		{
			struct dirent* dir;
			while ((dir = readdir(d)) != NULL)
			{
				if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) continue;

				std::string dirPath(path);
				dirPath += dir->d_name;
				std::string thumb(dirPath);
				thumb += "/thumb.bjpg";
				FILE* check = fopen(thumb.c_str(), "r");
				if (check)
				{
					fclose(check);
					DIR* f;
					struct dirent* file;
					f = opendir(dirPath.c_str());
					if (f)
					{
						int count = 0;
						log(stdout, "Found file %s\n", dir->d_name);
						while ((file = readdir(f)) != NULL)
						{
							if (file->d_type == DT_REG && strstr(file->d_name, ".bjpg") != NULL)
							{
								count++;
							}
						}
						rapidjson::Value entry;
						entry.SetObject();
						entry.AddMember("name", rapidjson::Value(dir->d_name, alloc).Move(), alloc);
						entry.AddMember("pages", count - 1, alloc);
						entry.AddMember("thumb", readFile(thumb.c_str(), alloc).Move(), alloc);
						entry.AddMember("type", "file", alloc);
						files.PushBack(entry.Move(), alloc);
					}
					else
					{
						int err = errno;
						log(stderr, "Could not open directory %s: ERRNO %i\n", dirPath.c_str(), err);
					}
					closedir(f);
				}
				else if (dir->d_type == DT_DIR)
				{
					log(stdout, "Found directory %s\n", dir->d_name);

					rapidjson::Value entry;
					entry.SetObject();
					entry.AddMember("name", rapidjson::Value(dir->d_name, alloc).Move(), alloc);
					entry.AddMember("type", "directory", alloc);
					files.PushBack(entry.Move(), alloc);
				}
			}
		}
		else
		{
			int err = errno;
			log(stderr, "Could not open directory %s: ERRNO %i\n", path, err);
		}
		closedir(d);
	}
}