#include "Scroll.h"

#include "Image.h"
#include "MouseEvent.h"

using namespace Framework;

// Contents of the VScrollBar class from Scroll.h
// Constructor
ScrollBar::ScrollBar()
    : ReferenceCounter(),
      data(new ScrollData()),
      knopfdruck(0),
      color(0xFF808080),
      bgColor(0xFF000000),
      bg(0),
      clickScroll(10),
      mx(-1),
      my(-1),
      mp(0),
      rend(0)
{}

// Destructor
ScrollBar::~ScrollBar()
{
    delete data;
}

// non-constant
void ScrollBar::setColor(int fc)
{
    color = fc;
    rend = 1;
}

void ScrollBar::setBgColor(int fc, bool bgF)
{
    bgColor = fc;
    bg = bgF;
    rend = 1;
}

void ScrollBar::update(int maxGr, int anzeigeGr)
{
    if (data->max != maxGr || data->anzeige != anzeigeGr)
    {
        data->max = maxGr, data->anzeige = anzeigeGr;
        rend = 1;
    }
    if (data->scrollPos > data->max - data->anzeige
        && data->max - data->anzeige >= 0)
    {
        data->scrollPos = data->max - data->anzeige;
        rend = 1;
    }
    if (data->scrollPos < 0)
    {
        data->scrollPos = 0;
        rend = 1;
    }
}

void ScrollBar::setClickScroll(int ks)
{
    clickScroll = ks;
    rend = 1;
}

void ScrollBar::scroll(int height)
{
    data->scrollPos = height;
    if (data->scrollPos > data->max - data->anzeige)
        data->scrollPos = data->max - data->anzeige;
    if (data->scrollPos < 0) data->scrollPos = 0;
    rend = 1;
}

bool ScrollBar::getNeedRender()
{
    if (knopfdruck == 1)
    {
        int tmp = data->scrollPos;
        data->scrollPos -= clickScroll;
        if (data->scrollPos > data->max - data->anzeige)
            data->scrollPos = data->max - data->anzeige;
        if (data->scrollPos < 0) data->scrollPos = 0;
        if (tmp != data->scrollPos) rend = 1;
    }
    if (knopfdruck == 2)
    {
        int tmp = data->scrollPos;
        data->scrollPos += clickScroll;
        if (data->scrollPos > data->max - data->anzeige)
            data->scrollPos = data->max - data->anzeige;
        if (data->scrollPos < 0) data->scrollPos = 0;
        if (tmp != data->scrollPos) rend = 1;
    }
    bool ret = rend;
    rend = 0;
    return ret;
}

// const
ScrollData* ScrollBar::getScrollData() const
{
    return data;
}

int ScrollBar::getClickScroll() const
{
    return clickScroll;
}

int ScrollBar::getColor() const
{
    return color;
}

int ScrollBar::getBgColor() const
{
    return bg ? bgColor : 0;
}

int ScrollBar::getScroll() const
{
    return data->scrollPos;
}

// Contents of the VScrollBar class
VScrollBar::VScrollBar()
    : ScrollBar()
{}

// Destructor
VScrollBar::~VScrollBar() {}

bool VScrollBar::doMouseMessage(int x, int y, int br, int hi, MouseEvent& me)
{
    if (me.id == ME_Leaves)
    {
        mp = 0;
        mx = -1;
        my = -1;
    }
    bool ret = me.mx >= x && me.mx <= x + br && me.my >= y && me.my <= y + hi;
    knopfdruck = 0;
    if (me.processed)
    {
        mx = -1, my = -1;
        mp = 0;
        return ret;
    }
    if (me.id == ME_UScroll)
    {
        data->scrollPos -= clickScroll;
        if (data->scrollPos < 0) data->scrollPos = 0;
        rend = 1;
        return ret;
    }
    if (me.id == ME_DScroll)
    {
        data->scrollPos += clickScroll;
        if (data->scrollPos > data->max - data->anzeige)
            data->scrollPos = data->max - data->anzeige;
        if (data->scrollPos < 0) data->scrollPos = 0;
        rend = 1;
        return ret;
    }
    if (ret)
        mx = me.mx - x, my = me.my - y;
    else
        mx = -1, my = -1;
    if (me.id == ME_PLeft) mp = 1;
    if (me.id == ME_RLeft) mp = 0;
    if (mp)
    {
        if (mx >= 0 && my >= 0)
        {
            if (my < br)
            {
                knopfdruck = 1;
                data->scrollPos -= clickScroll;
            }
            else if (my > hi - br)
            {
                knopfdruck = 2;
                data->scrollPos += clickScroll;
            }
            else
                data->scrollPos
                    = (int)((data->max / (hi - 2.0 * br)) * (my - br))
                    - data->anzeige / 2;
            if (data->scrollPos > data->max - data->anzeige)
                data->scrollPos = data->max - data->anzeige;
            if (data->scrollPos < 0) data->scrollPos = 0;
            rend = 1;
        }
    }
    return ret;
}

