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

public class MultilinedStringBuilder extends StringBuilder
{
    public static String truncate(String string, Font font, int width) {
        int i;
        int len;
        int pos;
        char[] c;
        if(string == null || (len = string.length()) <= 0) return "";
        if(width < 0) return string;
        if(font == null) font = Font.getDefaultFont();
        for(pos = len, i = 0; i < len; i++) if(string.charAt(i) < CharacterDestination.SPACE)
        {
            pos = i;
            break;
        }
        if(pos < len)
        {
            string.getChars(0, pos, c = new char[len = pos + 1], 0);
            c[pos] = '…';
        }
        else if(font.stringWidth(string) > width)
        {
            (c = string.toCharArray())[len - 1] = '…';
        }
        else
        {
            return string;
        }
        while(len > 1 && font.charsWidth(c, 0, len) > width) c[--len - 1] = '…';
        return (new String(c, 0, len)).intern();
    }

    private int сount;
    private int[] offsets;
    private int[] lengths;

    public MultilinedStringBuilder() {
        this.offsets = new int[0x0f];
        this.lengths = new int[0x0f];
    }

    public MultilinedStringBuilder(int initialCapacity) {
        super(initialCapacity);
        this.offsets = new int[0x0f];
        this.lengths = new int[0x0f];
    }

    public void split(Font font, int width) {
        int line = 0;
        int len = length;
        char[] c = content;
        int[] lofs = offsets;
        int[] llen = lengths;
        if(len <= 0)
        {
            сount = 1;
            lofs[0] = 0;
            llen[0] = 0;
            return;
        }
        if(font == null) font = Font.getDefaultFont();
        for(int n, s, e, i = s = 0; i <= len; line++, i = s = n)
        {
            boolean ending;
            for(; ; i++) if((ending = i >= len || c[i] == CharacterDestination.LINE) || font.charsWidth(c, s, i - s + 1) > width) break;
            if(ending)
            {
                n = (e = i) + 1;
            }
            else if(i == s)
            {
                n = e = s + 1;
            }
            else
            {
                n = e = i;
                for(int j = i - 1; j > s; j--)
                {
                    char ch;
                    if((ch = c[j]) == CharacterDestination.SPACE)
                    {
                        n = (e = j) + 1;
                        break;
                    }
                    if(isWordSeparator(ch))
                    {
                        n = e = j + 1;
                        break;
                    }
                }
            }
            if(lofs.length == line)
            {
                int nlen = (line << 1) + 1;
                Array.copy(lofs, 0, lofs = new int[nlen], 0, line);
                Array.copy(llen, 0, llen = new int[nlen], 0, line);
            }
            lofs[line] = s;
            llen[line] = e - s;
        }
        сount = line;
        offsets = lofs;
        lengths = llen;
    }

    public boolean isWordSeparator(char c) {
        return c >= '\u0000' && c <= '\u0020' || c == '!' || c == '%' || c == '&' || c >= ')' && c <= '/' || c >= ':' && c <= '?' || c >= '\\' && c <= '`' || c >= '|' && c <= '~';
    }

    public final int lines() {
        return сount;
    }

    public final int lineOffset(int index) {
        Array.checkIndex("MultilinedStringBuilder.lineOffset", сount, index);
        return offsets[index];
    }

    public final int lineLength(int index) {
        Array.checkIndex("MultilinedStringBuilder.lineLength", сount, index);
        return lengths[index];
    }

    public final int lineAt(int position) {
        int a;
        int b;
        int c;
        int oa;
        int ob;
        int oc;
        int count = this.сount;
        int[] lofs = this.offsets;
        int[] llen = this.lengths;
        a = 0;
        b = (count - 1) >> 1;
        c = count - 1;
        for(; ; )
        {
            oa = lofs[a];
            ob = lofs[b] + llen[b];
            oc = lofs[c] + llen[c];
            if(a == b && b == c) break;
            if(position >= oa && position <= ob)
            {
                c = b;
                b = (a + c) >> 1;
                continue;
            }
            if(position > ob && position <= oc)
            {
                a = b < c ? b + 1 : b;
                b = (a + c) >> 1;
                continue;
            }
            return -1;
        }
        return a;
    }
}
