/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#include "ui_local.h"
#include "../qcommon/localization.h"

Event W_Scrollbar_Positioned
(
	"scrollbar_positioned",
	EV_DEFAULT,
	"i",
	"new_position",
	"Signaled when the user scrolls the view"
);

Event EV_Scrollbar_Scroll
(
	"_scrollbar_scroll",
	EV_DEFAULT,
	"ii",
	"scrollrate autorepeat",
	"scroll the scrollbar, at the specified rate.\n"
	"The autorepeat is used for autoscrolling with the mouse button held down"
);

CLASS_DECLARATION( UIWidget, UIVertScroll, NULL )
{
	{ &W_LeftMouseDown,			&UIVertScroll::MouseDown },
	{ &W_LeftMouseUp,			&UIVertScroll::MouseUp },
	{ &W_LeftMouseDragged,		&UIVertScroll::MouseDragged },
	{ &W_MouseEntered,			&UIVertScroll::MouseEnter },
	{ &W_MouseExited,			&UIVertScroll::MouseLeave },
	{ &EV_Scrollbar_Scroll,		&UIVertScroll::Scroll },
	{ NULL, NULL }
};

UIVertScroll::UIVertScroll()
	: m_numitems(0)
	, m_pageheight(0)
	, m_topitem(0)
	, m_marlett("marlett")
	, thumbRect(0, 0, 0, 0)
	, m_thumbcolor(0.15, 0.196, 0.278, 1.0)
	, m_solidbordercolor(0.075, 0.098, 0.139, 1.0)
	, m_pressed(VS_NONE)
	, m_frameinitted(false)
{
	m_background_color = UColor(0.15, 0.196, 0.278, 1.0);
	m_foreground_color = UHudColor;
}

int UIVertScroll::getItemFromHeight
	(
	float height
	)

{
	return (int)((height - 16.0 * uid.scaleRes[1]) * (float)this->m_numitems / (m_frame.size.height - 32.0 * uid.scaleRes[1]));
}

bool UIVertScroll::isEnoughItems
	(
	void
	)

{
	return m_numitems > m_pageheight;
}

void UIVertScroll::Draw
	(
	void
	)

{
	DrawBoxWithSolidBorder(
		getClientFrame(),
		getBackgroundColor(),
		m_solidbordercolor,
		1,
		3,
		m_local_alpha
	);

	DrawArrow(0.0, "5", m_pressed == VS_UP_ARROW);
	DrawArrow(m_frame.size.height - getVirtualScale()[1] * 16.0, "6", m_pressed == VS_DOWN_ARROW);

	if (m_numitems > m_pageheight) {
		DrawThumb();
	}
}

void UIVertScroll::DrawArrow
	(
	float top,
	const char *text,
	bool pressed
	)

{
	UIRect2D arrowRect;
	UColor innerColor;

	arrowRect.pos.x = 0.0;
	arrowRect.pos.y = top;
	arrowRect.size.width = m_frame.size.width;
	arrowRect.size.height = getVirtualScale()[1] * 16.0;

	innerColor = getBackgroundColor();
	m_marlett.setColor(getForegroundColor());

	if (pressed)
	{
		innerColor = m_border_color.light;

		if (m_background_color.r != 0.0 || m_background_color.g || m_background_color.b) {
			m_marlett.setColor(m_border_color.light);
		} else {
			m_marlett.setColor(UColor(0.15, 0.196, 0.278, 1.0));
		}
	}

	DrawBoxWithSolidBorder(arrowRect, innerColor, m_solidbordercolor, 1, 3, m_local_alpha);
	if (m_numitems > m_pageheight) {
		DrawMac3DBox(arrowRect, pressed, m_border_color, 1, m_local_alpha);
	}

	m_marlett.setAlpha(m_local_alpha);
	m_marlett.PrintJustified(
		arrowRect,
		m_iFontAlignmentHorizontal,
		m_iFontAlignmentVertical,
		Sys_LV_CL_ConvertString(text),
		getVirtualScale()
	);
}

void UIVertScroll::DrawThumb
	(
	void
	)

