// Datum.java
package objectstreams;
import java.util.Calendar;
import java.io.Serializable;

/**
 * Datum ist ein Bauplan f&uuml;r Datumswerte.
 * Verwendung von Serializable ist ein Sicherheitsrisiko!
 * @author H.Drachenfels
 * @version 17.1.2020
 */
public final class Datum implements Serializable {
    private static final String[] MONATE = {
        "Januar",
        "Februar",
        "Maerz",
        "April",
        "Mai",
        "Juni",
        "Juli",
        "August",
        "September",
        "Oktober",
        "November",
        "Dezember"
    };

    private final int tag;
    private final String monat;
    private final int jahr;

    private Datum(/* final Datum this, */ int tag, int monat, int jahr) {
        this.tag = tag;
        this.monat = MONATE[monat - 1];
        this.jahr = jahr;
    }

    /**
     * Fabrikmethode, die ein value object mit dem angegebenen Datum liefert.
     * @param tag ist der Tag im Monat
     * @param monat ist der Monat im Jahr
     * @param jahr ist das Jahr
     * @return Referenz auf das value object
     */
    public static Datum valueOf(int tag, int monat, int jahr) {
        // Datum pruefen (stark vereinfacht)
        if (tag < 1 || tag > 31 || monat < 1 || monat > 12) {
            throw new IllegalArgumentException("ungueltiges Datum");
        }

        // value object erzeugen
        return new Datum(tag, monat, jahr);
    }

    /**
     * Fabrikmethode, die ein value object mit dem aktuellen Datum liefert.
     * @return Referenz auf das value object
     */
    public static Datum heute() {
        // Systemkalender ablesen
        Calendar c = Calendar.getInstance();

        // value object erzeugen
        return new Datum(c.get(Calendar.DAY_OF_MONTH),
                         c.get(Calendar.MONTH) + 1,
                         c.get(Calendar.YEAR));
    }

    @Override
    public String toString(/* final Datum this */) {
        return String.format("%d. %s %d", this.tag, this.monat, this.jahr);
    }

    @Override
    public boolean equals(/* final Datum this, */ Object o) {
        if (o instanceof Datum) {
            Datum that = (Datum) o;
            return this.tag == that.tag
                   && this.monat.equals(that.monat)
                   && this.jahr == that.jahr;
        }

        return false;
    }

    @Override
    public int hashCode(/* final Datum this */) {
        return ((this.jahr << 5) + this.tag) ^ this.monat.hashCode();
    }
}

