/* 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.arbeitstag;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.backup.BackupManager;
import android.content.Context;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.MinutenInterpretationDialog;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.abwesenheiten.Abwesenheit;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.Arbeitsschicht;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.SchichtListAdapter;
import askanimus.arbeitszeiterfassung2.einsatzort.Einsatzort;
import askanimus.arbeitszeiterfassung2.einsatzort.EinsatzortAuswahlDialog;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.Bereichsfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzWertAuswahlListe;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzwertAuswahlDialog;
import askanimus.betterpickers.calendardatepicker.CalendarDatePickerDialogFragment;
import askanimus.betterpickers.calendardatepicker.MonthAdapter;
import askanimus.betterpickers.numberpicker.NumberPickerBuilder;
import askanimus.betterpickers.numberpicker.NumberPickerDialogFragment;
import askanimus.betterpickers.radialtimepicker.RadialTimePickerDialogFragment;
import askanimus.betterpickers.timepicker.TimePickerBuilder;
import askanimus.betterpickers.timepicker.TimePickerDialogFragment;


/**
 * @author askanimus@gmail.com on 19.08.15.
 */
public class ArbeitstagFragment
        extends
        Fragment
        implements
        SchichtListAdapter.SchichtListeCallbacks,
        View.OnClickListener,
        NumberPickerDialogFragment.NumberPickerDialogHandlerV2,
        RadialTimePickerDialogFragment.OnTimeSetListener,
        TimePickerDialogFragment.TimePickerDialogHandler,
        EinsatzortAuswahlDialog.EinsatzortAuswahlDialogCallbacks,
        PopupMenu.OnMenuItemClickListener,
        ZusatzwertAuswahlDialog.ZusatzwertAuswahlDialogCallbacks, CalendarDatePickerDialogFragment.OnDateSetListener {
    static int KOPIE_EINZELN = 0;
    static int KOPIE_PERIODE = 1;

    private static final String ARG_JAHR = "jahr";
    private static final String ARG_MONAT = "monat";
    private static final String ARG_TAG = "tag";

    // Aktuell zu haltende Elemente der Anzeige
    private TextView tSoll;
    private TextView tIst;
    private TextView tDifferenz;
    private TextView tStundenlohn;

    // die Variablen der Schichtenliste
    private ListView mListe;
    private SchichtListAdapter myAdapter;

    //Der Rückrufpunkt
    ArbeitstagCallbacks mCallback;
    private ArbeitstagMainCallbacks mCallbackMain;

    //die Daten des angezigten Tages
    private Arbeitstag mTag;


    // die Schicht, in der ein Picker geöffnet ist
    private Arbeitsschicht mEditSchicht;

    // das Zusatzfeld, in welchen ein Picker geöffnet wurde
    private IZusatzfeld mEditZusatzfeld;

    // das Item der Auswahlliste, welches neu angelegt wurde
    private ZusatzWertAuswahlListe.zusatzWertAuswahlItem mAuswahlItemNeu;
    private ZusatzwertAuswahlDialog auswahlDialog;

    // Der Fragmentcontext
    private Context mContext;
    private int kopie_methode = -1;


    /*
     * Neue Instanz anlegen
     */
    public static ArbeitstagFragment newInstance(Datum datum) {
        ArbeitstagFragment fragment = new ArbeitstagFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_JAHR, datum.get(Calendar.YEAR));
        args.putInt(ARG_MONAT, datum.get(Calendar.MONTH));
        args.putInt(ARG_TAG, datum.get(Calendar.DAY_OF_MONTH));
        fragment.setArguments(args);

        return fragment;
    }


    // den Callbackpunkt übergeben
    protected void setUp(ArbeitstagCallbacks cb, /*Context context,*/ ArbeitstagMainCallbacks cm) {
        mCallback = cb;
        mCallbackMain = cm;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        mContext = getContext();
        return inflater.inflate(R.layout.fragment_arbeitstag, container, false);
    }

    @Override
    public void onResume() {
        super.onResume();
        ASettings.init(mContext, this::resume);
    }

    void resume() {
        Bundle mArgs = getArguments();
        if (mArgs != null) {
            Datum mDatum = new Datum(mArgs.getInt(ARG_JAHR), mArgs.getInt(ARG_MONAT), mArgs.getInt(ARG_TAG), ASettings.aktJob.getWochenbeginn());
            mTag = new Arbeitstag(
                    mDatum.getCalendar(),
                    ASettings.aktJob,
                    ASettings.aktJob.getSollstundenTag(mDatum),
                    ASettings.aktJob.getSollstundenTagPauschal(mDatum.get(Calendar.YEAR), mDatum.get(Calendar.MONTH)));
        }

        // Standartelemente finden
        View mInhalt = getView();
        if (mInhalt != null) {
            LinearLayout cDatum = mInhalt.findViewById(R.id.T_box_datum);

            TextView tTagName = mInhalt.findViewById(R.id.T_tag_name);
            TextView tDatum = mInhalt.findViewById(R.id.T_tag_datum);
            TextView tWoche = mInhalt.findViewById(R.id.T_tag_woche);
            tSoll = mInhalt.findViewById(R.id.T_wert_soll);
            tIst = mInhalt.findViewById(R.id.T_wert_ist);
            tDifferenz = mInhalt.findViewById(R.id.T_wert_diff);
            LinearLayout cStundenlohn = mInhalt.findViewById(R.id.T_box_stundenlohn);
            tStundenlohn = mInhalt.findViewById(R.id.T_wert_stundenlohn);
            // Button zum hinzufügen einer Schicht
            ImageView bAddASchicht = mInhalt.findViewById(R.id.T_add_schicht);

            // Button zum zurückspringen in die Monats- oder Wochenansicht
            ImageView bGoMonat = mInhalt.findViewById(R.id.T_go_monat);
            ImageView bGoWoche = mInhalt.findViewById(R.id.T_go_woche);

            //Button zum Schichten in die nächsten Tage zu übertragen
            ImageView bCopyTag = mInhalt.findViewById(R.id.T_copy_tag);

            mListe = mInhalt.findViewById(R.id.T_list_schichten);

            if (mTag != null) {
                switch (mTag.getKalender().get(Calendar.DAY_OF_WEEK)) {
                    case Calendar.SUNDAY:
                        cDatum.setBackgroundColor(ASettings.cHintergrundSo);
                        break;
                    case Calendar.SATURDAY:
                        cDatum.setBackgroundColor(ASettings.cHintergrundSa);
                        break;
                    default:
                        cDatum.setBackgroundColor(ASettings.aktJob.getFarbe_Tag());
                }
                if (!ASettings.isVerdienst)
                    cStundenlohn.setVisibility(View.GONE);


                // Werte eintragen
                SimpleDateFormat dFormat = new SimpleDateFormat("EEEE", Locale.getDefault());
                tTagName.setText(dFormat.format(mTag.getKalender().getDate()));

                tDatum.setText(mTag.getKalender().getString_Datum(mContext));
                tWoche.setText(getString(R.string.woche_nummer, mTag.getKalender().get(Calendar.WEEK_OF_YEAR)));

                // die Schichtenliste einrichten
                myAdapter = new SchichtListAdapter(mContext, mTag, this);
                mListe.setAdapter(myAdapter);

                // Handler für Button zum addieren einer Schicht
                bAddASchicht.setOnClickListener(this);

                // Handler für Go-Buttons
                bGoMonat.setOnClickListener(this);
                bGoWoche.setOnClickListener(this);

                // Handler für den Copy Button
                if (mTag.getKalender().liegtVor(ASettings.letzterAnzeigeTag))
                    bCopyTag.setOnClickListener(this);
                else
                    bCopyTag.setVisibility(View.INVISIBLE);

                updateKopf();
            }
        }
    }

    private void updateKopf() {
        int mSoll = mTag.getTagSollNetto();

        // Nettoarbeitszeit
        Uhrzeit mZeit = new Uhrzeit(mTag.getTagNetto());
        tIst.setText(mZeit.getStundenString(true, ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));

        // Verdienst
        if (ASettings.isVerdienst) {
            tStundenlohn.setText(ASettings.waehrungformat.format(mTag.getTagVerdienst()));
        }

        mZeit.set(mZeit.getAlsMinuten() - mSoll);
        tDifferenz.setText(mZeit.getStundenString(
                true,
                ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL))
        );

        if (mZeit.getAlsMinuten() == 0)
            tDifferenz.setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
        else if (mZeit.getAlsMinuten() < 0)
            tDifferenz.setTextColor(ASettings.cNegativText);
        else
            tDifferenz.setTextColor(ASettings.cPositivText);

        //Sollstunden
        mZeit.set(mSoll);
        tSoll.setText(mZeit.getStundenString(true, ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));

    }

    /*
     * Rückmeldung vom Schichtenadapter das eine Änderung erfolgte
     */
    @Override
    public void onSchichtChanged(long schicht) {
        // die Werte des Tages updaten
        mTag.updateSchicht(schicht);
        updateKopf();
        // den Monat anpassen
        if (mCallback != null)
            mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
        // Schichtliste neu aufbauen
        myAdapter.notifyDataSetChanged();
    }

    @Override
    public void onSchichtOpenPicker(Arbeitsschicht schicht, int wert) {
        final FragmentManager fManager;
        try {
            fManager = getParentFragmentManager();
            switch (wert) {
                case Arbeitsschicht.WERT_STUNDEN:
                    mEditSchicht = schicht;
                    //if (Einstellungen.mPreferenzen.getBoolean(Einstellungen.KEY_ANZEIGE_DEZIMAL, true)) {
                    if (ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)) {
                        NumberPickerBuilder stundenPicker = new NumberPickerBuilder()
                                .setFragmentManager(fManager)
                                .setStyleResId(ASettings.themePicker)
                                .setMinNumber(BigDecimal.valueOf(0))
                                .setMaxNumber(BigDecimal.valueOf(24))
                                .setLabelText(getString(R.string.k_stunde))
                                .setPlusMinusVisibility(View.INVISIBLE)
                                .setDecimalVisibility(View.VISIBLE)
                                .setReference(wert)
                                .setTargetFragment(this);
                        stundenPicker.show();
                    } else {
                        TimePickerBuilder stundenPicker = new TimePickerBuilder()
                                .setFragmentManager(fManager)
                                .setTargetFragment(this)
                                .setReference(wert)
                                .setStyleResId(ASettings.themePicker)
                                .addTimePickerDialogHandler(this);
                        stundenPicker.show();
                    }
                    break;
                case Arbeitsschicht.WERT_PROZENT:
                    mEditSchicht = schicht;
                    NumberPickerBuilder prozentPicker = new NumberPickerBuilder()
                            .setFragmentManager(fManager)
                            .setStyleResId(ASettings.themePicker)
                            .setMinNumber(BigDecimal.valueOf(0))
                            .setMaxNumber(BigDecimal.valueOf(100))
                            .setLabelText("%")
                            .setPlusMinusVisibility(View.INVISIBLE)
                            .setDecimalVisibility(View.INVISIBLE)
                            .setReference(wert)
                            .setTargetFragment(this);
                    prozentPicker.show();
                    break;
                case Arbeitsschicht.WERT_VON:
                    mEditSchicht = schicht;
                    Uhrzeit mZeitVon = new Uhrzeit(mEditSchicht.getVon());
                    /*
                     * Wenn die Zeit am aktuellen Tag, in der Nähe (+- 2 Stunden)
                     * der eingetragenen Zeit verändert werden soll,
                     * wird die aktuelle Zeit im Dialog eingestellt
                     */
                    if (mTag.getKalender().istGleich(ASettings.aktDatum)) {
                        Calendar now = Calendar.getInstance();
                        int h_now = now.get(Calendar.HOUR_OF_DAY);
                        int h_get = mZeitVon.getStunden();
                        if (h_now >= (h_get - 2) && h_now <= (h_get + 2)) {
                            mZeitVon.set(h_now, now.get(Calendar.MINUTE));
                        }
                    }
                    RadialTimePickerDialogFragment vonPickerDialog =
                            new RadialTimePickerDialogFragment()
                                    .setOnTimeSetListener(this)
                                    .setStartTime(
                                            mZeitVon.getStunden(),
                                            mZeitVon.getMinuten());
                    if (ASettings.isThemaDunkel)
                        vonPickerDialog.setThemeDark();
                    else
                        vonPickerDialog.setThemeLight();
                    vonPickerDialog.show(fManager, String.valueOf(wert));
                    break;
                case Arbeitsschicht.WERT_BIS:
                    mEditSchicht = schicht;
                    Uhrzeit mZeitBis = new Uhrzeit(mEditSchicht.getBis());
                    /*
                     * Wenn die Zeit am aktuellen Tag, in der Nähe (+- 2 Stunden)
                     * der eingetragenen Zeit verändert werden soll,
                     * wird die aktuelle Zeit im Dialog eingestellt
                     */
                    if (mTag.getKalender().istGleich(ASettings.aktDatum)) {
                        Calendar now = Calendar.getInstance();
                        int h_now = now.get(Calendar.HOUR_OF_DAY);
                        int h_get = mZeitBis.getStunden();
                        if (h_now >= (h_get - 2) && h_now <= (h_get + 2)) {
                            mZeitBis.set(h_now, now.get(Calendar.MINUTE));
                        }
                    }
                    RadialTimePickerDialogFragment bisPickerDialog =
                            new RadialTimePickerDialogFragment()
                                    .setOnTimeSetListener(this)
                                    .setStartTime(
                                            mZeitBis.getStunden(),
                                            mZeitBis.getMinuten());
                    if (ASettings.isThemaDunkel)
                        bisPickerDialog.setThemeDark();
                    else
                        bisPickerDialog.setThemeLight();
                    bisPickerDialog.show(fManager, String.valueOf(wert));
                    break;
                case Arbeitsschicht.WERT_PAUSE:
                    mEditSchicht = schicht;
                    if (ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)) {
                        NumberPickerBuilder pausePicker = new NumberPickerBuilder()
                                .setFragmentManager(fManager)
                                .setStyleResId(ASettings.themePicker)
                                .setMinNumber(BigDecimal.valueOf(0))
                                .setLabelText(getString(R.string.k_stunde))
                                .setPlusMinusVisibility(View.INVISIBLE)
                                .setDecimalVisibility(View.VISIBLE)
                                .setReference(wert)
                                .setTargetFragment(this);
                        pausePicker.show();
                    } else {
                        TimePickerBuilder tpb = new TimePickerBuilder()
                                .setFragmentManager(fManager)
                                .setTargetFragment(this)
                                .setReference(wert)
                                .setStyleResId(ASettings.themePicker)
                                .addTimePickerDialogHandler(this);
                        tpb.show();
                    }
                    break;
                case Arbeitsschicht.WERT_EORT:
                    mEditSchicht = schicht;
                    new EinsatzortAuswahlDialog(
                            mContext,
                            this,
                            schicht.getArbeitsplatz(),
                            mTag.getKalender().getTimeInMillis()
                    ).open();
                    break;
            }
        } catch (IllegalStateException ignore) {
        }
    }

    @Override
    public void onZusatzfeldOpenPicker(IZusatzfeld feld, int wert) {
        final FragmentManager fManager;
        try {
            fManager = getParentFragmentManager();
            switch (wert) {
                case Arbeitsschicht.WERT_ZUSATZ_PROZENT:
                case Arbeitsschicht.WERT_ZUSATZ_ZAHL:
                case Arbeitsschicht.WERT_ZUSATZ_ZAHL_VON:
                case Arbeitsschicht.WERT_ZUSATZ_ZAHL_BIS:
                    mEditZusatzfeld = feld;
                    NumberPickerBuilder nPicker = new NumberPickerBuilder()
                            .setFragmentManager(fManager)
                            .setStyleResId(ASettings.themePicker)
                            .setMinNumber(BigDecimal.valueOf(0))
                            .setLabelText(feld.getEinheit())
                            .setPlusMinusVisibility(View.INVISIBLE)
                            .setDecimalVisibility(View.VISIBLE)
                            .setReference(wert)
                            .setTargetFragment(this);
                    nPicker.show();
                    break;
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT:
                    mEditZusatzfeld = feld;
                    if (ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)) {
                        NumberPickerBuilder zPicker = new NumberPickerBuilder()
                                .setFragmentManager(fManager)
                                .setStyleResId(ASettings.themePicker)
                                .setMinNumber(BigDecimal.valueOf(0))
                                .setMaxNumber(BigDecimal.valueOf(24))
                                .setLabelText(feld.getEinheit())
                                .setPlusMinusVisibility(View.INVISIBLE)
                                .setDecimalVisibility(View.VISIBLE)
                                .setReference(wert)
                                .setTargetFragment(this);
                        zPicker.show();
                    } else {
                        TimePickerBuilder zPicker = new TimePickerBuilder()
                                .setFragmentManager(fManager)
                                .setTargetFragment(this)
                                .setReference(wert)
                                .setStyleResId(ASettings.themePicker)
                                .addTimePickerDialogHandler(this);
                        zPicker.show();
                    }
                    break;
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON:
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS:
                    int w;
                    if (wert == Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON) {
                        w = (int) ((Bereichsfeld) feld).getVon().getWert();
                    } else {
                        w = (int) ((Bereichsfeld) feld).getBis().getWert();
                    }
                    mEditZusatzfeld = feld;
                    Uhrzeit mZeit = new Uhrzeit(w);
                    RadialTimePickerDialogFragment zusatzPickerDialog =
                            new RadialTimePickerDialogFragment()
                                    .setOnTimeSetListener(this)
                                    .setStartTime(
                                            mZeit.getStunden(),
                                            mZeit.getMinuten());
                    if (ASettings.isThemaDunkel)
                        zusatzPickerDialog.setThemeDark();
                    else
                        zusatzPickerDialog.setThemeLight();
                    zusatzPickerDialog.show(fManager, String.valueOf(wert));
                    break;
                case Arbeitsschicht.WERT_ZUSATZ_AUSWAHL:
                    mEditZusatzfeld = feld;
                    auswahlDialog = new ZusatzwertAuswahlDialog(mContext, this, feld, mTag.getArbeitsplatz());
                    auswahlDialog.open();
                    break;
            }
        } catch (IllegalStateException ignore) {
        }
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.T_add_schicht) {
            if (mTag.getSchichtAnzahl() < ASettings.aktJob.getAnzahlSchichtenTag()) {
                mTag.addSchicht(
                        -1,
                        ASettings.aktJob.getDefaultSchichten().getAktive(mTag.getSchichtAnzahl())
                );
                updateKopf();
                mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                myAdapter.notifyDataSetChanged();
            } else {
                final InputMethodManager imm =
                        (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                final EditText input = new EditText(mContext);
                input.setText(mContext.getString(R.string.schicht_nr, mTag.getSchichtAnzahl() + 1));
                input.setInputType(InputType.TYPE_CLASS_TEXT);
                input.setSelection(0, input.getText().length());
                input.setFocusableInTouchMode(true);
                input.requestFocus();
                input.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
                //Längenbegrenzung des Inputstrings
                InputFilter[] fa = new InputFilter[1];
                fa[0] = new InputFilter.LengthFilter(ISettings.LAENGE_NAME);
                input.setFilters(fa);
                new android.app.AlertDialog.Builder(mContext)
                        .setTitle(mContext.getString(R.string.schichtname))
                        .setView(input)
                        .setPositiveButton(mContext.getString(android.R.string.ok), (dialog, whichButton) -> {
                            if (imm != null) {
                                imm.hideSoftInputFromWindow(input.getWindowToken(), 0);
                            }
                            mTag.addSchicht(-1, input.getText().toString());
                            //Schicht als Arbeitszeit Vorbelegen
                            mTag.getSchicht(
                                            mTag.getSchichtAnzahl() - 1)
                                    .setAbwesenheit(
                                            ASettings.aktJob
                                                    .getAbwesenheiten()
                                                    .getAktive(Abwesenheit.ARBEITSZEIT),
                                            0
                                    );
                            if (mTag.getSchicht(mTag.getSchichtAnzahl() - 2).getAbwesenheit().getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                                mTag.getSchicht(mTag.getSchichtAnzahl() - 1).setVon(mTag.getSchicht(mTag.getSchichtAnzahl() - 2).getBis());
                                mTag.getSchicht(mTag.getSchichtAnzahl() - 1).setBis(mTag.getSchicht(mTag.getSchichtAnzahl() - 1).getVon() + 120);
                            } else {
                                Calendar mKalender = Calendar.getInstance();
                                mKalender.setTime(new Date());
                                Uhrzeit mZeit = new Uhrzeit(mKalender.get(Calendar.HOUR_OF_DAY), mKalender.get(Calendar.MINUTE));
                                mTag.getSchicht(mTag.getSchichtAnzahl() - 1).setVon(mZeit.getAlsMinuten());
                                mTag.getSchicht(mTag.getSchichtAnzahl() - 1).setBis(mTag.getSchicht(mTag.getSchichtAnzahl() - 1).getVon() + 240);
                            }
                            updateKopf();
                            mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                            myAdapter.notifyDataSetChanged();
                        }).setNegativeButton(mContext.getString(android.R.string.cancel), (dialog, whichButton) -> {
                            // die Tatstatur ausblenden
                            if (imm != null) {
                                imm.hideSoftInputFromWindow(input.getWindowToken(), 0);
                            }
                        }).show();
                if (imm != null) {
                    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                }
            }
            mListe.smoothScrollToPosition(mListe.getMaxScrollAmount());
        } else if (id == R.id.T_go_woche) {
            mCallbackMain.onArbeitstagGoback(ISettings.VIEW_WOCHE, mTag.getKalender());
        } else if (id == R.id.T_go_monat) {
            mCallbackMain.onArbeitstagGoback(ISettings.VIEW_MONAT, mTag.getKalender());
        } else if (id == R.id.T_copy_tag) {
            PopupMenu popup = new PopupMenu(mContext, v);
            MenuInflater inflater = popup.getMenuInflater();
            inflater.inflate(R.menu.kopie, popup.getMenu());
            popup.setOnMenuItemClickListener(this);
            popup.show();
        }
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        int itemId = item.getItemId();
        if (itemId == R.id.k_einzeln) {
            //mCallback.onArbeitstagCopy(mTag.getKalender(), ArbeitstagPager.KOPIE_EINZELN);
            if (mTag != null) {
                kopie_methode = KOPIE_EINZELN;
                Datum zielTag = new Datum(mTag.getKalender());
                zielTag.add(Calendar.DAY_OF_MONTH, 1);

                CalendarDatePickerDialogFragment bisKalenderPicker =
                        new CalendarDatePickerDialogFragment()
                                .setOnDateSetListener(this)
                                .setFirstDayOfWeek(ASettings.aktJob.getWochenbeginn())
                                .setPreselectedDate(
                                        zielTag.get(Calendar.YEAR),
                                        zielTag.get(Calendar.MONTH) - 1,
                                        zielTag.get(Calendar.DAY_OF_MONTH));
                bisKalenderPicker.setDateRange(
                        new MonthAdapter.CalendarDay(
                                zielTag.get(Calendar.YEAR),
                                zielTag.get(Calendar.MONTH) - 1,
                                zielTag.get(Calendar.DAY_OF_MONTH)),
                        new MonthAdapter.CalendarDay(
                                ASettings.letzterAnzeigeTag.get(Calendar.YEAR),
                                ASettings.letzterAnzeigeTag.get(Calendar.MONTH) - 1,
                                ASettings.letzterAnzeigeTag.get(Calendar.DAY_OF_MONTH)));
                if (ASettings.isThemaDunkel)
                    bisKalenderPicker.setThemeDark();
                else
                    bisKalenderPicker.setThemeLight();
                FragmentManager fManager;
                try {
                    fManager = getParentFragmentManager();
                    bisKalenderPicker.show(fManager, getString(R.string.ende_titel));
                } catch (IllegalStateException ignore) {
                }
                return true;
            }
        } else if (itemId == R.id.k_periode) {
            //mCallback.onArbeitstagCopy(mTag.getKalender(), ArbeitstagPager.KOPIE_PERIODE);
            kopie_methode = KOPIE_PERIODE;
            Datum zielTag = new Datum(mTag.getKalender());
            zielTag.add(Calendar.DAY_OF_MONTH, 1);

            CalendarDatePickerDialogFragment bisKalenderPicker =
                    new CalendarDatePickerDialogFragment()
                            .setOnDateSetListener(this)
                            .setFirstDayOfWeek(ASettings.aktJob.getWochenbeginn())
                            .setPreselectedDate(
                                    zielTag.get(Calendar.YEAR),
                                    zielTag.get(Calendar.MONTH) - 1,
                                    zielTag.get(Calendar.DAY_OF_MONTH));
            bisKalenderPicker.setDateRange(
                    new MonthAdapter.CalendarDay(
                            zielTag.get(Calendar.YEAR),
                            zielTag.get(Calendar.MONTH) - 1,
                            zielTag.get(Calendar.DAY_OF_MONTH)),
                    new MonthAdapter.CalendarDay(
                            ASettings.letzterAnzeigeTag.get(Calendar.YEAR),
                            ASettings.letzterAnzeigeTag.get(Calendar.MONTH) - 1,
                            ASettings.letzterAnzeigeTag.get(Calendar.DAY_OF_MONTH)));
            if (ASettings.isThemaDunkel)
                bisKalenderPicker.setThemeDark();
            else
                bisKalenderPicker.setThemeLight();
            FragmentManager fManager;
            try {
                fManager = getParentFragmentManager();
                bisKalenderPicker.show(fManager, getString(R.string.ende_titel));
            } catch (IllegalStateException ignore) {
            }

            return true;
        }
        return false;
    }


    @Override
    public void onDialogNumberSet(final int reference, final BigInteger number, final double decimal, boolean isNegative, BigDecimal fullNumber) {
        MinutenInterpretationDialog.MinutenInterpretationDialogListener mListener = null;

        switch (reference) {
            case Arbeitsschicht.WERT_PROZENT:
                if (mEditSchicht != null) {
                    mEditSchicht.setBis(number.intValue());
                    onSchichtChanged(mEditSchicht.getID());
                    mEditSchicht = null;
                }
                break;
            case Arbeitsschicht.WERT_PAUSE:
                if (mEditSchicht != null) {
                    mListener = z -> {
                        mEditSchicht.setPause(z.getAlsMinuten());
                        onSchichtChanged(mEditSchicht.getID());
                        mEditSchicht = null;
                    };
                }
                break;
            case Arbeitsschicht.WERT_STUNDEN:
                if (mEditSchicht != null) {
                    mListener = z -> {
                        mEditSchicht.setBis(z.getAlsMinuten());
                        onSchichtChanged(mEditSchicht.getID());
                        mEditSchicht = null;
                    };
                }
                break;
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT:
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON:
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS:
                if (mEditZusatzfeld != null) {
                    final IZusatzfeld feld;
                    if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getVon();
                    } else if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getBis();
                    } else {
                        feld = mEditZusatzfeld;
                    }
                    mListener = z -> {
                        feld.setWert(z.getAlsMinuten());
                        mEditZusatzfeld.save(false);
                        // das neu angelegte Auswahlitem mit dem neuen Wert versehen und speichern
                        if (mAuswahlItemNeu != null) {
                            mAuswahlItemNeu.setWert(mEditZusatzfeld);
                            mAuswahlItemNeu = null;
                        }
                        mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                        updateKopf();
                        myAdapter.notifyDataSetChanged();
                        mEditZusatzfeld = null;
                    };
                }
                break;
            case Arbeitsschicht.WERT_ZUSATZ_PROZENT:
            case Arbeitsschicht.WERT_ZUSATZ_ZAHL:
            case Arbeitsschicht.WERT_ZUSATZ_ZAHL_VON:
            case Arbeitsschicht.WERT_ZUSATZ_ZAHL_BIS:
                if (mEditZusatzfeld != null) {
                    IZusatzfeld feld = mEditZusatzfeld;
                    if (reference == Arbeitsschicht.WERT_ZUSATZ_ZAHL_VON) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getVon();
                    } else if (reference == Arbeitsschicht.WERT_ZUSATZ_ZAHL_BIS) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getBis();
                    }
                    feld.setWert(fullNumber.floatValue());
                    mEditZusatzfeld.save(false);
                    // das neu angelegte Auswahlitem mit dem neuen Wert versehen und speichern
                    if (mAuswahlItemNeu != null) {
                        mAuswahlItemNeu.setWert(mEditZusatzfeld);
                        mAuswahlItemNeu = null;
                    }
                    mEditZusatzfeld = null;
                    updateKopf();
                    myAdapter.notifyDataSetChanged();
                    mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                }
                break;
        }

        if (mListener != null) {
            new MinutenInterpretationDialog(
                    mContext,
                    ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL),
                    /*number,*/
                    decimal,
                    fullNumber,
                    mListener
            );
        }
    }

    @Override
    public void onTimeSet(RadialTimePickerDialogFragment dialog, int hourOfDay, int minute) {
        String dTag = dialog.getTag();
        if (dTag != null) {
            int reference = Integer.parseInt(dTag);
            switch (reference) {
                case Arbeitsschicht.WERT_VON:
                    if (mEditSchicht != null) {
                        mEditSchicht.setVon(Uhrzeit.makeMinuten(hourOfDay, minute));
                        onSchichtChanged(mEditSchicht.getID());
                        mEditSchicht = null;
                    }
                    break;
                case Arbeitsschicht.WERT_BIS:
                    if (mEditSchicht != null) {
                        mEditSchicht.setBis(Uhrzeit.makeMinuten(hourOfDay, minute));
                        onSchichtChanged(mEditSchicht.getID());
                        mEditSchicht = null;
                    }
                    break;
                case Arbeitsschicht.WERT_PAUSE:
                    if (mEditSchicht != null) {
                        mEditSchicht.setPause(Uhrzeit.makeMinuten(hourOfDay, minute));
                        onSchichtChanged(mEditSchicht.getID());
                        mEditSchicht = null;
                    }
                    break;
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT:
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON:
                case Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS:
                    if (mEditZusatzfeld != null) {
                        IZusatzfeld feld = mEditZusatzfeld;
                        if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON) {
                            feld = ((Bereichsfeld) mEditZusatzfeld).getVon();
                        } else if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS) {
                            feld = ((Bereichsfeld) mEditZusatzfeld).getBis();
                        }
                        feld.setWert(Uhrzeit.makeMinuten(hourOfDay, minute));
                        mEditZusatzfeld.save(false);
                        // das neu angelegte Auswahlitem mit dem neuen Wert versehen und speichern
                        if (mAuswahlItemNeu != null) {
                            mAuswahlItemNeu.setWert(mEditZusatzfeld);
                            mAuswahlItemNeu = null;
                        }
                        mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                        myAdapter.notifyDataSetChanged();
                        mEditZusatzfeld = null;
                        updateKopf();
                    }
            }
        }
    }

    @Override
    public void onDialogTimeSet(int reference, int hourOfDay, int minute) {
        switch (reference) {
            case Arbeitsschicht.WERT_PAUSE:
                if (mEditSchicht != null) {
                    mEditSchicht.setPause(Uhrzeit.makeMinuten(hourOfDay, minute));
                    onSchichtChanged(mEditSchicht.getID());
                    mEditSchicht = null;
                }
                break;
            case Arbeitsschicht.WERT_STUNDEN:
                if (mEditSchicht != null) {
                    mEditSchicht.setBis(Uhrzeit.makeMinuten(hourOfDay, minute));
                    onSchichtChanged(mEditSchicht.getID());
                    mEditSchicht = null;
                }
                break;
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT:
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON:
            case Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS:
                if (mEditZusatzfeld != null) {
                    IZusatzfeld feld = mEditZusatzfeld;
                    if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_VON) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getVon();
                    } else if (reference == Arbeitsschicht.WERT_ZUSATZ_ZEIT_BIS) {
                        feld = ((Bereichsfeld) mEditZusatzfeld).getBis();
                    }
                    feld.setWert(Uhrzeit.makeMinuten(hourOfDay, minute));
                    mEditZusatzfeld.save(false);
                    // das neu angelegte Auswahlitem mit dem neuen Wert versehen und speichern
                    if (mAuswahlItemNeu != null) {
                        mAuswahlItemNeu.setWert(mEditZusatzfeld);
                        mAuswahlItemNeu = null;
                    }
                    mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
                    myAdapter.notifyDataSetChanged();
                    mEditZusatzfeld = null;
                    updateKopf();
                }
        }
    }

    @Override
    public void onEinsatzortSet(Einsatzort eort) {
        mEditSchicht.setEinsatzort(eort);
        myAdapter.notifyDataSetChanged();
    }

    @Override
    public void onZusatzwertSet(IZusatzfeld wert) {
        if (mEditZusatzfeld != null) {
            mEditZusatzfeld.set(wert);
            mEditZusatzfeld.save(false);
            mCallback.onArbeitstagDatenChanged(mTag.getKalender(), null);
            myAdapter.notifyDataSetChanged();
            mEditZusatzfeld = null;
            updateKopf();
        }
    }

    @Override
    public void onZusatzwertAdd(IZusatzfeld feld, ZusatzWertAuswahlListe.zusatzWertAuswahlItem eintragNeu) {
        switch (feld.getDatenTyp()) {
            case IZusatzfeld.TYP_AUSWAHL_ZAHL:
                mAuswahlItemNeu = eintragNeu;
                onZusatzfeldOpenPicker(feld, Arbeitsschicht.WERT_ZUSATZ_ZAHL);
                break;
            case IZusatzfeld.TYP_AUSWAHL_PROZENT:
                mAuswahlItemNeu = eintragNeu;
                onZusatzfeldOpenPicker(feld, Arbeitsschicht.WERT_ZUSATZ_PROZENT);
                break;
            case IZusatzfeld.TYP_AUSWAHL_ZEIT:
                mAuswahlItemNeu = eintragNeu;
                onZusatzfeldOpenPicker(feld, Arbeitsschicht.WERT_ZUSATZ_ZEIT);
                break;
            default:
                final InputMethodManager imm =
                        (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                final EditText mInput = new EditText(mContext);
                mInput.setText("");
                mInput.setFocusableInTouchMode(true);
                mInput.setInputType(
                        InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
                                | InputType.TYPE_CLASS_TEXT
                                | InputType.TYPE_TEXT_FLAG_MULTI_LINE
                );

                //Längenbegrenzung des Inputstrings
                InputFilter[] fa = new InputFilter[1];
                fa[0] = new InputFilter.LengthFilter(ISettings.LAENGE_NOTIZ);
                mInput.setFilters(fa);

                new AlertDialog.Builder(mContext)
                        .setTitle(feld.getName())
                        .setView(mInput)
                        .setPositiveButton(
                                mContext.getString(android.R.string.ok),
                                (dialog, whichButton) -> {
                                    if (whichButton == Dialog.BUTTON_POSITIVE) {
                                        // ein neues leeres Zusatzfeld anlegen
                                        IZusatzfeld feldNeu = feld.getDefinition().makeNewZusatzfeld();
                                        // den neuen Wert eintragen
                                        feldNeu.setWert(mInput.getText().toString());
                                        // das neu angelegte Auswahlitem mit dem neuen Wert versehen und speichern
                                        eintragNeu.setWert(feldNeu);
                                        // die Auswahlliste erweitern
                                        auswahlDialog.addWert(eintragNeu);
                                        //mCallback.onArbeitstagDatenChanged(mTag.getKalender());
                                        //myAdapter.notifyDataSetChanged();
                                        if (imm != null) {
                                            imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
                                        }
                                    }
                                }).setNegativeButton(
                                mContext.getString(android.R.string.cancel),
                                (dialog, whichButton) -> {
                                    // Abbruchknopf gedrückt
                                    if (imm != null) {
                                        imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
                                    }
                                }).show();

                mInput.requestFocus();
                if (imm != null) {
                    imm.toggleSoftInputFromWindow(
                            mInput.getWindowToken(),
                            InputMethodManager.SHOW_FORCED,
                            0
                    );
                }

        }
    }

    @Override
    public void onDateSet(CalendarDatePickerDialogFragment dialog, int year, int monthOfYear, int dayOfMonth) {
        final Datum datVon = new Datum(mTag.getKalender());
        final Datum datBis = new Datum(year, monthOfYear + 1, dayOfMonth, ASettings.aktJob.getWochenbeginn());

        if (kopie_methode == KOPIE_PERIODE) {
            kopie_methode = -1;
            new AlertDialog.Builder(mContext)
                    .setTitle(getString(R.string.dialog_tage_kopie_periode))
                    .setMessage(getString(R.string.dialog_tage_kopie_frage_periode,
                            datVon.getString_Datum(mContext),
                            datBis.getString_Datum(mContext)))
                    .setPositiveButton(getString(android.R.string.yes), (dialog1, whichButton) -> {
                        // Anzahl Tage die kopiert werden
                        int mTage = datVon.tageBis(datBis);

                        datVon.add(Calendar.DAY_OF_MONTH, 1);
                        //Datum datErsterZieltag = new Datum(datVon);

                        mTag.copy(datVon);
                        //Aktion ausführen
                        while (datVon.liegtVor(datBis)) {
                            datVon.add(Calendar.DAY_OF_MONTH, 1);
                            mTag.copy(datVon);
                        }
                        mCallback.onScrollTage(mTage);
                        //AUpdateDatenbank.updateDatenbank(requireActivity(), mTag.getArbeitsplatz());
                        //requestBackup();
                    })
                    .setNegativeButton(getString(android.R.string.no), (dialog14, whichButton) -> {
                        // Nichts tun, nur den Dialog schliessen.
                    }).show();
        } else if (kopie_methode == KOPIE_EINZELN) {
            kopie_methode = -1;
            new AlertDialog.Builder(mContext)
                    .setTitle(getString(R.string.dialog_tage_kopie_einzel))
                    .setMessage(getString(R.string.dialog_tage_kopie_frage_einzel,
                            datVon.getString_Datum(mContext),
                            datBis.getString_Datum(mContext)))
                    .setPositiveButton(getString(android.R.string.yes), (dialog1, whichButton) -> {
                        // Anzahl Tage die kopiert werden
                        int mTage = datVon.tageBis(datBis);
                        // Tag in Zieltag kopieren
                        mTag.copy(datBis);
                        mCallback.onScrollTage(mTage);
                        //AUpdateDatenbank.updateDatenbank(requireActivity(), mTag.getArbeitsplatz());
                        //requestBackup();
                    })
                    .setNegativeButton(getString(android.R.string.no), (dialog14, whichButton) -> {
                        // Nichts tun, nur den Dialog schliessen.
                    }).show();

            //AUpdateDatenbank.updateDatenbank(requireActivity(), mTag.getArbeitsplatz());
        }
    }

    /// ////////////////////////////////////////////////////////////////////////////////////////////
    // Callback interface zum Pager //////////////////////////////////////////////////////////////
    public interface ArbeitstagCallbacks {
        /**
         * Aufgerufen wenn sich Werte des Tages geändert haben
         */
        void onArbeitstagDatenChanged(Datum tagStart, Datum tagEnd);
        void onScrollTage(int tage);

        //void onArbeitstagCopy(Datum tag, int methode);
    }

    // Callbacks zur Mainactivity
    public interface ArbeitstagMainCallbacks {
        void onArbeitstagGoback(int ansicht, Datum tag);
    }

}
