/*
    Реализация спецификаций 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 javax.microedition.lcdui;

import malik.emulator.media.graphics.*;
import malik.emulator.microedition.lcdui.*;
import malik.emulator.util.*;

public class StringItem extends AppearanceModeItem
{
    private static final String NEW_LINE = "\n";

    private static void writeText(StringBuilder builder, String text) {
        builder.clear();
        builder.append(text);
        if(text != null)
        {
            if(text.startsWith(NEW_LINE)) builder.delete(0);
            if(text.endsWith(NEW_LINE) && !builder.isEmpty()) builder.delete(builder.length() - 1);
        }
    }

    private char[] buffer;
    private Font textFont;
    private String textAsString;
    private final MultilinedStringBuilder textAsBuilder;

    public StringItem(String label, String text) {
        this(label, text, PLAIN);
    }

    public StringItem(String label, String text, int appearanceMode) {
        super(label, appearanceMode);
        MultilinedStringBuilder builder;
        this.textFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
        this.textAsString = text;
        this.textAsBuilder = builder = new FastMultilinedStringBuilder();
        writeText(builder, text);
    }

    public void setText(String text) {
        StringBuilder builder;
        synchronized(builder = textAsBuilder)
        {
            writeText(builder, textAsString = text);
        }
        requestInvalidate();
    }

    public void setFont(Font font) {
        textFont = font == null ? Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM) : font;
        requestInvalidate();
    }

    public String getText() {
        return textAsString;
    }

    public Font getFont() {
        return textFont;
    }

    void paint(Graphics render, int contentWidth, int contentHeight) {
        boolean f;
        boolean p;
        boolean c;
        int l;
        int t;
        int w;
        Font font;
        MultilinedStringBuilder builder;
        switch(appearanceMode)
        {
        default:
            c = false;
            l = t = 0;
            w = contentWidth;
            render.setColor(RasterCanvas.getSystemColor(0x28));
            break;
        case HYPERLINK:
            c = false;
            l = t = (p = pressed) ? 1 : 0;
            w = contentWidth > 1 ? contentWidth - 1 : 0;
            render.setColor(RasterCanvas.getSystemColor(focused ? p ? 0x25 : 0x27 : 0x24));
            break;
        case BUTTON:
            c = true;
            f = focused;
            l = ((p = pressed) ? 1 : 0) + (contentWidth >> 1);
            t = p ? 5 : 4;
            w = contentWidth > 8 ? contentWidth - 8 : 0;
            render.drawElement(4, f ? p ? 1 : 3 : 0, 0, 0, 0, contentWidth, contentHeight);
            render.setColor(RasterCanvas.getSystemColor(f ? p ? 0x25 : 0x27 : 0x24));
            break;
        }
        render.setFont(font = textFont);
        synchronized(builder = textAsBuilder)
        {
            int line;
            int srow;
            int frow;
            int clipTop;
            char[] lbuf = buffer;
            srow = (clipTop = render.getClipY() - t) / (line = font.getHeight());
            frow = (clipTop + render.getClipHeight() - 1) / line;
            builder.split(font, w);
            for(int len = builder.lines(), top = t + srow * line, index = srow < 0 ? 0 : srow; index <= frow && index < len; top += line, index++)
            {
                int lofs = builder.lineOffset(index);
                int llen = builder.lineLength(index);
                if(lbuf == null || lbuf.length < llen) lbuf = buffer = new char[StringBuilder.optimalCapacity(llen)];
                builder.copy(lofs, lofs + llen, lbuf, 0);
                render.drawChars(lbuf, 0, llen, l, top, c ? Graphics.HCENTER | Graphics.TOP : Graphics.LEFT | Graphics.TOP);
            }
        }
    }

    boolean onFocusMove(int direction, int viewportWidth, int viewportHeight, int[] visibleRectangle) {
        int max;
        int pos1;
        int pos2;
        int size;
        int delta;
        if(!super.onFocusMove(direction, viewportWidth, viewportHeight, visibleRectangle))
        {
            pressed = false;
            return true;
        }
        switch(direction)
        {
        default:
            break;
        case DIR_LEFT:
            if((pos1 = visibleRectangle[LEFT]) <= 0) return false;
            visibleRectangle[LEFT] = pos1 > (delta = viewportWidth >> 1) ? pos1 - delta : 0;
            break;
        case DIR_RIGHT:
            if((pos2 = (pos1 = visibleRectangle[LEFT]) + (size = visibleRectangle[WIDTH])) >= (max = contentWidth)) return false;
            visibleRectangle[LEFT] = pos2 < max - (delta = viewportWidth >> 1) ? pos1 + delta : max - size;
            break;
        case DIR_UP:
            if((pos1 = visibleRectangle[TOP]) <= 0) return false;
            visibleRectangle[TOP] = pos1 > (delta = textFont.getHeight()) ? pos1 - delta : 0;
            break;
        case DIR_DOWN:
            if((pos2 = (pos1 = visibleRectangle[TOP]) + (size = visibleRectangle[HEIGHT])) >= (max = contentHeight)) return false;
            visibleRectangle[TOP] = pos2 < max - (delta = textFont.getHeight()) ? pos1 + delta : max - size;
            break;
        }
        return true;
    }

    boolean hasRowBreakBefore(int layout, int alignment) {
        String text;
        return super.hasRowBreakBefore(layout, alignment) || (text = textAsString) != null && text.startsWith("\n");
    }

    boolean hasRowBreakAfter(int layout, int alignment) {
        String text;
        return super.hasRowBreakAfter(layout, alignment) || (text = textAsString) != null && text.endsWith("\n");
    }

    int getDefaultLayout() {
        return appearanceMode == PLAIN ? LAYOUT_EXPAND : LAYOUT_DEFAULT;
    }

    int getMinimumContentWidth() {
        int result = 0;
        StringBuilder builder;
        synchronized(builder = textAsBuilder)
        {
            if(!builder.isEmpty()) result = 100;
        }
        return result + sizeAppendix();
    }

    int getMinimumContentHeight() {
        int result = 0;
        MultilinedStringBuilder builder;
        synchronized(builder = textAsBuilder)
        {
            if(!builder.isEmpty())
            {
                Font font;
                builder.split(font = textFont, Integer.MAX_VALUE);
                result = font.getHeight() * builder.lines();
            }
        }
        return result + sizeAppendix();
    }

    int getPreferredContentWidth(int contentHeight) {
        int result = 0;
        int maxWidth = contentHeight >= 0 ? width : 100;
        MultilinedStringBuilder builder;
        synchronized(builder = textAsBuilder)
        {
            if(!builder.isEmpty())
            {
                int index;
                Font font;
                builder.split(font = textFont, maxWidth);
                index = builder.lines();
                for(char[] buf = buffer; index-- > 0; )
                {
                    int lwid;
                    int lofs = builder.lineOffset(index);
                    int llen = builder.lineLength(index);
                    if(buf == null || buf.length < llen) buf = buffer = new char[StringBuilder.optimalCapacity(llen)];
                    builder.copy(lofs, lofs + llen, buf, 0);
                    if(result < (lwid = font.charsWidth(buf, 0, llen))) result = lwid;
                }
            }
        }
        return result + sizeAppendix();
    }

    int getPreferredContentHeight(int contentWidth) {
        int result = 0;
        int sapp = sizeAppendix();
        MultilinedStringBuilder builder;
        synchronized(builder = textAsBuilder)
        {
            if(!builder.isEmpty())
            {
                Font font;
                builder.split(font = textFont, contentWidth >= sapp ? contentWidth - sapp : Integer.MAX_VALUE);
                result = font.getHeight() * builder.lines();
            }
        }
        return result + sapp;
    }

    private int sizeAppendix() {
        switch(appearanceMode)
        {
        default:
            return 0;
        case HYPERLINK:
            return 1;
        case BUTTON:
            return 8;
        }
    }
}
