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

import java.io.*;
import malik.emulator.fileformats.text.mapped.*;
import malik.emulator.io.cloud.*;

public final class System extends Object
{
    private static final MappedTextDecoder config;
    public static final PrintStream out;
    public static final PrintStream err;

    static {
        OutputStream stdout;
        OutputStream stderr;
        MappedTextDecoder cfg = new PropertiesDecoder();
        try
        {
            HandleInputStream stream = new FileInputStream("/config.properties");
            try
            {
                cfg.loadFromInputStream(stream);
            }
            finally
            {
                stream.close();
            }
        }
        catch(IOException e)
        {
        }
        try
        {
            stdout = (OutputStream) Class.forName(cfg.get("malik.emulator.application.out.class")).newInstance();
        }
        catch(Exception e)
        {
            stdout = new FileOutputStream("/out.txt");
        }
        try
        {
            stderr = (OutputStream) Class.forName(cfg.get("malik.emulator.application.err.class")).newInstance();
        }
        catch(Exception e)
        {
            stderr = new FileOutputStream("/err.txt");
        }
        /* ВАЖНО: сперва нужно записать данные в config */
        config = cfg;
        out = new PrintStream(stdout);
        err = new PrintStream(stderr);
    }

    public static void gc() {
        Runtime.getRuntime().gc();
    }

    public static void exit(int status) {
        Runtime.getRuntime().exit(status);
    }

    public static void arraycopy(Object src, int srcOffset, Object dst, int dstOffset, int length) {
        Class type;
        Class srcComponentType;
        Class dstComponentType;
        if(src == null)
        {
            throw new NullPointerException("System.arraycopy: аргумент src равен нулевой ссылке.");
        }
        if(dst == null)
        {
            throw new NullPointerException("System.arraycopy: аргумент dst равен нулевой ссылке.");
        }
        if((srcComponentType = src.getClass().componentType) == null)
        {
            throw new ArrayStoreException("System.arraycopy: аргумент src не является массивом.");
        }
        if((dstComponentType = dst.getClass().componentType) == null)
        {
            throw new ArrayStoreException("System.arraycopy: аргумент dst не является массивом.");
        }
        if(((srcComponentType.modifiers & Class.PRIMITIVE) != 0 || (dstComponentType.modifiers & Class.PRIMITIVE) != 0) && srcComponentType != dstComponentType)
        {
            throw new ArrayStoreException("System.arraycopy", dstComponentType, srcComponentType, false);
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("Z")) && dstComponentType == type)
        {
            Array.copy((boolean[]) src, srcOffset, (boolean[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("C")) && dstComponentType == type)
        {
            Array.copy((char[]) src, srcOffset, (char[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("F")) && dstComponentType == type)
        {
            Array.copy((float[]) src, srcOffset, (float[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("D")) && dstComponentType == type)
        {
            Array.copy((double[]) src, srcOffset, (double[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("B")) && dstComponentType == type)
        {
            Array.copy((byte[]) src, srcOffset, (byte[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("S")) && dstComponentType == type)
        {
            Array.copy((short[]) src, srcOffset, (short[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("I")) && dstComponentType == type)
        {
            Array.copy((int[]) src, srcOffset, (int[]) dst, dstOffset, length);
            return;
        }
        if(srcComponentType == (type = MalikSystem.getClassInstance("J")) && dstComponentType == type)
        {
            Array.copy((long[]) src, srcOffset, (long[]) dst, dstOffset, length);
            return;
        }
        if(dstComponentType.isAssignableFrom(srcComponentType))
        {
            Array.copy((Object[]) src, srcOffset, (Object[]) dst, dstOffset, length);
            return;
        }
        Array.copyReferences((Object[]) src, srcOffset, (Object[]) dst, dstOffset, length);
    }

    public static int identityHashCode(Object reference) {
        return MalikSystem.convertToReference(reference);
    }

    public static long currentTimeMillis() {
        return MalikSystem.syscall(2L, 0x000c) - 0x00003883122cd800L;
    }

    public static String getProperty(String key) {
        if(key == null)
        {
            throw new NullPointerException("System.getSystemProperty: аргумент key равен нулевой ссылке.");
        }
        if(key.length() <= 0)
        {
            throw new IllegalArgumentException("System.getSystemProperty: аргумент key имеет нулевую длину.");
        }
        return readProperty(false, key);
    }

    public static String getSystemProperty(String key) {
        if(key == null)
        {
            throw new NullPointerException("System.getSystemProperty: аргумент key равен нулевой ссылке.");
        }
        if(key.length() <= 0)
        {
            throw new IllegalArgumentException("System.getSystemProperty: аргумент key имеет нулевую длину.");
        }
        return readProperty(true, key);
    }

    private static String readProperty(boolean fromSystem, String key) {
        return !fromSystem && key.startsWith("malik.emulator.") ? null : config.get(key);
    }

    private System() {
    }
}
