/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии 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;
}
}