/* Copyright 2014-2023 askanimus@gmail.com */

/* This File is part of "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).  If not, see <http://www.gnu.org/licenses/>.
 *
 * Diese Datei ist Teil von "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) ist Freie Software: Sie können es unter den Bedingungen
 * der GNU General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
 * veröffentlichten Version, weiter verteilen und/oder modifizieren.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
 * Siehe die GNU General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
 * Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
 */
package askanimus.arbeitszeiterfassung2;

import android.content.Context;
import android.text.format.DateFormat;

import androidx.annotation.NonNull;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import askanimus.arbeitszeiterfassung2.setup.ASettings;

/**
 * @author askanimus@gmail.com on 30.11.15.
 */
public class Datum {
    public static final int JANUAR = 1;
    static final int FEBRUAR = 2;
    static final int MAERZ = 3;
    static final int APRIL = 4;
    static final int MAI = 5;
    static final int JUNI = 6;
    static final int JULI = 7;
    static final int AUGUST = 8;
    static final int SEPTEMBER = 9;
    static final int OKTOBER = 10;
    static final int NOVEMBER = 11;
    static final int DEZEMBER = 12;

    /*public static final int KURZ_NICHTS = 0;
    public static final int KURZ_DOPPEL = 1;
    public static final int KURZ_ALL = 2;*/

    private final Calendar mKalender;

    /**
     * mit aktuellem Datum initialisieren und den Wochenbegin setzen
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param wochenbeginn Wochentag mit dem die Woche beginnen soll
     */
    public Datum(int wochenbeginn){
        mKalender = Calendar.getInstance();
        mKalender.setTime(new Date());
        loescheZeit();
        mKalender.setFirstDayOfWeek(wochenbeginn);
    }

    /**
     * mit den Daten eines anderen Datumsobjekts initialisieren
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param kalender Datumsobjekt
     */
    public Datum(Datum kalender){
        mKalender = Calendar.getInstance();
        mKalender.setTimeInMillis(kalender.getTimeInMillis());
        loescheZeit();
        mKalender.setFirstDayOfWeek(kalender.getCalendar().getFirstDayOfWeek());
    }


 /**
  * mit den Daten eines Date Objekts initialisieren und den Wochenbegin setzen
  * es werden nur Jahr, Monat und Tag verwendet
  *
  * @param datum Date Objekt
  * @param wochenbeginn Wochentag mit dem die Woche beginnen soll
  */
    public Datum(Date datum, int wochenbeginn) {
        mKalender = Calendar.getInstance();
        mKalender.setTimeInMillis(datum.getTime());
        loescheZeit();
        mKalender.setFirstDayOfWeek(wochenbeginn);
    }

    /**
     * mit Datum in Millisekunden initialisieren und den Wochenbegin setzen
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param datum Millisekunden vom 1.1.1970 beginnend
     * @param wochenbeginn Wochentag mit dem die Woche beginnen soll
     */
    public Datum(long datum, int wochenbeginn) {
        mKalender = Calendar.getInstance();
        mKalender.setTimeInMillis(datum);
        loescheZeit();
        mKalender.setFirstDayOfWeek(wochenbeginn);
    }

    /**
     * mit den Daten eines Calendar Objekts initialisieren und den Wochenbegin setzen
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param kalender Calendar Objekt
     * @param wochenbeginn Wochentag mit dem die Woche beginnen soll
     */
    public Datum(Calendar kalender, int wochenbeginn) {
        mKalender = Calendar.getInstance();
        mKalender.setTime(kalender.getTime());
        loescheZeit();
       mKalender.setFirstDayOfWeek(wochenbeginn);
    }

    /**
     * mit Jahr, Monat und Tag initialisieren und den Wochenbegin setzen
     *
     * @param jahr Jahr
     * @param monat Monat beginnend mit 1
     * @param tag Tag
     * @param wochenbeginn Wochentag mit dem die Woche beginnen soll
     */
    public Datum(int jahr, int monat, int tag, int wochenbeginn) {
        mKalender = Calendar.getInstance();
        mKalender.set(jahr, monat - 1, tag);
        loescheZeit();
        mKalender.setFirstDayOfWeek(wochenbeginn);
    }