{
	UIRect2D inbarrect;
	float thumbHeight, thumbdiff;
	UColor thumbInside;

	thumbdiff = m_frame.size.height - getVirtualScale()[1] * 32.0;

	inbarrect.pos.x = 0.0;
	inbarrect.pos.y = getVirtualScale()[1] * 16.0;
	inbarrect.size.width = m_frame.size.width;
	inbarrect.size.height = m_frame.size.height - thumbdiff;

	thumbHeight = m_pageheight * thumbdiff;

	thumbRect.pos.x = 0.0;
	thumbRect.pos.y = m_topitem * thumbdiff / (float)m_numitems;
	thumbRect.size.width = m_frame.size.width;
	thumbRect.size.height = thumbHeight / (float)m_numitems;
	if (thumbRect.size.height < 6.0) {
		thumbRect.size.height = 6.0;
	}

	thumbInside = UColor(0.15, 0.196, 0.278, 1.0);

	if (thumbRect.pos.y + thumbRect.size.height - thumbdiff > 0.0) {
		thumbRect.pos.y -= thumbRect.pos.y + thumbRect.size.height - thumbdiff;
	}
	thumbRect.pos.y = thumbRect.pos.y + inbarrect.pos.y;

	DrawBoxWithSolidBorder(thumbRect, thumbInside, m_solidbordercolor, 1, 3, m_local_alpha);
	DrawMac3DBox(thumbRect, m_pressed == VS_THUMB, thumbInside, true, m_local_alpha);

	inbarrect.pos.x += 1.0;
	inbarrect.pos.y += 1.0;
	inbarrect.size.width -= 2.0;
	inbarrect.size.height -= 2.0;

	thumbRect.pos.x -= 1.0;
	thumbRect.pos.y -= 1.0;
	thumbRect.size.width -= 2.0;
	thumbRect.size.height -= 2.0;

	if (m_pressed == VS_PAGE_UP)
	{
		DrawBox(
			0.0,
			inbarrect.pos.y,
			m_frame.size.width,
			thumbRect.pos.y - inbarrect.pos.y,
			m_border_color.light,
			m_local_alpha
		);
	}
	else if (m_pressed == VS_PAGE_DOWN)
	{
		DrawBox(
			0.0,
			thumbRect.pos.y + thumbRect.size.height,
			m_frame.size.width,
			inbarrect.pos.y + inbarrect.size.height - (thumbRect.pos.y + thumbRect.size.height),
			m_border_color.light,
			m_local_alpha
		);
	}
}

void UIVertScroll::MouseDown
	(
	Event *ev
	)

{
	UIPoint2D p;
	int scrollrate;

	scrollrate = 0;

	p.x = ev->GetFloat(1) - m_screenframe.pos.x;
	p.y = ev->GetFloat(2) - m_screenframe.pos.y;
	m_pressed = VS_NONE;

	if (p.x < 0 || p.y < 0) {
		return;
	}

	if (p.x > m_frame.size.width || p.y > m_frame.size.height) {
		return;
	}

	if (m_numitems <= m_pageheight) {
		return;
	}

	if (p.y >= 16.0)
	{
		if (m_frame.size.height - 16.0 >= p.y)
		{
			if (thumbRect.pos.y > p.y)
			{
				m_pressed = VS_PAGE_UP;
				scrollrate = -m_pageheight;
			}
			else
			{
				if (thumbRect.pos.y + thumbRect.size.height > p.y)
				{
					m_pressed = VS_THUMB;
					m_dragThumbState.itemOffset = m_topitem - getItemFromHeight(p.y);
					m_dragThumbState.orgItem = m_topitem;
					uWinMan.setFirstResponder(this);
				}
				else
				{
					m_pressed = VS_PAGE_DOWN;
					scrollrate = m_pageheight;
				}
			}

			if (!scrollrate) {
				return;
			}
		}
		else
		{
			m_pressed = VS_DOWN_ARROW;
			scrollrate = 1;
		}
	}
	else
	{
		m_pressed = VS_UP_ARROW;
		scrollrate = -1;
	}

	Event* newev = new Event(EV_Scrollbar_Scroll);
	newev->AddInteger(scrollrate);
	newev->AddInteger(0);
	CancelEventsOfType(EV_Scrollbar_Scroll);
	PostEvent(newev, 0);

	uWinMan.setFirstResponder(this);
}

