#include "SVGResource.h"
#include "../nanosvg/nanosvg.h"
#include "../nanosvg/nanosvgrast.h"
#include "../Log.h"
#include "../Util.h"

#define DPI 96

SVGResource::SVGResource(const std::string& path, bool tile) : TextureResource(path, tile), mSVGImage(NULL)
{
	mLastWidth = 0;
	mLastHeight = 0;
}

SVGResource::~SVGResource()
{
	deinitSVG();
}

void SVGResource::unload(std::shared_ptr<ResourceManager>& rm)
{
	deinitSVG();
	TextureResource::unload(rm);
}

void SVGResource::initFromMemory(const char* file, size_t length)
{
	deinit();
	deinitSVG();

	// nsvgParse excepts a modifiable, null-terminated string
	char* copy = (char*)malloc(length + 1);
	memcpy(copy, file, length);
	copy[length] = '\0';

	mSVGImage = nsvgParse(copy, "px", DPI);
	free(copy);

	if(!mSVGImage)
	{
		LOG(LogError) << "Error parsing SVG image.";
		return;
	}

	if(mLastWidth && mLastHeight)
		rasterizeAt(mLastWidth, mLastHeight);
	else
		rasterizeAt((size_t)round(mSVGImage->width), (size_t)round(mSVGImage->height));
}

void SVGResource::rasterizeAt(size_t width, size_t height)
{
	if(!mSVGImage || (width == 0 && height == 0))
		return;

	if(width == 0)
	{
		// auto scale width to keep aspect
		width = (size_t)round((height / mSVGImage->height) * mSVGImage->width);
	}else if(height == 0)
	{
		// auto scale height to keep aspect
		height = (size_t)round((width / mSVGImage->width) * mSVGImage->height);
	}

	if(width != (size_t)round(mSVGImage->width) && height != (size_t)round(mSVGImage->height))
	{
		mLastWidth = width;
		mLastHeight = height;
	}

	unsigned char* imagePx = (unsigned char*)malloc(width * height * 4);

	NSVGrasterizer* rast = nsvgCreateRasterizer();
	nsvgRasterize(rast, mSVGImage, 0, 0, height / mSVGImage->height, imagePx, width, height, width * 4);
	nsvgDeleteRasterizer(rast);

	// flip the pixels
	unsigned int temp;
	unsigned int* arr = (unsigned int*)imagePx;
	for(size_t y = 0; y < height / 2; y++)
	{
		for(size_t x = 0; x < width; x++)
		{
			temp = arr[x + (y * width)];
			arr[x + (y * width)] = arr[x + (height * width) - ((y + 1) * width)];
			arr[x + (height * width) - ((y + 1) * width)] = temp;
		}
	}

	initFromPixels(imagePx, width, height);
	free(imagePx);
}

Eigen::Vector2f SVGResource::getSourceImageSize() const
{
	if(mSVGImage)
		return Eigen::Vector2f(mSVGImage->width, mSVGImage->height);

	return Eigen::Vector2f::Zero();
}

void SVGResource::deinitSVG()
{
	if(mSVGImage)
		nsvgDelete(mSVGImage);

	mSVGImage = NULL;
}