    //////////////// Set //////////////////////////////////
    public void set(Datum kalender){
        mKalender.setTimeInMillis(kalender.getTimeInMillis());
        loescheZeit();
        mKalender.setFirstDayOfWeek(kalender.getCalendar().getFirstDayOfWeek());
    }
    /**
     * Jahr, Monat und Tag überschreiben
     *
     * @param jahr Jahr
     * @param monat Monat beginnend mit 1
     * @param tag Tag
     */
    public void set(int jahr, int monat, int tag){
        mKalender.set(Calendar.YEAR, jahr);
        mKalender.set(Calendar.MONTH, monat - 1);
        mKalender.set(Calendar.DAY_OF_MONTH, tag);
        loescheZeit();
    }

    /**
     * mit den Daten eines Calendar Objekts überschreiben
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param kalender Calendar Objekt
     */
    public void set(Calendar kalender){
        mKalender.setTime(kalender.getTime());
        loescheZeit();
    }

    /**
     * mit einen Date Objekt übrschreiben
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param datum Date Objekt
     */
    public void set(Date datum){
        mKalender.setTime(datum);
        loescheZeit();
    }

    /**
     * mit Datum in Millisekunden überschreiben
     * es werden nur Jahr, Monat und Tag verwendet
     *
     * @param datum Datum in Millisekunden vom 1.1.1970 beginnend
     */
     public void set(long datum){
        mKalender.setTimeInMillis(datum);
        loescheZeit(/*Kalender*/);
    }

    /**
     * das Jahr überschreiben
     *
     * @param jahr Jahr
     */
    public void setJahr(int jahr){
        mKalender.set(Calendar.YEAR, jahr);
    }

    /**
     * den Monat überschreiben
     *
     * @param monat Monat beginnend mit 1
     */
    public void setMonat(int monat){
        mKalender.set(Calendar.MONTH, monat - 1);
    }

    /**
     * die Woche setzen
     *
     * @param woche nummer der Woche im Jahr
     */
    public void setWoche(int woche){
        mKalender.set(Calendar.WEEK_OF_YEAR, woche);
    }

    /**
     * den Tag überschreiben
     *
     * @param tag Tag im Monat
     */
    public void setTag(int tag){
        mKalender.set(Calendar.DAY_OF_MONTH, tag);
    }

    /**
     * den Wochenbeginn auf einen anderen Wochentag setzen
     *
     * @param wochentag neuer Wochenbeginn
     */
    public void setWocheBeginn(int wochentag) {
        if (wochentag != mKalender.get(Calendar.DAY_OF_WEEK)) {
           Datum altKalender = new Datum(mKalender.getTime(), mKalender.getFirstDayOfWeek());

            int quelltag = mKalender.get(Calendar.DAY_OF_WEEK);

            mKalender.add(Calendar.DAY_OF_MONTH, wochentag - quelltag);

            int tageDiff = tageBis(altKalender);

            if(tageDiff < 0)
                mKalender.add(Calendar.WEEK_OF_YEAR, -1);
            else {
                if(tageDiff > 6){
                    mKalender.add(Calendar.WEEK_OF_YEAR, 1);
                }
            }
        }

    }

    /**
     * Korrigiert das gespeicherte Datum, dass es auf den Beginn der Woche zeigt
     *
     */
    public void setDatumAufWochenbeginn() {
        int zielTag = mKalender.getFirstDayOfWeek();
        int startTag = mKalender.get(Calendar.DAY_OF_WEEK);

        if (startTag != zielTag) {
            Datum altKalender = new Datum(mKalender.getTime(), mKalender.getFirstDayOfWeek());

            mKalender.add(Calendar.DAY_OF_MONTH, zielTag - startTag);

            int tageDiff = tageBis(altKalender);

            if (tageDiff < 0)
                mKalender.add(Calendar.WEEK_OF_YEAR, -1);
            else {
                if (tageDiff > 6) {
                    mKalender.add(Calendar.WEEK_OF_YEAR, 1);
                }
            }
        }
    }

    private void loescheZeit(){
        mKalender.set(Calendar.HOUR_OF_DAY, 0);
        mKalender.set(Calendar.MINUTE, 0);
        mKalender.set(Calendar.SECOND, 0);
        mKalender.set(Calendar.MILLISECOND, 0);
    }

    /////////////// Get ///////////////////////////////////

