#include "PLRadioButtonWidget.h"
#include "PLStandardColors.h"
#include "FontFamily.h"
#include "PLTimeTaggedVOSEvent.h"

#include <algorithm>

namespace PortabilityLayer
{
	RadioButtonWidget::RadioButtonWidget(const WidgetBasicState &state)
		: WidgetSpec<RadioButtonWidget>(state)
		, m_text(state.m_text)
		, m_haveMouseDown(false)
	{
	}

	RadioButtonWidget::~RadioButtonWidget()
	{
	}

	bool RadioButtonWidget::Init(const WidgetBasicState &state)
	{
		(void)state;

		return true;
	}

	void RadioButtonWidget::DrawControl(DrawSurface *surface)
	{
		if (!m_rect.IsValid())
			return;

		surface->SetForeColor(StdColors::White());
		surface->FillRect(m_rect);

		uint16_t radioFrameSize = std::min<uint16_t>(12, std::min(m_rect.Width(), m_rect.Height()));
		int16_t top = (m_rect.top + m_rect.bottom - static_cast<int16_t>(radioFrameSize)) / 2;

		surface->SetForeColor(StdColors::Black());
		const Rect radioRect = Rect::Create(top, m_rect.left, top + static_cast<int16_t>(radioFrameSize), m_rect.left + static_cast<int16_t>(radioFrameSize));
		surface->FillEllipse(radioRect);

		surface->SetForeColor(StdColors::White());
		surface->FillEllipse(radioRect.Inset(1, 1));

		if (m_state)
		{
			surface->SetForeColor(StdColors::Black());
			surface->FillEllipse(radioRect.Inset(3, 3));
		}

		surface->SetForeColor(StdColors::Black());
		surface->SetSystemFont(12, FontFamilyFlag_Bold);
		int32_t textV = (m_rect.top + m_rect.bottom + surface->MeasureFontAscender()) / 2;
		surface->DrawString(Point::Create(m_rect.left + radioFrameSize + 2, textV), m_text.ToShortStr(), true);
	}

	void RadioButtonWidget::SetString(const PLPasStr &str)
	{
		m_text = PascalStr<255>(str);
	}

	PLPasStr RadioButtonWidget::GetString() const
	{
		return m_text.ToShortStr();
	}

	void RadioButtonWidget::OnStateChanged()
	{
		if (m_window)
			DrawControl(&m_window->m_surface);
	}

	WidgetHandleState_t RadioButtonWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
	{
		if (!m_visible || !m_enabled)
			return WidgetHandleStates::kIgnored;

		if (m_haveMouseDown)
		{
			if (evt.IsLMouseUpEvent())
			{
				m_haveMouseDown = false;

				const Point pt = m_window->MouseToLocal(evt.m_vosEvent.m_event.m_mouseInputEvent);
				if (m_rect.Contains(pt))
					return WidgetHandleStates::kActivated;
				else
					return WidgetHandleStates::kIgnored;
			}

			return WidgetHandleStates::kCaptured;
		}
		else
		{
			if (evt.IsLMouseDownEvent())
			{
				const Point pt = m_window->MouseToLocal(evt.m_vosEvent.m_event.m_mouseInputEvent);

				if (m_rect.Contains(pt))
				{
					m_haveMouseDown = true;
					return WidgetHandleStates::kCaptured;
				}
				else
					return WidgetHandleStates::kIgnored;
			}
		}

		return WidgetHandleStates::kIgnored;
	}
}
