#include "Draw.h"

namespace Upp {

// Upscale2x is based on xBR filter idea by Hyllian, google search on 'xBR filter'
// should eventually lead you to a forum topic where he made the algorithm public:
// http://board.byuu.org/viewtopic.php?f=10&t=2248
 
namespace Upscale2x_helper {
	int d(RGBA c1, RGBA c2)
	{
		int r = abs(c1.r - c2.r);
		int g = abs(c1.g - c2.g);
		int b = abs(c1.b - c2.b);
		return 48 * (r *  299 + g *  587 + b *  114)
		     +  7 * (r * -169 + g * -331 + b *  500)
		     +  6 * (r *  500 + g * -419 + b *  -81);
	}
};

Image Upscale2x_(const Image& src)
{
	using namespace Upscale2x_helper;
	Size isz = src.GetSize();
	ImageBuffer dst;
	dst.Create(2 * isz);
	for(int y = 0; y < isz.cy; y++)
		for(int x = 0; x < isz.cx; x++) {
	        static const int8 cm[] = {
			//  -2  -1   0  +1  +2
				-1,  0,  1,  2, -1, // -2
				17, 19,  3,  4,  5, // -1
				16, 18, -1,  8,  6, //  0
				15, 14, 13,  9,  7, // +1
				-1, 12, 11, 10, -1, // +2
	        };
	
	        RGBA pp[40];
	        const int8 *q = cm;
			for(int dy = -2; dy <= 2; dy++)
				for(int dx = -2; dx <= 2; dx++) {
					if(*q >= 0) {
						int xx = x + dx;
						int yy = y + dy;
						pp[*q] = pp[*q + 20] = src[clamp(yy, 0, isz.cy - 1)][clamp(xx, 0, isz.cx - 1)];
					}
					q++;
				}
	
			RGBA c = src[y][x];
			RGBA *p = pp;
			
			for(int rot = 0; rot < 4; rot++) {
				RGBA t = c;
				if(d(c, p[14]) + d(c, p[4]) + d(p[19], p[16]) + d(p[19], p[1]) + 4 * d(p[18], p[3])
				   < d(p[18], p[13]) + d(p[18], p[17]) + d(p[3], p[8]) + d(p[3], p[0]) + 4 * d(c, p[19])) {
					RGBA nc = d(c, p[18]) <= d(c, p[3]) ? p[18] : p[3];
					t.r = (nc.r + c.r) >> 1;
					t.g = (nc.g + c.g) >> 1;
					t.b = (nc.b + c.b) >> 1;
				}
				// 0 1
				// 3 2
				dst[2 * y + (rot >= 2)][2 * x + (rot == 1 || rot == 2)] = t;
				p += 5;
			}
		}
	return Image(dst);
}

Image Upscale2x(const Image& src)
{
	if(IsNull(src))
		return src;
	Size s2 = src.Get2ndSpot();
	Image s;
	if(s2.cx > 0 || s2.cy > 0)  // When 2nd spot is defined, it is likely Chameleon rescaling item (e.g. button)
		s = Magnify(src, 2, 2); // in that case, filtering by smart rescale methods could lead to artifacts
	else {
		Size isz = src.GetSize();
		s = RecreateAlpha(Upscale2x_(GetOver(CreateImage(isz, White()), src)),
		                  Upscale2x_(GetOver(CreateImage(isz, Black()), src)));

		struct SFilter : ImageFilter9 { // Improve contours
			virtual RGBA operator()(const RGBA **mx) {
				RGBA s = mx[1][1];
				dword l = mx[0][1].a;
				dword r = mx[2][1].a;
				dword t = mx[1][0].a;
				dword b = mx[1][2].a;
				int l1 = 110;
				int l2 = 230;
				return l * r * t * b != 0 || s.a > l1 || mx[0][1].a > l2 || mx[2][1].a > l2 || mx[1][0].a > l2 || mx[1][2].a > l2 ? s
				       : RGBAZero();
			}
		} ef;
		s = Filter(s, ef);
	}
	ImageBuffer h(s);
	h.SetHotSpot(src.GetHotSpot() * 2);
	h.Set2ndSpot(s2 * 2);
	return Image(h);
}

Image Downscale2x(const Image& src)
{
	if(IsNull(src))
		return src;
	Size s2 = src.Get2ndSpot(); // see above...
	Image m = RescaleFilter(src, src.GetSize() / 2, s2.cx > 0 || s2.cy > 0 ? FILTER_BILINEAR : FILTER_LANCZOS3);
	ImageBuffer h(m);
	h.SetHotSpot(s2 / 2);
	h.Set2ndSpot(src.Get2ndSpot() / 2);
	return Image(h);
}

Image Downscale6x(const Image& src)
{
	if(IsNull(src))
		return src;
	Size s2 = src.Get2ndSpot(); // see above...
	Image m = DownSample2x(DownSample3x(src));
	ImageBuffer h(m);
	h.SetHotSpot(s2 / 6);
	h.Set2ndSpot(src.Get2ndSpot() / 6);
	return Image(h);
}

static bool sUHDMode;

void SetUHDMode(bool b)
{
	Iml::ResetAll();
	sUHDMode = b;
}

bool IsUHDMode()
{
	return sUHDMode;
}

void SyncUHDMode()
{
	bool uhd = GetStdFontCy() > 24;
	if(uhd != IsUHDMode())
		SetUHDMode(uhd);
}

Image DPI(const Image& img, int expected)
{
	if(img.GetSize().cy <= expected && IsUHDMode())
		return AdjustImage(img, Upscale2x);
	return img;
}

};