// This file is part of VSTGUI. It is subject to the license terms 
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE

#include "cdrawmethods.h"
#include "cbitmap.h"
#include "cstring.h"
#include "cdrawcontext.h"
#include "platform/iplatformfont.h"

namespace VSTGUI {

namespace CDrawMethods {

//------------------------------------------------------------------------
UTF8String createTruncatedText (TextTruncateMode mode, const UTF8String& text, CFontRef font,
                                CCoord maxWidth, const CPoint& textInset, uint32_t flags)
{
	if (mode == kTextTruncateNone || text.length () < 2)
		return text;
	auto painter = font->getPlatformFont () ? font->getPlatformFont ()->getPainter () : nullptr;
	if (!painter)
		return text;
	CCoord width = painter->getStringWidth (nullptr, text.getPlatformString (), true);
	width += textInset.x * 2;
	if (width > maxWidth)
	{
		std::string truncatedText;
		UTF8String result;
		auto left = text.begin ();
		auto right = text.end ();
		size_t distance = std::distance (left, right) - 1;
		int32_t dir = 1;
		while (distance > 0 && width != maxWidth)
		{
			distance = (distance / 2);
			while ((dir > 0 ? (width > maxWidth) : (width < maxWidth)) && distance > 0)
			{
				if (mode == kTextTruncateHead)
				{
					if (dir > 0)
					{
						for (auto i = distance; i > 0 && left != right; --i)
							++left;
					}
					else
					{
						for (auto i = distance; i > 0 && left != text.begin (); --i)
							--left;
					}
					truncatedText = "..";
				}
				else if (mode == kTextTruncateTail)
				{
					if (dir > 0)
					{
						for (auto i = distance; i > 0 && left != right; --i)
							--right;
					}
					else
					{
						for (auto i = distance; i > 0 && right != text.end (); --i)
							++right;
					}
					truncatedText = "";
				}

				truncatedText += {left.base (), right.base ()};

				if (mode == kTextTruncateTail)
					truncatedText += "..";

				result = truncatedText;
				width = painter->getStringWidth (nullptr, result.getPlatformString (), true);
				width += textInset.x * 2;
				if (left == right)
					break;
			}
			dir *= -1;
		}
		if (left == right && flags & kReturnEmptyIfTruncationIsPlaceholderOnly)
			result = "";
		return result;
	}
	return text;
}

//------------------------------------------------------------------------
void drawIconAndText (CDrawContext* context, CBitmap* iconToDraw, IconPosition iconPosition,
                      CHoriTxtAlign textAlignment, CCoord textIconMargin, CRect drawRect,
                      const UTF8String& title, CFontRef font, CColor textColor,
                      TextTruncateMode textTruncateMode)
{
	if (iconToDraw)
	{
		CRect iconRect (0, 0, iconToDraw->getWidth (), iconToDraw->getHeight ());
		iconRect.offset (drawRect.left, drawRect.top);
		switch (iconPosition)
		{
			case kIconLeft:
			{
				iconRect.offset (textIconMargin,
				                 drawRect.getHeight () / 2. - iconRect.getHeight () / 2.);
				drawRect.left = iconRect.right;
				drawRect.right -= textIconMargin;
				if (textAlignment == kLeftText)
					drawRect.left += textIconMargin;
				break;
			}
			case kIconRight:
			{
				iconRect.offset (drawRect.getWidth () - (textIconMargin + iconRect.getWidth ()),
				                 drawRect.getHeight () / 2. - iconRect.getHeight () / 2.);
				drawRect.right = iconRect.left;
				drawRect.left += textIconMargin;
				if (textAlignment == kRightText)
					drawRect.right -= textIconMargin;
				break;
			}
			case kIconCenterAbove:
			{
				iconRect.offset (drawRect.getWidth () / 2. - iconRect.getWidth () / 2., 0);
				if (title.empty ())
					iconRect.offset (0, drawRect.getHeight () / 2. - iconRect.getHeight () / 2.);
				else
				{
					iconRect.offset (0, drawRect.getHeight () / 2. -
					                        (iconRect.getHeight () / 2. +
					                         (textIconMargin + font->getSize ()) / 2.));
					drawRect.top = iconRect.bottom + textIconMargin;
					drawRect.setHeight (font->getSize ());
					if (textAlignment == kLeftText)
						drawRect.left += textIconMargin;
					else if (textAlignment == kRightText)
						drawRect.right -= textIconMargin;
				}
				break;
			}
			case kIconCenterBelow:
			{
				iconRect.offset (drawRect.getWidth () / 2. - iconRect.getWidth () / 2., 0);
				if (title.empty ())
					iconRect.offset (0, drawRect.getHeight () / 2. - iconRect.getHeight () / 2.);
				else
				{
					iconRect.offset (0, drawRect.getHeight () / 2. - (iconRect.getHeight () / 2.) +
					                        (textIconMargin + font->getSize ()) / 2.);
					drawRect.top = iconRect.top - (textIconMargin + font->getSize ());
					drawRect.setHeight (font->getSize ());
					if (textAlignment == kLeftText)
						drawRect.left += textIconMargin;
					else if (textAlignment == kRightText)
						drawRect.right -= textIconMargin;
				}
				break;
			}
		}
		context->drawBitmap (iconToDraw, iconRect);
	}
	else
	{
		if (textAlignment == kLeftText)
			drawRect.left += textIconMargin;
		else if (textAlignment == kRightText)
			drawRect.right -= textIconMargin;
	}
	if (!title.empty ())
	{
		context->setFont (font);
		context->setFontColor (textColor);
		if (textTruncateMode != kTextTruncateNone)
		{
			UTF8String truncatedText =
			    createTruncatedText (textTruncateMode, title, font, drawRect.getWidth (),
			                         CPoint (0, 0), kReturnEmptyIfTruncationIsPlaceholderOnly);
			context->drawString (truncatedText.getPlatformString (), drawRect, textAlignment);
		}
		else
			context->drawString (title.getPlatformString (), drawRect, textAlignment);
	}
}
}
} // namespaces
