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

import malik.emulator.time.*;

public abstract class Calendar extends Object
{
    public static final int YEAR         =  1;
    public static final int MONTH        =  2;
    public static final int DATE         =  5;
    public static final int DAY_OF_MONTH =  5;
    public static final int DAY_OF_WEEK  =  7;
    public static final int AM_PM        =  9;
    public static final int HOUR         = 10;
    public static final int HOUR_OF_DAY  = 11;
    public static final int MINUTE       = 12;
    public static final int SECOND       = 13;
    public static final int MILLISECOND  = 14;
    public static final int SUNDAY    = 1;
    public static final int MONDAY    = 2;
    public static final int TUESDAY   = 3;
    public static final int WEDNESDAY = 4;
    public static final int THURSDAY  = 5;
    public static final int FRIDAY    = 6;
    public static final int SATURDAY  = 7;
    public static final int JANUARY   =  0;
    public static final int FEBRUARY  =  1;
    public static final int MARCH     =  2;
    public static final int APRIL     =  3;
    public static final int MAY       =  4;
    public static final int JUNE      =  5;
    public static final int JULY      =  6;
    public static final int AUGUST    =  7;
    public static final int SEPTEMBER =  8;
    public static final int OCTOBER   =  9;
    public static final int NOVEMBER  = 10;
    public static final int DECEMBER  = 11;
    public static final int AM = 0;
    public static final int PM = 1;

    public static Calendar getInstance() {
        return new CLDCCalendar(CalendarSystem.gregorian);
    }

    public static Calendar getInstance(TimeZone zone) {
        Calendar result;
        (result = new CLDCCalendar(CalendarSystem.gregorian)).setTimeZone(zone);
        return result;
    }

    private boolean isTimeSet;
    protected long time;
    protected boolean[] isSet;
    protected int[] fields;
    private TimeZone zone;

    protected Calendar() {
        this.isSet = new boolean[15];
        this.fields = new int[15];
        this.zone = TimeZone.getDefault();
    }

    public boolean equals(Object anot) {
        return anot == this || anot instanceof Calendar && getTimeInMillis() == ((Calendar) anot).getTimeInMillis();
    }

    public void setTimeZone(TimeZone zone) {
        this.zone = zone;
        getTimeInMillis();
        computeFields();
    }

    public boolean before(Object anot) {
        return anot instanceof Calendar && getTimeInMillis() < ((Calendar) anot).getTimeInMillis();
    }

    public boolean after(Object anot) {
        return anot instanceof Calendar && getTimeInMillis() > ((Calendar) anot).getTimeInMillis();
    }

    public TimeZone getTimeZone() {
        return zone;
    }

    public final void set(int field, int value) {
        isTimeSet = false;
        isSet[field] = true;
        fields[field] = value;
    }

    public final void setTime(Date time) {
        if(time != null) setTimeInMillis(time.getTime());
    }

    public final int get(int field) {
        switch(field)
        {
        default:
            break;
        case DAY_OF_WEEK:
        case AM_PM:
        case HOUR:
        case HOUR_OF_DAY:
            getTimeInMillis();
            computeFields();
            break;
        }
        return fields[field];
    }

    public final Date getTime() {
        return new Date(getTimeInMillis());
    }

    protected abstract void computeTime();

    protected abstract void computeFields();

    protected void setTimeInMillis(long millis) {
        isTimeSet = true;
        fields[DAY_OF_WEEK] = 0;
        time = millis;
        computeFields();
    }

    protected long getTimeInMillis() {
        if(!isTimeSet)
        {
            isTimeSet = true;
            computeTime();
        }
        return time;
    }
}