void VScrollBar::render(int x, int y, int br, int hi, Image& zRObj) const
{
    if (bg) zRObj.alphaRegion(x, y, br, hi, bgColor);
    --br;
    --hi;
    zRObj.drawLineH(x, y, br + 1, color);
    zRObj.drawLineH(x, y + hi, br + 1, color);
    zRObj.drawLineV(x, y + 1, hi - 1, color);
    zRObj.drawLineV(x + br, y + 1, hi - 1, color);
    zRObj.drawLineH(x + 1, y + br, br - 1, color);
    zRObj.drawLineH(x + 1, y + hi - br, br - 1, color);
    ++br;
    ++hi;
    int st = (int)(data->scrollPos / (data->max / (hi - br * 2.0)));
    int end = (int)((hi - 2.0 * br) / ((double)data->max / data->anzeige));
    if (data->scrollPos > data->max - data->anzeige)
        data->scrollPos = data->max - data->anzeige;
    if (data->scrollPos < 0)
    {
        data->scrollPos = 0;
        end = hi - br * 2;
    }
    zRObj.fillRegion(x + 1, y + br + st, br - 1, end, color);
}

// Contents of the HScrollBar class from Scroll.h
// Constructor
HScrollBar::HScrollBar()
    : ScrollBar()
{}

// Destructor
HScrollBar::~HScrollBar() {}

// non-constant
bool HScrollBar::doMouseMessage(int x, int y, int br, int hi, MouseEvent& me)
{
    if (me.id == ME_Leaves)
    {
        mp = 0;
        mx = -1;
        my = -1;
    }
    bool ret = me.mx >= x && me.mx <= x + br && me.my >= y && me.my <= y + hi;
    knopfdruck = 0;
    if (me.processed)
    {
        mx = -1, my = -1;
        mp = 0;
        return ret;
    }
    if (me.id == ME_LScroll)
    {
        data->scrollPos -= clickScroll;
        if (data->scrollPos < 0) data->scrollPos = 0;
        rend = 1;
        return ret;
    }
    if (me.id == ME_RScroll)
    {
        data->scrollPos += clickScroll;
        if (data->scrollPos > data->max - data->anzeige)
            data->scrollPos = data->max - data->anzeige;
        if (data->scrollPos < 0) data->scrollPos = 0;
        rend = 1;
        return ret;
    }
    if (ret)
        mx = me.mx - x, my = me.my - y;
    else
        mx = -1, my = -1;
    if (me.id == ME_PLeft) mp = 1;
    if (me.id == ME_RLeft) mp = 0;
    if (mp)
    {
        if (mx >= 0 && my >= 0)
        {
            if (mx < hi)
            {
                knopfdruck = 1;
                data->scrollPos -= clickScroll;
            }
            else if (mx > br - hi)
            {
                knopfdruck = 2;
                data->scrollPos += clickScroll;
            }
            else
                data->scrollPos
                    = (int)((data->max / (br - 2.0 * hi)) * (mx - hi))
                    - data->anzeige / 2;
            if (data->scrollPos > data->max - data->anzeige)
                data->scrollPos = data->max - data->anzeige;
            if (data->scrollPos < 0) data->scrollPos = 0;
            rend = 1;
        }
    }
    return ret;
}

void HScrollBar::render(int x, int y, int br, int hi, Image& zRObj) const
{
    if (bg) zRObj.alphaRegion(x, y, br, hi, bgColor);
    --br;
    --hi;
    zRObj.drawLineV(x, y, hi + 1, color);
    zRObj.drawLineV(x + br, y, hi + 1, color);
    zRObj.drawLineH(x + 1, y, br - 1, color);
    zRObj.drawLineH(x + 1, y + hi, br - 1, color);
    zRObj.drawLineV(x + hi, y + 1, hi - 1, color);
    zRObj.drawLineV(x + br - hi, y + 1, hi - 1, color);
    ++br;
    ++hi;
    int st = (int)(data->scrollPos / (data->max / (br - hi * 2.0)));
    int end = (int)((br - 2.0 * hi) / ((double)data->max / data->anzeige));
    if (data->scrollPos > data->max - data->anzeige)
        data->scrollPos = data->max - data->anzeige;
    if (data->scrollPos < 0)
    {
        data->scrollPos = 0;
        end = br - hi * 2;
    }
    zRObj.fillRegion(x + hi + st, y + 1, end, hi - 1, color);
}