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

public final class Font extends Object
{
    private static final class Info extends Object
    {
        public final SystemFont emulatorFont;
        public final Font microeditionFont;
        public Info next;

        public Info(SystemFont emulatorFont, Font microeditionFont) {
            this.emulatorFont = emulatorFont;
            this.microeditionFont = microeditionFont;
        }
    }

    public static final int FONT_STATIC_TEXT = 0;
    public static final int FONT_INPUT_TEXT = 1;
    public static final int FACE_SYSTEM = 0x00;
    public static final int FACE_MONOSPACE = 0x20;
    public static final int FACE_PROPORTIONAL = 0x40;
    public static final int STYLE_PLAIN = 0x00;
    public static final int STYLE_BOLD = 0x01;
    public static final int STYLE_ITALIC = 0x02;
    public static final int STYLE_UNDERLINED = 0x04;
    public static final int SIZE_MEDIUM = 0x00;
    public static final int SIZE_SMALL = 0x08;
    public static final int SIZE_LARGE = 0x10;

    private static final Info[] fonts;

    static {
        fonts = new Info[3 * 3 * 8];
    }

    public static Font getDefaultFont() {
        return getFont(FACE_SYSTEM, STYLE_PLAIN, SIZE_MEDIUM);
    }

    public static Font getFont(int fontSpecifier) {
        switch(fontSpecifier)
        {
        case FONT_STATIC_TEXT:
            return getFont(FACE_SYSTEM, STYLE_BOLD, SIZE_SMALL);
        case FONT_INPUT_TEXT:
            return getFont(FACE_SYSTEM, STYLE_PLAIN, SIZE_SMALL);
        default:
            throw new IllegalArgumentException("Font.getFont: аргумент fontSpecifier имеет недопустимое значение.");
        }
    }

    public static Font getFont(int face, int style, int size) {
        int settingsSize;
        if((settingsSize = (size >> 0x03) & 0x03) == 0x03) settingsSize = DeviceSettings.FONT_SIZE_MEDIUM;
        return getFont(DeviceManager.getInstance().getSettings().getFont(style & 0x03, settingsSize), face, style, size);
    }

    public static Font getFont(SystemFont systemFont, int face, int style, int size) {
        int index;
        Info[] fonts;
        Font result;
        if(face != FACE_SYSTEM && face != FACE_MONOSPACE && face != FACE_PROPORTIONAL)
        {
            throw new IllegalArgumentException("Font.getFont: аргумент face имеет недопустимое значение.");
        }
        if(style < STYLE_PLAIN || style > (STYLE_BOLD | STYLE_ITALIC | STYLE_UNDERLINED))
        {
            throw new IllegalArgumentException("Font.getFont: аргумент style имеет недопустимое значение.");
        }
        if(size != SIZE_MEDIUM && size != SIZE_SMALL && size != SIZE_LARGE)
        {
            throw new IllegalArgumentException("Font.getFont: аргумент size имеет недопустимое значение.");
        }
        if(systemFont == null) systemFont = SystemFont.getDefault();
        index = style + (size >> 3) * 8 + (face >> 5) * (8 * 3);
        fonts = Font.fonts;
        synchronized(fonts)
        {
            label0:
            {
                Info last;
                if((last = fonts[index]) == null)
                {
                    result = new Font(systemFont, face, style, size);
                    fonts[index] = new Info(systemFont, result);
                    break label0;
                }
                for(Info next; ; last = next)
                {
                    if(last.emulatorFont == systemFont)
                    {
                        result = last.microeditionFont;
                        break label0;
                    }
                    if((next = last.next) == null) break;
                }
                result = new Font(systemFont, face, style, size);
                last.next = new Info(systemFont, result);
            }
        }
        return result;
    }

    private final int face;
    private final int style;
    private final int size;
    private final SystemFont systemFont;

    private Font(SystemFont systemFont, int face, int style, int size) {
        this.face = face;
        this.style = style;
        this.size = size;
        this.systemFont = systemFont;
    }

    public boolean isPlain() {
        return style == STYLE_PLAIN;
    }

    public boolean isBold() {
        return (style & STYLE_BOLD) != 0;
    }

    public boolean isItalic() {
        return (style & STYLE_ITALIC) != 0;
    }

    public boolean isUnderlined() {
        return (style & STYLE_UNDERLINED) != 0;
    }

    public int charWidth(char character) {
        return systemFont.characterWidth(character);
    }

    public int charsWidth(char[] src, int offset, int length) {
        return systemFont.charactersWidth(src, offset, length);
    }

    public int stringWidth(String string) {
        return systemFont.stringWidth(string);
    }

    public int substringWidth(String string, int offset, int length) {
        return systemFont.substringWidth(string, offset, length);
    }

    public int getHeight() {
        return systemFont.getHeight();
    }

    public int getBaselinePosition() {
        return systemFont.getBaselinePosition();
    }

    public int getFace() {
        return face;
    }

    public int getStyle() {
        return style;
    }

    public int getSize() {
        return size;
    }

    SystemFont getSystemFont() {
        return systemFont;
    }
}
