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

public class Object
{
    /* Нельзя менять порядок полей здесь, нельзя добавлять новые поля сюда. */
    private Thread.Monitor monitor;
    private int refcount;
    private Class objclass;

    public Object() {
    }

    public boolean equals(Object anot) {
        return anot == this;
    }

    public int hashCode() {
        return MalikSystem.convertToReference(this);
    }

    public String toString() {
        return (new StringBuilder()).append(objclass.getName()).append('@').append(Integer.toHexString(hashCode())).toString();
    }

    public final void wait() throws InterruptedException {
        Thread.Monitor monitor;
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_WAIT);
        }
        monitor.waitNotifying(0L);
    }

    public final void wait(long millis) throws InterruptedException {
        Thread.Monitor monitor;
        if(millis < 0L)
        {
            throw new IllegalArgumentException("Object.wait: аргумент millis не может быть отрицательным.");
        }
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_WAIT);
        }
        monitor.waitNotifying(millis);
    }

    public final void wait(long millis, int nanos) throws InterruptedException {
        Thread.Monitor monitor;
        if(millis < 0L)
        {
            throw new IllegalArgumentException("Object.wait: аргумент millis не может быть отрицательным.");
        }
        if(nanos < 0 || nanos > 999999)
        {
            throw new IllegalArgumentException("Object.wait: аргумент nanos выходит из диапазона.");
        }
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_WAIT);
        }
        monitor.waitNotifying(millis < Long.MAX_VALUE && nanos >= 500000 || millis == 0L && nanos > 0 ? millis + 1L : millis);
    }

    public final void notify() {
        Thread.Monitor monitor;
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_NOTIFY);
        }
        monitor.notifyWaiting(false);
    }

    public final void notifyAll() {
        Thread.Monitor monitor;
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_NOTIFY_ALL);
        }
        monitor.notifyWaiting(true);
    }

    public final Class getClass() {
        return objclass;
    }

    protected void $finalize$() {
        Class thisComponentType;
        if((thisComponentType = objclass.componentType) != null && (thisComponentType.modifiers & Class.PRIMITIVE) == 0) MalikSystem.arrayfill_object(this, 0, getArrayLength(), null);
    }

    final void monitorenter() {
        Thread.Monitor monitor;
        if((monitor = this.monitor) == null)
        {
            boolean status = MalikSystem.enterMonopolyAccess();
            try
            {
                if((monitor = this.monitor) == null) this.monitor = monitor = new Thread.Monitor();
            }
            finally
            {
                MalikSystem.leaveMonopolyAccess(status);
            }
        }
        monitor.enter();
    }

    final void monitorexit() {
        Thread.Monitor monitor;
        if((monitor = this.monitor) == null)
        {
            throw new IllegalMonitorStateException(Thread.Monitor.MESSAGE_NOT_OWNING_MONITOR_EXIT);
        }
        monitor.exit();
    }

    final void checkObjectArrayAssignable(Object element) {
        Class saving;
        Class required;
        if((required = objclass.componentType) == null || (required.modifiers & Class.PRIMITIVE) != 0)
        {
            throw new VerifyError("Инструкция aastore: ожидался массив объектных ссылок.");
        }
        if(element != null && !required.isAssignableFrom(saving = element.objclass))
        {
            throw new ArrayStoreException("Инструкция aastore", required, saving, true);
        }
    }

    final int dummyObject() {
        return refcount;
    }

    final int getArrayLength() {
        return MalikSystem.getIntAt(MalikSystem.convertToReference(this) + 0x08);
    }

    final int getArrayAddress() {
        int ref;
        return (ref = MalikSystem.convertToReference(this)) + MalikSystem.getIntAt(ref + 0x0c) + 0x10;
    }

    final int getQuantityOfReferencesTo(int refAnot) {
        Class thisType;
        Class thisComponentType;
        if((thisComponentType = (thisType = objclass).componentType) != null && (thisComponentType.modifiers & Class.PRIMITIVE) == 0)
        {
            return MalikSystem.getArrayRefs(this, refAnot, thisType.referenceOffsets);
        }
        return MalikSystem.getObjectRefs(this, refAnot, thisType.referenceOffsets);
    }
}
