#include <litehtml.h>
#include "win32_container.h"


litehtml::win32_container::win32_container()
{
	m_hClipRgn = NULL;
}

litehtml::win32_container::~win32_container()
{
	if(m_hClipRgn)
	{
		DeleteObject(m_hClipRgn);
	}
}

litehtml::uint_ptr litehtml::win32_container::create_font( const wchar_t* faceName, int size, int weight, font_style italic, unsigned int decoration )
{
	litehtml::string_vector fonts;
	tokenize(faceName, fonts, L",");
	litehtml::trim(fonts[0]);

	LOGFONT lf;
	ZeroMemory(&lf, sizeof(lf));
	wcscpy_s(lf.lfFaceName, LF_FACESIZE, fonts[0].c_str());

	lf.lfHeight			= -size;
	lf.lfWeight			= weight;
	lf.lfItalic			= (italic == litehtml::fontStyleItalic) ? TRUE : FALSE;
	lf.lfCharSet		= DEFAULT_CHARSET;
	lf.lfOutPrecision	= OUT_DEFAULT_PRECIS;
	lf.lfClipPrecision	= CLIP_DEFAULT_PRECIS;
	lf.lfQuality		= DEFAULT_QUALITY;
	lf.lfStrikeOut		= (decoration & litehtml::font_decoration_linethrough) ? TRUE : FALSE;
	lf.lfUnderline		= (decoration & litehtml::font_decoration_underline) ? TRUE : FALSE;
	HFONT hFont = CreateFontIndirect(&lf);

	return (uint_ptr) hFont;
}

void litehtml::win32_container::delete_font( uint_ptr hFont )
{
	DeleteObject((HFONT) hFont);
}

int litehtml::win32_container::line_height( uint_ptr hdc, uint_ptr hFont )
{
	HFONT oldFont = (HFONT) SelectObject((HDC) hdc, (HFONT) hFont);
	TEXTMETRIC tm;
	GetTextMetrics((HDC) hdc, &tm);
	SelectObject((HDC) hdc, oldFont);
	return (int) tm.tmHeight;
}

int litehtml::win32_container::text_width( uint_ptr hdc, const wchar_t* text, uint_ptr hFont )
{
	HFONT oldFont = (HFONT) SelectObject((HDC) hdc, (HFONT) hFont);

	SIZE sz = {0, 0};

	GetTextExtentPoint32((HDC) hdc, text, lstrlen(text), &sz);

	SelectObject((HDC) hdc, oldFont);

	return (int) sz.cx;
}

void litehtml::win32_container::draw_text( uint_ptr hdc, const wchar_t* text, uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos )
{
	apply_clip((HDC) hdc);

	HFONT oldFont = (HFONT) SelectObject((HDC) hdc, (HFONT) hFont);

	SetBkMode((HDC) hdc, TRANSPARENT);

	SetTextColor((HDC) hdc, RGB(color.red, color.green, color.blue));

	RECT rcText = { pos.left(), pos.top(), pos.right(), pos.bottom() };
	DrawText((HDC) hdc, text, -1, &rcText, DT_SINGLELINE | DT_NOPREFIX | DT_BOTTOM | DT_NOCLIP);

	SelectObject((HDC) hdc, oldFont);

	release_clip((HDC) hdc);
}

void litehtml::win32_container::fill_rect( uint_ptr hdc, const litehtml::position& pos, const litehtml::web_color color, const litehtml::css_border_radius& radius )
{
	apply_clip((HDC) hdc);
	fill_rect((HDC) hdc, pos.x, pos.y, pos.width, pos.height, color, radius);
	release_clip((HDC) hdc);
}

litehtml::uint_ptr litehtml::win32_container::get_temp_dc()
{
	return (litehtml::uint_ptr) GetDC(NULL);
}

void litehtml::win32_container::release_temp_dc( uint_ptr hdc )
{
	ReleaseDC(NULL, (HDC) hdc);
}

int litehtml::win32_container::pt_to_px( int pt )
{
	HDC dc = GetDC(NULL);
	int ret = MulDiv(pt, GetDeviceCaps(dc, LOGPIXELSY), 72);
	ReleaseDC(NULL, dc);
	return ret;
}

int litehtml::win32_container::get_text_base_line( uint_ptr hdc, uint_ptr hFont )
{
	HDC dc = (HDC) hdc;
	if(!dc)
	{
		dc = GetDC(NULL);
	}
	HFONT oldFont = (HFONT) SelectObject(dc, (HFONT) hFont);
	TEXTMETRIC tm;
	GetTextMetrics(dc, &tm);
	SelectObject(dc, oldFont);
	if(!hdc)
	{
		ReleaseDC(NULL, dc);
	}
	return (int) tm.tmDescent;
}

