#include "image.h"
#include "math_util.h"

void image::draw(image const* image, vec2i pos) {
	draw(image, pos, image->bounds());
}

void image::draw(image const* image, vec2i pos, recti src_rect) {
	src_rect = recti::intersection(src_rect, image->bounds());
	auto crop = recti::intersection(bounds(), recti(pos, image->bounds().size));
	crop = recti::intersection(crop, recti(crop.pos, src_rect.size));
	auto src_off = crop.pos - pos + src_rect.pos;
	auto start = crop.pos;
	auto end = crop.pos2();
	if(image->_alpha) {
		for(int y = start.y; y <= end.y; ++y) {
			for(int x = start.x; x <= end.x; ++x) {
				auto color = image->_data[
					x - start.x + src_off.x + (y - start.y + src_off.y) * image->_bounds.size.x
				];
				if(color & 0xff000000)
					_data[x + y * _bounds.size.x] = color;
			}
		}
	} else {
		for(int y = start.y; y <= end.y; ++y) {
			std::memcpy(
				_data + (y * _bounds.size.x),
				image->_data - start.x + src_off.x + (y-start.y + src_off.y) * image->_bounds.size.x,
				(end.x - start.x + 1)*4
			);
		}
	}
}

void image::draw(image const* image, vec2i pos, color color) {
	draw(image, pos, color, image->bounds());
}

void image::draw(image const* image, vec2i pos, color color, recti src_rect) {
	color |= 0xff000000;
	src_rect = recti::intersection(src_rect, image->bounds());
	auto crop = recti::intersection(bounds(), recti(pos, image->bounds().size));
	crop = recti::intersection(crop, recti(crop.pos, src_rect.size));
	auto src_off = crop.pos - pos + src_rect.pos;
	auto start = crop.pos;
	auto end = crop.pos2();
	for(int y = start.y; y <= end.y; ++y) {
		for(int x = start.x; x <= end.x; ++x) {
			auto color_src = image->_data[
				x - start.x + src_off.x + (y - start.y + src_off.y) * image->_bounds.size.x
			];
			if(color_src & 0xff000000)
				_data[x + y * _bounds.size.x] = color;
		}
	}
}

/*
void image::draw_upscaled(image const* image) {
	if(image->bounds() == bounds()) {
		std::memcpy(_data, image->_data, bounds().size.size() * 4);
		return;
	}

	auto ratio = _bounds.size / image->_bounds.size;
	auto scale = std::min(ratio.x, ratio.y);
	switch(scale) {
	case 3:
#pragma omp parallel for
		for(int y = 0; y < image->_bounds.size.y; ++y) {
			for(int x = 0; x < image->_bounds.size.x; ++x) {
				auto color = image->_data[x + y * image->_bounds.size.x];
				auto color2 = (color & 0xfefefe) >> 1;
				_data[x * 3 + 0 + (y * 3 + 0) * _bounds.size.x] = color;
				_data[x * 3 + 1 + (y * 3 + 0) * _bounds.size.x] = color;
				_data[x * 3 + 2 + (y * 3 + 0) * _bounds.size.x] = color2;
				_data[x * 3 + 0 + (y * 3 + 1) * _bounds.size.x] = color;
				_data[x * 3 + 1 + (y * 3 + 1) * _bounds.size.x] = color;
				_data[x * 3 + 2 + (y * 3 + 1) * _bounds.size.x] = color2;
				_data[x * 3 + 0 + (y * 3 + 2) * _bounds.size.x] = color2;
				_data[x * 3 + 1 + (y * 3 + 2) * _bounds.size.x] = color2;
				_data[x * 3 + 2 + (y * 3 + 2) * _bounds.size.x] = color2;
			}
		}
		break;
	default:
#pragma omp parallel for
		for(int y = 0; y < image->_bounds.size.y; ++y) {
			for(int x = 0; x < image->_bounds.size.x; ++x) {
				auto color = image->_data[x + y * image->_bounds.size.x];
				for(int sy = 0; sy < scale; ++sy) {
					for(int sx = 0; sx < scale; ++sx) {
						_data[(x * scale + sx) + (y * scale + sy) * _bounds.size.x] = color;
					}
				}
			}
		}
	}
}
*/

void image::draw_rot(image const* image, vec2i pos, double rot) {
	draw_rot(image, pos, image->bounds(), rot);
}

void image::draw_rot(image const* image, vec2i pos, recti src_rect, double rot) {
	src_rect = recti::intersection(src_rect, image->bounds());
	//auto crop = recti::intersection(bounds(), recti(pos, image->bounds().size));
	//crop = recti::intersection(crop, recti(crop.pos, src_rect.size));
	//todo: crop to screen...
	//todo: fmod the rot?
	//rot = rot/2;
	//if(rot >= 0.5)
	//	rot = 0.5 - rot;
	rot /= 2;
	if(rot >= 0.25)
		rot = 0.25 - (rot - 0.25);
	rot -= 0.125;
	auto crop = recti::intersection(recti(pos, src_rect.size), recti(pos, image->bounds().size));
	auto src_off = crop.pos - pos + src_rect.pos;
	auto start = crop.pos;
	auto end = crop.pos2();

	auto xshear = -std::tan(rot * TAU / 2.0) *crop.size.x;
	auto yshear = std::sin(rot * TAU) * crop.size.y;
	//auto xshear = (std::cos(rot * TAU) - 1) / sin(rot * TAU);

	std::vector<int> xshears;
	for(int y = start.y; y <= end.y; ++y) {
		auto yf = static_cast<double>(y - crop.pos.y) / crop.size.y * 2 - 0.5;
		xshears.push_back(static_cast<int>(xshear * yf));
	}

	for(int y = 0; y <= end.y - start.y; ++y) {
		auto yf = static_cast<double>(y) / crop.size.y * 2 - 1;
		for(int x = 0; x <= end.x - start.x; ++x) {
			double xf, yf;
			int nx, ny;
			nx = x;
			ny = y;

			yf = (static_cast<double>(ny) / crop.size.y * 1 - 0.5);
			nx = nx + yf * xshear;
			//int nxt = x;

			xf = (static_cast<double>(nx) / crop.size.x * 1 - 0.5);
			ny = ny + xf * yshear;

			yf = (static_cast<double>(ny) / crop.size.y * 1 - 0.5);
			nx = nx + yf * xshear;


			auto color = image->_data[
				x + src_off.x + (y + src_off.y) * image->_bounds.size.x
			];
			if(color & 0xff000000)
				_data[nx + start.x + (ny+start.y) * _bounds.size.x] = color;
		}
	}
}