void UIVertScroll::MouseUp
	(
	Event *ev
	)

{
	CancelEventsOfType(EV_Scrollbar_Scroll);
	if (uWinMan.getFirstResponder() == this) {
		uWinMan.setFirstResponder(NULL);
	}

	m_pressed = VS_NONE;
}

void UIVertScroll::MouseDragged
	(
	Event *ev
	)

{
	UIPoint2D p;

	if (m_pressed != VS_THUMB) {
		return;
	}

	p.x = ev->GetFloat(1) - m_screenframe.pos.x;
	p.y = ev->GetFloat(2);

	if (p.x < -24.0 || p.x > m_frame.size.width + 24.0) {
		AttemptScrollTo(m_dragThumbState.orgItem);
	} else {
		AttemptScrollTo(m_dragThumbState.itemOffset + getItemFromHeight(p.y - m_screenframe.pos.y));
	}
}

void UIVertScroll::MouseEnter
	(
	Event *ev
	)

{
	// Fixed in OPM
	// Why should hovering over the scrollbar activate the control it's on?
	// This is more disorienting than useful, also no sane window manager
	// works like this. Simply clicking into it should be sufficient.
	//uWinMan.ActivateControl(this);
}

void UIVertScroll::MouseLeave
	(
	Event *ev
	)

{
}

void UIVertScroll::Scroll
	(
	Event *ev
	)

{
	if (AttemptScrollTo(m_topitem + ev->GetInteger(1)))
	{
		float delay = 0.2;
		if (ev->GetInteger(2)) {
			delay = 0.1;
		}

		Event *newev = new Event(EV_Scrollbar_Scroll);
		newev->AddInteger(ev->GetInteger(1));
		newev->AddInteger(0);
		PostEvent(newev, delay);
	}
}

bool UIVertScroll::AttemptScrollTo
	(
	int to
	)

{
	int besttopitem;

	if (to < 0) {
		to = 0;
	}

	besttopitem = m_numitems - m_pageheight;
	if (besttopitem < 0) {
		besttopitem = 0;
	}

	if (to > besttopitem) {
		to = besttopitem;
	}

	if (to == m_topitem) {
		return false;
	}

	m_topitem = to;

	Event ev(W_Scrollbar_Positioned);
	ev.AddInteger(m_topitem);
	SendSignal(ev);

	return true;
}

void UIVertScroll::setNumItems
	(
	int i
	)

{
	m_numitems = i;
}

void UIVertScroll::setPageHeight
	(
	int i
	)

{
	m_pageheight = i;
}

void UIVertScroll::setTopItem
	(
	int i
	)

{
	if (i >= 0) {
		m_topitem = i;
	} else {
		m_topitem = 0;
	}
}

int UIVertScroll::getTopItem
	(
	void
	)

{
	return m_topitem;
}

int UIVertScroll::getPageHeight
	(
	void
	)

{
	return m_pageheight;
}

int UIVertScroll::getNumItems
	(
	void
	)

{
	return m_numitems;
}

void UIVertScroll::setThumbColor
	(
	const UColor& thumb
	)

{
	m_thumbcolor = thumb;
}

void UIVertScroll::setSolidBorderColor
	(
	const UColor& col
	)

{
	m_solidbordercolor = col;
}

void UIVertScroll::InitFrameAlignRight
	(
	UIWidget *parent,
	float fWidthPadding,
	float fHeightPadding
	)

{
	UIRect2D frame, frameOut;

	frame = parent->getClientFrame();
	frameOut.pos.x = frame.pos.x + frame.size.width - (fWidthPadding + 16.0) * getVirtualScale()[0];
	frameOut.pos.y = fHeightPadding * getVirtualScale()[1];
	frameOut.size.width = getVirtualScale()[0] * 16.0;
	frameOut.size.height = frame.size.height - (fHeightPadding * 2) * getVirtualScale()[1];

	if (!m_frameinitted)
	{
		InitFrame(parent, frameOut, -1, "verdana-12");
		m_frameinitted = true;
	}
	else {
		setFrame(frameOut);
	}
}

void UIVertScroll::FrameInitialized()
{
	UIWidget::FrameInitialized();
}