void litehtml::win32_container::draw_list_marker( uint_ptr hdc, list_style_type marker_type, int x, int y, int height, const web_color& color )
{
	apply_clip((HDC) hdc);

	int top_margin = height / 3;

	int draw_x		= x;
	int draw_y		= y + top_margin;
	int draw_width	= height - top_margin * 2;
	int draw_height	= height - top_margin * 2;

	switch(marker_type)
	{
	case list_style_type_circle:
		{
			draw_ellipse((HDC) hdc, draw_x, draw_y, draw_width, draw_height, color, 1);
		}
		break;
	case list_style_type_disc:
		{
			fill_ellipse((HDC) hdc, draw_x, draw_y, draw_width, draw_height, color);
		}
		break;
	case list_style_type_square:
		{
			fill_rect((HDC) hdc, draw_x, draw_y, draw_width, draw_height, color, css_border_radius());
		}
		break;
	}
	release_clip((HDC) hdc);
}

void litehtml::win32_container::load_image( const wchar_t* src, const wchar_t* baseurl, bool redraw_on_ready )
{
	std::wstring url;
	make_url(src, baseurl, url);
	if(m_images.find(url.c_str()) == m_images.end())
	{
		uint_ptr img = get_image(url.c_str());
		if(img)
		{ 
			m_images[url.c_str()] = img;
		}
	}
}

void litehtml::win32_container::get_image_size( const wchar_t* src, const wchar_t* baseurl, litehtml::size& sz )
{
	std::wstring url;
	make_url(src, baseurl, url);

	images_map::iterator img = m_images.find(url.c_str());
	if(img != m_images.end())
	{
		get_img_size(img->second, sz);
	}
}

void litehtml::win32_container::draw_image( uint_ptr hdc, const wchar_t* src, const wchar_t* baseurl, const litehtml::position& pos )
{
	apply_clip((HDC) hdc);

	std::wstring url;
	make_url(src, baseurl, url);
	images_map::iterator img = m_images.find(url.c_str());
	if(img != m_images.end())
	{
		draw_img((HDC) hdc, img->second, pos);
	}

	release_clip((HDC) hdc);
}

void litehtml::win32_container::clear_images()
{
	for(images_map::iterator i = m_images.begin(); i != m_images.end(); i++)
	{
		if(i->second)
		{
			free_image(i->second);
		}
	}
	m_images.clear();
}

int litehtml::win32_container::get_default_font_size() const
{
	return 16;
}

void litehtml::win32_container::draw_background( uint_ptr hdc, const wchar_t* image, const wchar_t* baseurl, const litehtml::position& draw_pos, const litehtml::css_position& bg_pos, litehtml::background_repeat repeat, litehtml::background_attachment attachment )
{
	apply_clip((HDC) hdc);

	std::wstring url;
	make_url(image, baseurl, url);

	images_map::iterator img = m_images.find(url.c_str());
	if(img != m_images.end())
	{
		litehtml::size img_sz;
		get_img_size(img->second, img_sz);

		litehtml::position pos = draw_pos;

		if(bg_pos.x.units() != css_units_percentage)
		{
			pos.x += (int) bg_pos.x.val();
		} else
		{
			pos.x += (int) ((float) (draw_pos.width - img_sz.width) * bg_pos.x.val() / 100.0);
		}

		if(bg_pos.y.units() != css_units_percentage)
		{
			pos.y += (int) bg_pos.y.val();
		} else
		{
			pos.y += (int) ( (float) (draw_pos.height - img_sz.height) * bg_pos.y.val() / 100.0);
		}

		draw_img_bg((HDC) hdc, img->second, draw_pos, pos, repeat, attachment);
	}

	release_clip((HDC) hdc);
}

wchar_t litehtml::win32_container::toupper( const wchar_t c )
{
	return (wchar_t) CharUpper((LPWSTR) c);
}

wchar_t litehtml::win32_container::tolower( const wchar_t c )
{
	return (wchar_t) CharLower((LPWSTR) c);
}

void litehtml::win32_container::set_clip( const litehtml::position& pos, bool valid_x, bool valid_y )
{
	litehtml::position clip_pos = pos;
	litehtml::position client_pos;
	get_client_rect(client_pos);
	if(!valid_x)
	{
		clip_pos.x		= client_pos.x;
		clip_pos.width	= client_pos.width;
	}
	if(!valid_y)
	{
		clip_pos.y		= client_pos.y;
		clip_pos.height	= client_pos.height;
	}
	m_clips.push_back(clip_pos);
}

void litehtml::win32_container::del_clip()
{
	if(!m_clips.empty())
	{
		m_clips.pop_back();
		if(!m_clips.empty())
		{
			litehtml::position clip_pos = m_clips.back();
		}
	}
}

void litehtml::win32_container::apply_clip(HDC hdc)
{
	if(m_hClipRgn)
	{
		DeleteObject(m_hClipRgn);
		m_hClipRgn = NULL;
	}

	if(!m_clips.empty())
	{
		POINT ptView = {0, 0};
		GetWindowOrgEx(hdc, &ptView);

		litehtml::position clip_pos = m_clips.back();
		m_hClipRgn = CreateRectRgn(clip_pos.left() - ptView.x, clip_pos.top() - ptView.y, clip_pos.right() - ptView.x, clip_pos.bottom() - ptView.y);
		SelectClipRgn(hdc, m_hClipRgn);
	}
}

void litehtml::win32_container::release_clip(HDC hdc)
{
	SelectClipRgn(hdc, NULL);

	if(m_hClipRgn)
	{
		DeleteObject(m_hClipRgn);
		m_hClipRgn = NULL;
	}
}
