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

import java.util.*;

public final class CLDCCalendar extends Calendar
{
    private final CalendarSystem system;

    public CLDCCalendar(CalendarSystem system) {
        this.system = system;
        setTimeInMillis(System.currentTimeMillis());
    }

    protected void computeTime() {
        int tmp;
        int[] flds = fields;
        TimeZone zone = getTimeZone();
        correctFields();
        time = system.computeTime(
            (tmp = flds[YEAR]) < 1 ? 1 : tmp, (tmp = flds[MONTH] + 1) < 1 ? 1 : tmp > 12 ? 12 : tmp,
            flds[DAY_OF_MONTH], flds[HOUR_OF_DAY], flds[MINUTE], flds[SECOND], flds[MILLISECOND],
            zone != null ? zone.getRawOffset() : 0
        );
    }

    protected void computeFields() {
        int h;
        int tmp;
        long days;
        long time;
        long fields;
        int[] flds;
        TimeZone zone;
        CalendarSystem system;
        fields = (system = this.system).computeFields(time = (zone = getTimeZone()) != null ? this.time + (long) zone.getRawOffset() : this.time, 0);
        flds = this.fields;
        days = (time + system.epochStart()) / 86400000L;
        flds[YEAR] = (int) (fields >>> 48);
        flds[MONTH] = ((int) (fields >> 40) & 0xff) - 1;
        flds[DAY_OF_MONTH] = (int) (fields >> 32) & 0xff;
        flds[DAY_OF_WEEK] = (int) ((days + 1L) % 7L) + 1;
        flds[AM_PM] = (tmp = (int) (fields >> 24) & 0xff) < 12 ? AM : PM;
        flds[HOUR] = (h = tmp % 12) == 0 ? 12 : h;
        flds[HOUR_OF_DAY] = tmp;
        flds[MINUTE] = (int) (fields >> 16) & 0xff;
        flds[SECOND] = (tmp = (int) fields & 0xffff) / 1000;
        flds[MILLISECOND] = tmp % 1000;
    }

    private void correctFields() {
        boolean[] sets = isSet;
        int[] flds = fields;
        if(sets[HOUR_OF_DAY])
        {
            int hour;
            flds[HOUR_OF_DAY] = hour = Math.abs(flds[HOUR_OF_DAY] % 24);
            flds[AM_PM] = hour < 12 ? AM : PM;
            sets[HOUR_OF_DAY] = false;
            return;
        }
        if(sets[AM_PM])
        {
            int ampm;
            if((ampm = flds[AM_PM]) != AM && ampm != PM) flds[AM_PM] = flds[HOUR_OF_DAY] < 12 ? AM : PM;
            sets[AM_PM] = false;
        }
        if(sets[HOUR])
        {
            int hour;
            if((hour = flds[HOUR]) > 12)
            {
                flds[HOUR_OF_DAY] = (hour % 12) + 12;
                flds[HOUR] = hour % 12;
                flds[AM_PM] = PM;
            } else
            {
                flds[HOUR_OF_DAY] = flds[AM_PM] == PM ? hour + 12 : hour;
            }
            sets[HOUR] = false;
        }
    }
}
