/*
===========================================================================
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();
}
