/*
 * This file is part of VoidArchiveTool.
 *
 * Copyright (C) 2025 Yanczi
 *
 * Void Archive Toolis free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "CompressionManager.h"

CompressionManager::CompressionManager()
	:cctx(ZSTD_createCCtx())
	,dctx(ZSTD_createDCtx())
{
	// Tu ustawienia pod kompresję
	const int level = COMPRESSION_LEVEL;

	// Ustawienia frameless
	size_t rc = 0;

	// Wyłącza ramkę i przestawia strumień na czyste bloki
	rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_format, ZSTD_f_zstd1_magicless);

	// Wyłącza sumę kontrolną na poziomie ramki
	rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0);

	// Wyłącza zapisywanie „content size” w nagłówku ramki
	rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, 0);

	// Wyłącza zapisywanie identyfikatora słownika
	rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, 0);

	// Ustawia poziom kompresji
	rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, level);

	if (ZSTD_isError(rc)) {
		std::cerr << "ZSTD_CCtx_setParameter error" << std::endl;
		ZSTD_freeCCtx(cctx);
	}

	/*====Tutaj Dekompresja=============================================================*/

	size_t r = 0;

	// Przestawia dekompresję na czyste bloki bez nagłówka
	r |= ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless);
	if (ZSTD_isError(r))
	{
		std::cerr << "ZSTD_DCtx_setParameter error" << std::endl;
		ZSTD_freeDCtx(dctx);
	}
}

CompressionManager::~CompressionManager()
{
	ZSTD_freeCCtx(cctx);
	ZSTD_freeDCtx(dctx);
}

//-----------------------------------------------------------------------------
//	Kompresja ZSTD frameless
//-----------------------------------------------------------------------------
std::vector<char> CompressionManager::compress(const std::vector<char>& input)
{
	// Obsługa pustego chunku: zwracamy pusty wynik (0 bajtów).
	if (input.empty()) return {};

	const size_t srcSize = input.size();

	// Szacowanie rozmiaru skompresowanego vectoru
	const size_t maxDst = ZSTD_compressBound(srcSize);

	std::vector<char> out(maxDst);

	// Faktyczna kompresja
	size_t written = ZSTD_compress2(cctx, out.data(), maxDst,
		input.data(), srcSize);

	if (ZSTD_isError(written)) {
		std::cerr << "ZSTD_compress error: " << ZSTD_getErrorName(written) << std::endl;
		return {};
	}

	out.resize(written);
	return out;
}

//-----------------------------------------------------------------------------
//	Dekompresja ZSTD
//-----------------------------------------------------------------------------
std::vector<char> CompressionManager::decompress(const std::vector<char>& input, const size_t& expected)
{
	std::vector<char> output(expected);

	size_t dsize = ZSTD_decompressDCtx(dctx, output.data(), expected, input.data(), input.size());

	if (ZSTD_isError(dsize)) {
		std::cerr << "ZSTD_decompressDCtx error: " << ZSTD_getErrorName(dsize) << "\n";
		return {};
	}

	return output;
}