/*
    Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
    и других спецификаций для функционирования компактных приложений на языке
    Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package malik.emulator.microedition.lcdui;

import javax.microedition.lcdui.*;
import malik.emulator.application.*;

public final class SystemScrollBarStyle extends ScrollBarStyle
{
    private static final int ELEMENT_NONE        = 0;
    private static final int ELEMENT_SLIDER      = 1;
    private static final int ELEMENT_PAGE_BACK   = 2;
    private static final int ELEMENT_PAGE_NEXT   = 3;
    private static final int ELEMENT_SCROLL_BACK = 4;
    private static final int ELEMENT_SCROLL_NEXT = 5;
    private static final int SLIDER_MINIMUM_LENGTH = 7;

    private static int getHorizontalScrollBarFocusedElement(int page, int range, int position, int x, int y, int width, int height) {
        if(y >= 0 && y < height)
        {
            if(width <= 32)
            {
                int center = width >> 1;
                if(x >= 0 && x < center) return ELEMENT_SCROLL_BACK;
                if(x >= center && x < width) return ELEMENT_SCROLL_NEXT;
            }
            if(x >= 0 && x < 16) return ELEMENT_SCROLL_BACK;
            if(x >= width - 16 && x < width) return ELEMENT_SCROLL_NEXT;
            if(width >= 32 + SLIDER_MINIMUM_LENGTH && page > 0 && range > page)
            {
                int sl = getSliderLength(page, range, width - 32, SLIDER_MINIMUM_LENGTH);
                int x1 = getSliderPosition(page, range, position, width - 32, sl) + 16;
                int x2 = sl + x1 - 1;
                if(x >= 16 && x < x1) return ELEMENT_PAGE_BACK;
                if(x >= x1 && x <= x2) return ELEMENT_SLIDER;
                if(x > x2 && x < width - 16) return ELEMENT_PAGE_NEXT;
            }
        }
        return ELEMENT_NONE;
    }

    private static int getVerticalScrollBarFocusedElement(int page, int range, int position, int x, int y, int width, int height) {
        if(x >= 0 && x < width)
        {
            if(height <= 32)
            {
                int center = height >> 1;
                if(y >= 0 && y < center) return ELEMENT_SCROLL_BACK;
                if(y >= center && y < height) return ELEMENT_SCROLL_NEXT;
            }
            if(y >= 0 && y < 16) return ELEMENT_SCROLL_BACK;
            if(y >= height - 16 && y < height) return ELEMENT_SCROLL_NEXT;
            if(height >= 32 + SLIDER_MINIMUM_LENGTH && page > 0 && range > page)
            {
                int sl = getSliderLength(page, range, height - 32, SLIDER_MINIMUM_LENGTH);
                int y1 = getSliderPosition(page, range, position, height - 32, sl) + 16;
                int y2 = sl + y1 - 1;
                if(y >= 16 && y < y1) return ELEMENT_PAGE_BACK;
                if(y >= y1 && y <= y2) return ELEMENT_SLIDER;
                if(y > y2 && y < height - 16) return ELEMENT_PAGE_NEXT;
            }
        }
        return ELEMENT_NONE;
    }

    private int focused;
    private int pressedHorz;
    private int pressedVert;

    public SystemScrollBarStyle() {
        super(16);
    }

    public void horizontalScrollBarPointerEvent(ScrollBar scrollbar, PointerEvent event, int width, int height) {
        int f;
        int page = scrollbar.getPage();
        int range = scrollbar.getRange();
        switch(event.getAction())
        {
        case PointerEvent.ACTION_POINTER_PRESSED:
            switch(focused = pressedHorz = getHorizontalScrollBarFocusedElement(page, range, scrollbar.getPosition(), event.getX(), event.getY(), width, height))
            {
            case ELEMENT_PAGE_BACK:
                scrollbar.scroll(-page);
                break;
            case ELEMENT_PAGE_NEXT:
                scrollbar.scroll(page);
                break;
            case ELEMENT_SCROLL_BACK:
                scrollbar.scroll(-16);
                break;
            case ELEMENT_SCROLL_NEXT:
                scrollbar.scroll(16);
                break;
            }
            scrollbar.repaint();
            break;
        case PointerEvent.ACTION_BUTTON_PRESSED:
        case PointerEvent.ACTION_POINTER_DRAGGED:
        case PointerEvent.ACTION_BUTTON_RELEASED:
            f = focused;
            if(page > 0 && range > page && f == ELEMENT_SLIDER)
            {
                int x = event.getX();
                int p = event.historicalX(1);
                scrollbar.scroll((int) ((double) (x - p) * (double) range / (double) (width - 32)));
            }
            if(pressedHorz != (pressedHorz = getHorizontalScrollBarFocusedElement(page, range, scrollbar.getPosition(), event.getX(), event.getY(), width, height) != f ? 0 : f)) scrollbar.repaint();
            break;
        case PointerEvent.ACTION_POINTER_RELEASED:
            if(page > 0 && range > page && focused == ELEMENT_SLIDER)
            {
                int x = event.getX();
                int p = event.historicalX(1);
                scrollbar.scroll((int) ((double) (x - p) * (double) range / (double) (width - 32)));
            }
            pressedHorz = focused = 0;
            scrollbar.repaint();
            break;
        }
    }

    public void horizontalScrollBarPaintEvent(ScrollBar scrollbar, Graphics render, int width, int height) {
        boolean enabled;
        int sl;
        int x1;
        int x2;
        int page = scrollbar.getPage();
        int range = scrollbar.getRange();
        int element = pressedHorz;
        enabled = page > 0 && range > page;
        if(width <= 32)
        {
            int center = width >> 1;
            render.drawElement(10, 2, enabled ? element != ELEMENT_SCROLL_BACK ? 0 : 1 : 2, 0, 0, center, height);
            render.drawElement(10, 3, enabled ? element != ELEMENT_SCROLL_NEXT ? 0 : 1 : 2, center, 0, width - center, height);
            return;
        }
        render.drawElement(10, 2, enabled ? element != ELEMENT_SCROLL_BACK ? 0 : 1 : 2, 0, 0, 16, height);
        render.drawElement(10, 3, enabled ? element != ELEMENT_SCROLL_NEXT ? 0 : 1 : 2, width - 16, 0, 16, height);
        if(width < 32 + SLIDER_MINIMUM_LENGTH || !enabled)
        {
            render.drawElement(10, 6, enabled ? 0 : 2, 16, 0, width - 32, height);
            return;
        }
        sl = getSliderLength(page, range, width - 32, SLIDER_MINIMUM_LENGTH);
        x1 = getSliderPosition(page, range, scrollbar.getPosition(), width - 32, sl) + 16;
        x2 = sl + x1;
        render.drawElement(10, 6, element != ELEMENT_PAGE_BACK ? 0 : 1, 16, 0, x1 - 16, height);
        render.drawElement(10, 7, element != ELEMENT_PAGE_NEXT ? 0 : 1, x2, 0, width - x2 - 16, height);
        render.drawElement(10, 4, element != ELEMENT_SLIDER ? 0 : 1, x1, 0, x2 - x1, height);
    }

    public void verticalScrollBarPointerEvent(ScrollBar scrollbar, PointerEvent event, int width, int height) {
        int f;
        int page = scrollbar.getPage();
        int range = scrollbar.getRange();
        switch(event.getAction())
        {
        case PointerEvent.ACTION_POINTER_PRESSED:
            switch(focused = pressedVert = getVerticalScrollBarFocusedElement(page, range, scrollbar.getPosition(), event.getX(), event.getY(), width, height))
            {
            case ELEMENT_PAGE_BACK:
                scrollbar.scroll(-page);
                break;
            case ELEMENT_PAGE_NEXT:
                scrollbar.scroll(page);
                break;
            case ELEMENT_SCROLL_BACK:
                scrollbar.scroll(-16);
                break;
            case ELEMENT_SCROLL_NEXT:
                scrollbar.scroll(16);
                break;
            }
            scrollbar.repaint();
            break;
        case PointerEvent.ACTION_BUTTON_PRESSED:
        case PointerEvent.ACTION_POINTER_DRAGGED:
        case PointerEvent.ACTION_BUTTON_RELEASED:
            f = focused;
            if(page > 0 && range > page && f == ELEMENT_SLIDER)
            {
                int y = event.getY();
                int p = event.historicalY(1);
                scrollbar.scroll((int) ((double) (y - p) * (double) range / (double) (height - 32)));
            }
            if(pressedVert != (pressedVert = getVerticalScrollBarFocusedElement(page, range, scrollbar.getPosition(), event.getX(), event.getY(), width, height) != f ? 0 : f)) scrollbar.repaint();
            break;
        case PointerEvent.ACTION_POINTER_RELEASED:
            if(page > 0 && range > page && focused == ELEMENT_SLIDER)
            {
                int y = event.getY();
                int p = event.historicalY(1);
                scrollbar.scroll((int) ((double) (y - p) * (double) range / (double) (height - 32)));
            }
            pressedVert = focused = 0;
            scrollbar.repaint();
            break;
        }
    }

    public void verticalScrollBarPaintEvent(ScrollBar scrollbar, Graphics render, int width, int height) {
        boolean enabled;
        int sl;
        int y1;
        int y2;
        int page = scrollbar.getPage();
        int range = scrollbar.getRange();
        int element = pressedVert;
        enabled = page > 0 && range > page;
        if(height <= 32)
        {
            int center = height >> 1;
            render.drawElement(10, 0, enabled ? element != ELEMENT_SCROLL_BACK ? 0 : 1 : 2, 0, 0, width, center);
            render.drawElement(10, 1, enabled ? element != ELEMENT_SCROLL_NEXT ? 0 : 1 : 2, 0, center, width, height - center);
            return;
        }
        render.drawElement(10, 0, enabled ? element != ELEMENT_SCROLL_BACK ? 0 : 1 : 2, 0, 0, width, 16);
        render.drawElement(10, 1, enabled ? element != ELEMENT_SCROLL_NEXT ? 0 : 1 : 2, 0, height - 16, width, 16);
        if(height < 32 + SLIDER_MINIMUM_LENGTH || !enabled)
        {
            render.drawElement(10, 8, enabled ? 0 : 2, 0, 16, width, height - 32);
            return;
        }
        sl = getSliderLength(page, range, height - 32, SLIDER_MINIMUM_LENGTH);
        y1 = getSliderPosition(page, range, scrollbar.getPosition(), height - 32, sl) + 16;
        y2 = sl + y1;
        render.drawElement(10, 8, element != ELEMENT_PAGE_BACK ? 0 : 1, 0, 16, width, y1 - 16);
        render.drawElement(10, 9, element != ELEMENT_PAGE_NEXT ? 0 : 1, 0, y2, width, height - y2 - 16);
        render.drawElement(10, 5, element != ELEMENT_SLIDER ? 0 : 1, 0, y1, width, y2 - y1);
    }

    public void sizeGripPaintEvent(boolean sizeChangeAllowed, Graphics render, int width, int height) {
        render.drawElement(10, sizeChangeAllowed ? 11 : 12, 0, 0, 0, width, height);
    }
}