    /**
     * gibt das Jahr des gespeicherten Kalenders zurück
     *
     * @return das Jahr
     */
    public int getJahr(){
        return mKalender.get(Calendar.YEAR);
    }

    /**
     * gibt den Monat beginnend mit 1 für Januar des gespeicherten Kalenders zurück
     *
     * @return der Monat beginnend mit 1 für Januar
     */
    public int getMonat() {
        return (mKalender.get(Calendar.MONTH) + 1);
    }

    /**
     * gibt die Wochennummer im Jahr des gespeicherten Kalenders zurück
     *
     * @return die Wochennnummer des Jahres
     */
    public int getWoche() {
        return (mKalender.get(Calendar.WEEK_OF_YEAR));
    }

    /**
     * gibt dden Tag des Monats des gespeicherten Kalenders zurück
     *
     * @return der Tag des Monats
     */
    public int getTagimMonat(){
        return mKalender.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * gibt alle Werte analog zu einem Calendar Objekt zurück
     * außer das die Monate mit 1 beginnen nicht mit 0
     *
     * @param wert vom Calendar Objekt zurückzuliefernder Wert z.B. Calendar.MONTH
     * @return vom Calendar Objekt zurückgelieferter Wert - Monat mit 1 beginnen nicht mit 0
     */
    public int get(int wert){
        if (wert == Calendar.MONTH)
            return (mKalender.get(Calendar.MONTH) + 1);
        else {
            return mKalender.get(wert);
        }
    }

    /**
     * Gibt ein Date Objekt des Datums zurück
     * die Uhrzeit ist immer 00:00:00
     *
     * @return Date Objekt
     */
    public Date getDate(){
        return mKalender.getTime();
    }

    /**
     * gibt das Datum in Millisekunden seit 1.1.1970 zurück
     * die Uhrzeit ist immer 00:00:00
     *
     * @return Datum in Millisekunden seit 1.1.1970
     */
    public long getTimeInMillis(){
        return mKalender.getTimeInMillis();
    }

    /**
     * gibt das Calendar Objekt zurück
     *
     * @return Calendar Objekt des gespeicherten Datums
     */
    public Calendar getCalendar(){
        return mKalender;
    }

    /**
     * gibt den ersten Tag der Woche zurück
     *
     * @return erster Wochentag
     */
    public int getWochenbeginn() {
        return mKalender.getFirstDayOfWeek();
    }

    /**
     * verhält sich analog zu einen Calendar Objekt und
     * addiert einen Feldwert
     *
     * @param feld Calendar Fald - Wert zu dem addiert wird z.B. Calendar.MONTH
     * @param wert der zu addierende Wert
     */
    public void add(int feld, int wert){
        mKalender.add(feld, wert);
    }

    /**
     * verhält sich analog zu einen Calendar Objekt und
     * und gibt das aktuelle Maximum eines Feldes zurück
     *
     * @param feld Feld dessen Maximum benötigt wird z.B.: Calendar.DAY_OF_MONTH
     * @return der aktuelle Maximalwert
     */
    public int getAktuellMaximum(int feld){
        return mKalender.getActualMaximum(feld);
    }

    /**
     * zählt die Tage vom gespeicherten Datum bis zum übergebenen Datum
     * ist das übergebene Datum kleiner als das gespeicherte, wird ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum, bis zu welchen gezählt werden soll
     * @return Anzahl Tage
     */
    public int tageBis(Datum kalender) {
        float mTage = kalender.getTimeInMillis() - mKalender.getTimeInMillis();
        mTage /= TimeUnit.DAYS.toMillis(1);
        return Math.round(mTage);
    }

    /**
     * zählt die Tage vom übergebenen Datum bis zum gespeicherten Datum
     * ist das übergebene Datum grösser als das gespeicherte wird, ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum ab dem gezählt werden soll
     * @return Anzahl Tage
     */
    public int tageAb(Datum kalender) {
        float mTage = mKalender.getTimeInMillis() - kalender.getTimeInMillis();
        mTage /= TimeUnit.DAYS.toMillis(1);
        return Math.round(mTage);
    }

    /**
     * Differenz an Tagen zwischen dem übergebenen und dem gespeichertem Datum
     * dieser Wert ist immer positiv oder 0
     *
     * @param kalender Datum bis dessen Differenz an Tagen zum gespeicherten Datum ermittelt werden soll
     * @return Anzahl Tage - immer positiv oder 0
     */
    private int tageDiff(Datum kalender) {
        float mTage = mKalender.getTimeInMillis() - kalender.getTimeInMillis();
        mTage /= TimeUnit.DAYS.toMillis(1);
        if(mTage < 0)
            mTage = 0 - mTage;
        return Math.round(mTage);
    }

    /**
     * gibt die Tage vom gespeicherten Datum bis zum Wochenende (Samstag)aus
     *
     * @return Anzahl Tage bis zum Wochenende (Samstag)
     */
    public int tagebisWochenende(){
        int mTag = 7 - mKalender.get(Calendar.DAY_OF_WEEK);
        mTag += (mKalender.getFirstDayOfWeek() -1);
        if(mTag >= 7)
           mTag -= 7;
        return mTag;
    }

    /**
     * zählt die Wochen vom gespeicherten Datum bis zum übergebenen Datum
     * ist das übergebene Datum kleiner als das gespeicherte, wird ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum, bis zu welchen gezählt werden soll
     * @return Anzahl Wochen
     */
    public int wochenBis(Datum kalender) {
        if (istGleich(kalender))
            return 0;
        else {
            float wert = (float)tageBis(kalender) / 7;
            if(wert % 1 != 0)
                if(wert > 0) wert++; else wert--;

            return (int)wert;
        }
    }

    /**
     * zählt die Wochen vom übergebenen Datum bis zum gespeicherten Datum
     * ist das übergebene Datum grösser als das gespeicherte, wird ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum, bis zu welchen gezählt werden soll
     * @return Anzahl Wochen
     */
    public int wochenAb(Datum kalender){
        if(istGleich(kalender))
            return 0;
        else{
            float wert = (float)tageAb(kalender) / 7;
            if(wert % 1 != 0)
                if(wert > 0) wert++; else wert--;

            return (int)wert;
        }
    }

    /**
     * Differenz an Wochen zwischen dem übergebenen und dem gespeichertem Datum
     * dieser Wert ist immer positiv oder 0
     *
     * @param kalender Datum bis dessen Differenz an Tagen zum gespeicherten Datum ermittelt werden soll
     * @return Anzahl Wochen - immer positiv oder 0
     */
    public int wochenDiff(Datum kalender) {
        if (istGleich(kalender))
            return 0;
        else {
            float wochen = ((float)tageDiff(kalender) / 7);
            if(wochen %1 != 0)
                wochen++;

            return (int) wochen;
        }

    }

    /**
     * zählt die Monate vom gespeicherten Datum bis zum übergebenen Datum
     * ist das übergebene Datum kleiner als das gespeicherte, wird ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum, bis zu welchen gezählt werden soll
     * @return Anzahl Monate
     */
    public int monateBis(Datum kalender){
        int meinMonat = (getJahr() * 12) + get(Calendar.MONTH);
        int vergleichMonat = (kalender.getJahr() * 12) + kalender.get(Calendar.MONTH);

        return vergleichMonat - meinMonat;
    }

    /**
     * zählt die Monate vom übergebenen Datum bis zum gespeicherten Datum
     * ist das übergebene Datum grösser als das gespeicherte, wird ein negativer Wert zurück gegeben
     *
     * @param kalender das Datum, bis zu welchen gezählt werden soll
     * @return Anzahl Monate
     */
    public int monateAb(Datum kalender){
        int meinMonat = (getJahr() * 12) + get(Calendar.MONTH);
        int vergleichMonat = (kalender.getJahr() * 12) + kalender.get(Calendar.MONTH);

        return meinMonat - vergleichMonat;
    }

    /**
     * Differenz an Monate zwischen dem übergebenen und dem gespeichertem Datum
     * dieser Wert ist immer positiv oder 0
     *
     * @param kalender Datum bis dessen Differenz an Tagen zum gespeicherten Datum ermittelt werden soll
     * @return Anzahl Monate - immer positiv oder 0
     */
    public int monateDiff(Datum kalender){
        int meinMonat = (getJahr() * 12) + get(Calendar.MONTH);
        int vergleichMonat = (kalender.getJahr() * 12) + kalender.get(Calendar.MONTH);
        int monate = vergleichMonat - meinMonat;
        if (monate < 0)
            monate = -monate;

        return monate;
    }


    ////////////// Vergleiche ////////////////////////////

    /**
     * Vergleicht das gespeicherte Datum mit dem übergebenen Datum
     *
     * @param kalender Vergleichdatum
     * @return true wenn das gespeicherte Datum vor dem übergbenen liegt
     */
    public boolean liegtVor(Datum kalender){
        /*
        int meinMonat = (
                get(Calendar.YEAR) << 16) |
                (get(Calendar.MONTH) << 8) |
                get(Calendar.DAY_OF_MONTH);
        int vergleichMonat = (
                kalender.get(Calendar.YEAR) << 16) |
                (kalender.get(Calendar.MONTH) << 8) |
                kalender.get(Calendar.DAY_OF_MONTH);
         */
        return (DatumZuInteger(this) < DatumZuInteger(kalender));
    }

    /**
     * Vergleicht das gespeicherte Datum mit dem übergebenen Datum
     *
     * @param kalender Vergleichdatum
     * @return true wenn das gespeicherte Datum vor dem übergbenen liegt
     */
    public boolean liegtNach(Datum kalender){
        /*
        int meinMonat = (
                get(Calendar.YEAR) << 16) |
                (get(Calendar.MONTH) << 8) |
                get(Calendar.DAY_OF_MONTH);
        int vergleichMonat = (
                kalender.get(Calendar.YEAR) << 16) |
                (kalender.get(Calendar.MONTH) << 8) |
                kalender.get(Calendar.DAY_OF_MONTH);
         */
        return (DatumZuInteger(this) > DatumZuInteger(kalender));
    }

    /**
     * Vergleicht das gespeicherte Datum mit dem übergbenen Datum
     *
     * @param kalender Vergleichdatum
     * @return true wenn beide Datums gleich sind
     */
    public boolean istGleich(Datum kalender) {
        return (DatumZuInteger(this) == DatumZuInteger(kalender));
    }

    /**
     * Vergleicht Teile des übergeben Datums mit den entsprechenden Teilen des gespeicherten Datums
     *
     * @param kalender Vergleichdatum
     * @param periode - Calendar.DAY_OF_MONTH entspricht der Funktion istGleich(Datum kalender)
     *                - Calendar.WEEK_OF_YEAR vergleicht Jahr und Woche
     *                - Calendar.MONTH vergleicht Jahr und Monat
     *                - Calendar.YEAR vergleicht das Jahr
     * @return true wenn beide Perioden übereinstimmen
     */
    public boolean istGleich(Datum kalender, int periode) {
        //boolean isGleich = false;
        switch (periode){
            case Calendar.DAY_OF_MONTH:
                return DatumZuInteger(this) == DatumZuInteger(kalender);
                        /*(kalender.get(Calendar.YEAR) == mKalender.get(Calendar.YEAR))
                        && (kalender.getCalendar().get(Calendar.MONTH) == mKalender.get(Calendar.MONTH))
                        && kalender.get(Calendar.DAY_OF_MONTH) == mKalender.get(Calendar.DAY_OF_MONTH);*/
            case Calendar.WEEK_OF_YEAR :
                return (getJahr() * 100 + getWoche()) == (kalender.getJahr() * 100 + kalender.getWoche());
                        /*kalender.get(Calendar.YEAR) == mKalender.get(Calendar.YEAR)
                        &&  kalender.get(Calendar.WEEK_OF_YEAR) == mKalender.get(Calendar.WEEK_OF_YEAR);*/
            case Calendar.MONTH :
                return (getJahr() * 100 + getMonat()) == (kalender.getJahr() * 100 + kalender.getMonat());
                        /*kalender.get(Calendar.YEAR) == mKalender.get(Calendar.YEAR)
                        && (kalender.getCalendar().get(Calendar.MONTH) == mKalender.get(Calendar.MONTH));*/
            case Calendar.YEAR :
                return getJahr() == kalender.getJahr();
        }
        return false;
        //return isGleich;
    }

    ////////////////// formatierte Datumsstrings /////////////////////////////////////////////////

    /**
     * gibt den Monatsname und das Jahr aus
     * in der Form "Monat Jahr" oder "Monat Jahr/Monat Jahr"
     *
     * @param monatsBeginn Beginn des Abrechnungsmonats, ist dieser grösser als 1 wird "Monat Jahr/Monat Jahr" ausgegeben
     * @param lang soll lange Version der Zeichenkette ausgegeben werden
     * @return Monatsname und Jahr als Zeichenkette
     */
    public String getString_Monat_Jahr(int monatsBeginn, boolean lang){
        String sMonat;
        Datum datum = new Datum(this);

        if (monatsBeginn > 1) {
            // Monatsname zusammenstellen
            SimpleDateFormat dFormat;
            if(datum.getMonat() == DEZEMBER) {
                dFormat = new SimpleDateFormat( lang ? "MMMM yyyy" : "MMM yy", Locale.getDefault());
                sMonat = dFormat.format(datum.getDate());
                sMonat += "/";
            } else {
                dFormat = new SimpleDateFormat(lang ? "MMMM" : "MMM", Locale.getDefault());
                sMonat = dFormat.format(datum.getDate());
                sMonat += "/";
                dFormat = new SimpleDateFormat(lang ? "MMMM yyyy" : "MMM yy", Locale.getDefault());
            }
            datum.add(Calendar.MONTH, 1);
            sMonat += dFormat.format(datum.getDate());
        } else {
            // Monatsname zusammenstellen
            SimpleDateFormat dFormat = new SimpleDateFormat(lang ? "MMMM yyyy" : "MMM yy", Locale.getDefault());
            sMonat = dFormat.format(datum.getDate());
        }

        return sMonat;
    }

    /**
     * gibt die Woche in Form "Woche Jahr" als Zeichenkette aus
     *
     * @return "Woche Jahr" als Zeichenkette
     */
    public String getString_Woche_Jahr(){
        return ASettings.res.getString(
                R.string.woche_jahr,
                getWoche(),
                getJahr()
        );
    }

    /**
     * gibt einen formatierten Datumsstring aus
     *
     * @param context wird benötigt um die lokalen besonderheiten aus dem System zu lesen
     * @param beginn der Tag des Beginns der periode (0= das hinterlegte Datum)
     * @param anzahl Anzahl Perioden (-1= eine komplette Periode, 0= vom Perioden Start bis zum Ende der Periode)
     * @param periode Periode ( Tage, Wochen, Monate etc.)
     * @return Datumsstring in der Form 00.00.0000 - 00.00.0000 angepasst an lokale besonderheiten
     */
    public String getString_Datum_Bereich(@NonNull Context context, int beginn, int anzahl, int periode) {
        java.text.DateFormat dFormat = DateFormat.getDateFormat(context.getApplicationContext());
        String sDatum;
        Calendar datum = Calendar.getInstance();
        datum.setTime(mKalender.getTime());

        // ist kein Starttag festgelegt, mit dem gespeicherten Datum beginnen
        if (beginn > 0) {
            datum.set(periode, beginn);
        }
        sDatum = dFormat.format(datum.getTimeInMillis());
        sDatum += " - ";

        datum.add(periode,
                anzahl < 0 ? (datum.getActualMaximum(periode) - 1) : anzahl
        );
        sDatum += dFormat.format(datum.getTimeInMillis());

        return sDatum;
    }

    /**
     * gibt den Name des Wochentgages aus
     *
     * @param kurz Abgekürzte Version oder ausgeschriebene (Di. oder Dienstag)
     * @return der Wochentag als Zeichenkette
     */
    public String getString_Wochentag(boolean kurz){
        SimpleDateFormat tFormat = new SimpleDateFormat(
                kurz?"EE.":"EEEE", Locale.getDefault());

        return tFormat.format(getDate());
    }

    /**
     * gibt einen formatierten Datumsstring aus
     * in der Regionstypischen Form
     *
     * @param context wird benötigt um die lokalen besonderheiten aus dem System zu lesen
     * @return Datumsstring in der Form 00.00.0000 angepasst an lokale besonderheiten
     */
    public String getString_Datum(Context context) {
        java.text.DateFormat dFormat = DateFormat.getDateFormat(context.getApplicationContext());

        return dFormat.format(getTimeInMillis());
    }

    // Werkzeuge
    private int DatumZuInteger(Datum datum){
       return datum.getJahr() * 10000 + datum.getMonat() * 100 + datum.getTagimMonat();
    }
}
