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

import android.app.ProgressDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.appcompat.widget.AppCompatRadioButton;
import androidx.appcompat.widget.AppCompatSpinner;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.view.ViewCompat;
import androidx.core.widget.CompoundButtonCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Objects;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.StorageHelper;
import askanimus.arbeitszeiterfassung2.Zeitraum.Zeitraum_Frei;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.einsatzort.Einsatzort;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.betterpickers.calendardatepicker.CalendarDatePickerDialogFragment;
import askanimus.betterpickers.calendardatepicker.MonthAdapter;
import askanimus.betterpickers.numberpicker.NumberPickerBuilder;
import askanimus.betterpickers.numberpicker.NumberPickerDialogFragment;

/**
 * @author askanimus@gmail.com on 09.01.16.
 */
public class Export_Fragment_Einsatzort
        extends
        Fragment
        implements
        IExport_Fragment,
        View.OnClickListener,
        CalendarDatePickerDialogFragment.OnDateSetListener,
        CompoundButton.OnCheckedChangeListener,
        RadioGroup.OnCheckedChangeListener,
        Fragment_Dialog_Spalten.EditSpaltenDialogListener,
        Fragment_Dialog_Zeilen.EditZeilenDialogListener,
        AdapterView.OnItemSelectedListener,
        NumberPickerDialogFragment.NumberPickerDialogHandlerV2,
        MultiSelectSpinner.OnMultiSelectedListener {

    private BitSet bsSpalten;
    private BitSet bsSpaltenDeaktiv;
    private BitSet bsOptionen;
    private BitSet bsOptionenDeaktiv;
    private BitSet bsZusatzfelder;
    private String KEY_EXP_EO_SPALTEN;
    private String KEY_EXP_EO_ZEILEN;
    private String KEY_EXP_EO_ZUSATZ;

    private int exportDateityp;

    private Datum kStarttag;
    private Datum kEndtag;
    private int mAnzahlTage;
    private int mAnzahlBerichte = 1;

    private static IExportFinishListener mCallback;

    private LinearLayout bAuswahl;
    private RadioGroup rgGroesse;
    private RadioGroup rgLayout;

    private TextView wBeginn;
    private TextView wEnde;
    private TextView wAnzahlBerichte;
    private TextView wNachwort;

    private TextView wTrenner;
    private LinearLayout bTrenner;

    private TextView wNotiz;
    private LinearLayout bNotiz;
    private AppCompatCheckBox cbZusammen;

    private SwitchCompat swTabelleJeOrt;
    private TextView titelSpinnerEinastzorte;
    private MultiSelectSpinner spinnerEinastzorte;


    private ArrayList<MultiSelectItem> listeEinsatzorte;
    private Context mContext;

    /**
     * Gibt eine neue Instance des Fragments zurück
     */
    public static Export_Fragment_Einsatzort newInstance(IExportFinishListener cb, long startdatun) {
        mCallback = cb;
        Export_Fragment_Einsatzort fragment = new Export_Fragment_Einsatzort();
        Bundle args = new Bundle();
        args.putLong(ISettings.ARG_DATUM, startdatun);
        fragment.setArguments(args);
        return fragment;
    }


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

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

    private void resume() {
        Bundle mArgs = getArguments();
        if (mArgs != null)
            kStarttag = new Datum(mArgs.getLong(ISettings.ARG_DATUM), ASettings.aktJob.getWochenbeginn());
        else
            kStarttag = new Datum(ASettings.aktDatum.getDate(), ASettings.aktJob.getWochenbeginn());

        kEndtag = new Datum(kStarttag);
        kEndtag.add(Calendar.DAY_OF_MONTH, kStarttag.getAktuellMaximum(Calendar.DAY_OF_MONTH) - 1);
        if (kEndtag.liegtNach(ASettings.letzterAnzeigeTag))
            kEndtag.set(ASettings.letzterAnzeigeTag.getCalendar());

        if(kStarttag.liegtNach(kEndtag)){
            kStarttag.set(kEndtag.getCalendar());
            kStarttag.setTag(ASettings.aktJob.getMonatsbeginn());
        }

        // der Dateityp CSV oder PDF
        // bis zur Version 10291 war für alle Exporte nur ein gemeinsamer Dateityp gespeichert
        exportDateityp = ASettings.mPreferenzen.getInt(ISettings.KEY_EXP_TYP_EORT, ASettings.mPreferenzen.getInt(ISettings.KEY_EXP_TYP, IExport_Basis.TYP_PDF));

        View rootView = getView();
        if (rootView != null) {
            // die einzelnen Bedienelemente finden
            wBeginn = rootView.findViewById(R.id.EO_wert_von);
            wEnde = rootView.findViewById(R.id.EO_wert_bis);
            wAnzahlBerichte = rootView.findViewById(R.id.EO_wert_anzahl);
            wNachwort = rootView.findViewById(R.id.EO_nachwort);
            wTrenner = rootView.findViewById(R.id.EO_wert_trenner);
            bTrenner = rootView.findViewById(R.id.EO_box_trenner);
            rgGroesse = rootView.findViewById(R.id.EO_gruppe_groesse);
            rgLayout = rootView.findViewById(R.id.EO_gruppe_layout);
            wNotiz = rootView.findViewById(R.id.EO_wert_notiz);
            bNotiz = rootView.findViewById(R.id.EO_box_notiz);
            bAuswahl = rootView.findViewById(R.id.EO_box_auswahl);
            cbZusammen = rootView.findViewById(R.id.EO_button_zus);
            RadioGroup rgDateityp = rootView.findViewById(R.id.EO_gruppe_typ);
            SwitchCompat swAllJobs = rootView.findViewById(R.id.EO_switch_all_jobs);
            SwitchCompat swNurOrte = rootView.findViewById(R.id.EO_switch_nur_orte);
            swTabelleJeOrt = rootView.findViewById(R.id.EO_switch_seiten);
            ImageButton ibEditSpalten = rootView.findViewById(R.id.EO_button_edit_spalten);
            ImageButton ibEditZeilen = rootView.findViewById(R.id.EO_button_edit_zeilen);
            AppCompatSpinner spinnerFontSize = rootView.findViewById(R.id.EO_spinner_fontgroesse);
            titelSpinnerEinastzorte = rootView.findViewById(R.id.EO_text_orte);
            spinnerEinastzorte = rootView.findViewById(R.id.EO_spinner_orte);

            // die Bitsets für Spalten, Zeilen/Optionen und Zusatzwerte initialisieren
            bsSpalten = new BitSet(IExport_Basis.DEF_MAXBIT_SPALTE);
            bsSpaltenDeaktiv = new BitSet(IExport_Basis.DEF_MAXBIT_SPALTE);
            bsOptionen = new BitSet(IExport_Basis.DEF_MAXBIT_OPTION);
            bsOptionenDeaktiv = new BitSet(IExport_Basis.DEF_MAXBIT_OPTION);
            bsZusatzfelder = new BitSet();

            long i = ASettings.aktJob.getId();
            KEY_EXP_EO_SPALTEN = ISettings.KEY_EXP_EO_SPALTEN + i;
            KEY_EXP_EO_ZEILEN = ISettings.KEY_EXP_EO_ZEILEN + i;
            KEY_EXP_EO_ZUSATZ = ISettings.KEY_EXP_EO_ZUSATZ + i;
            initSpaltenZeilen();

            // Handler registrieren
            wBeginn.setOnClickListener(this);
            wEnde.setOnClickListener(this);
            wAnzahlBerichte.setOnClickListener(this);
            wTrenner.setOnClickListener(this);
            rgGroesse.setOnCheckedChangeListener(this);
            rgLayout.setOnCheckedChangeListener(this);
            wNotiz.setOnClickListener(this);
            ibEditSpalten.setOnClickListener(this);
            ibEditZeilen.setOnClickListener(this);
            cbZusammen.setOnCheckedChangeListener(this);
            rgDateityp.setOnCheckedChangeListener(this);
            swAllJobs.setOnCheckedChangeListener(this);
            swNurOrte.setOnCheckedChangeListener(this);
            swTabelleJeOrt.setOnCheckedChangeListener(this);
            spinnerFontSize.setOnItemSelectedListener(this);

            // Farbgebung der Knöpfe anpassen
            // Radiobuttons Dateitypen
            for (View v : rgDateityp.getTouchables()) {
                CompoundButtonCompat.setButtonTintList(
                        ((AppCompatRadioButton) v),
                        ASettings.aktJob.getFarbe_Radio());
            }
            for (View v : rgGroesse.getTouchables()) {
                CompoundButtonCompat.setButtonTintList(
                        ((AppCompatRadioButton) v),
                        ASettings.aktJob.getFarbe_Radio());
            }
            // Radiobuttons Seitenformat
            for (View v : rgLayout.getTouchables()) {
                CompoundButtonCompat.setButtonTintList(
                        ((AppCompatRadioButton) v),
                        ASettings.aktJob.getFarbe_Radio());
            }
            // Checkboxen
            CompoundButtonCompat.setButtonTintList(
                    cbZusammen,
                    ASettings.aktJob.getFarbe_Radio());

            // Schalter
            swAllJobs.setThumbTintList(ASettings.aktJob.getFarbe_Thumb());
            swAllJobs.setTrackTintList(ASettings.aktJob.getFarbe_Trak());
            swNurOrte.setThumbTintList(ASettings.aktJob.getFarbe_Thumb());
            swNurOrte.setTrackTintList(ASettings.aktJob.getFarbe_Trak());
            swTabelleJeOrt.setThumbTintList(ASettings.aktJob.getFarbe_Thumb());
            swTabelleJeOrt.setTrackTintList(ASettings.aktJob.getFarbe_Trak());

            // Spalte- und Zeilenknöpfe
            ViewCompat.setBackgroundTintList(ibEditSpalten, ASettings.aktJob.getFarbe_Button());
            ViewCompat.setBackgroundTintList(ibEditZeilen, ASettings.aktJob.getFarbe_Button());

            // Die Dateitypauswahl
            int d = exportDateityp;
            rgDateityp.clearCheck();
            if (d == IExport_Basis.TYP_CSV) {
                rgDateityp.check(R.id.EO_button_csv);
                bTrenner.setVisibility(View.VISIBLE);
                swTabelleJeOrt.setVisibility(View.GONE);
                cbZusammen.setVisibility(View.GONE);
            } else {
                rgDateityp.check(R.id.EO_button_pdf);
                bTrenner.setVisibility(View.GONE);
                swTabelleJeOrt.setVisibility(View.VISIBLE);
                cbZusammen.setVisibility(View.VISIBLE);
            }
            // die Seitengrösse
            rgGroesse.clearCheck();
            rgGroesse.check(
                    bsOptionen.get(IExport_Basis.OPTION_LAYOUT_A3) ?
                    R.id.EO_button_a3 :
                    R.id.EO_button_a4
            );

            // die Formatauswahl
            rgLayout.clearCheck();
            rgLayout.check(
                    bsOptionen.get(IExport_Basis.OPTION_LAYOUT_QUEER) ?
                            R.id.EO_button_quer :
                            R.id.EO_button_hoch
            );

            // die Zeitraumzusammenfassung
            boolean b = bsOptionen.get(IExport_Basis.OPTION_ZUSAMMENFASSUNG);
            cbZusammen.setChecked(false);
            cbZusammen.setChecked(b);

            // Tabellenoptionen
            // Nur die Liste aller Einsatzorte
            swNurOrte.setChecked(bsOptionen.get(IExport_Basis.OPTION_NUR_ORTE));
            if (swNurOrte.isChecked()) {
                swTabelleJeOrt.setVisibility(View.GONE);
                bAuswahl.setVisibility(View.GONE);
                wBeginn.setEnabled(false);
                wEnde.setEnabled(false);
            } else {
                if (exportDateityp == IExport_Basis.TYP_PDF)
                    swTabelleJeOrt.setVisibility(View.VISIBLE);
                bAuswahl.setVisibility(View.VISIBLE);
                wBeginn.setEnabled(true);
                wEnde.setEnabled(true);
            }

            // Alle Arbeitsplätze einbeziehen
            swAllJobs.setChecked(bsOptionen.get(IExport_Basis.OPTION_ALL_JOBS));

            // eine Seite pro Einsatzort
            swTabelleJeOrt.setChecked(bsOptionen.get(IExport_Basis.OPTION_TABELLE_JE_ORT));

            // Werte an Hand der letzten Auswahl vorbelegen
            // das Trennzeichen für den CSV export
            wTrenner.setText(ASettings.mPreferenzen.getString(ISettings.KEY_EXPORT_CSV_TRENNER, ";"));

            // der Datumsbereich
            wBeginn.setText(kStarttag.getString_Datum(mContext));
            wEnde.setText(kEndtag.getString_Datum(mContext));
            updateAnzahlBerichte(mAnzahlBerichte);

            // Notiz, die auf dem Wochenreport gedruckt wird
            wNotiz.setText(ASettings.mPreferenzen.getString(ISettings.KEY_EXP_EO_NOTIZ, ""));

            // die Vorauswahl der Schriftgrösse
            spinnerFontSize.setSelection(ASettings.mPreferenzen.getInt(ISettings.KEY_EXP_EO_FONTSIZE, IExport_Basis.MIN_FONTSIZE));

            // Einsatzorte Auswahl initialisieren
            spinnerEinastzorte.setItems(initEinsatzortAuswahl(swAllJobs.isChecked()));
            spinnerEinastzorte.setOnMultiSelected(this);
        }
    }

    /*
     * Handlerfunktionen
     */

    @Override
    public void onClick(View v) {
        FragmentManager fManager;
        try {
            fManager = getParentFragmentManager();
            int id = v.getId();
            if (id == R.id.EO_wert_notiz) {
                final InputMethodManager immNotiz = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                final AlertDialog.Builder mDialogNotiz = new AlertDialog.Builder(mContext);
                final EditText mInputNotiz = new EditText(getActivity());
                mInputNotiz.setText(wNotiz.getText());
                mInputNotiz.setSelection(wNotiz.getText().length());
                mInputNotiz.setFocusableInTouchMode(true);
                mInputNotiz.requestFocus();
                mInputNotiz.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
                mInputNotiz.setMaxLines(8);
                mDialogNotiz.setTitle(R.string.exp_notiz_hint);
                mDialogNotiz.setView(mInputNotiz);
                mDialogNotiz.setPositiveButton(getString(android.R.string.ok), (dialog, whichButton) -> {
                    wNotiz.setText(mInputNotiz.getText());
                    SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
                    mEdit.putString(ISettings.KEY_EXP_EO_NOTIZ, wNotiz.getText().toString()).apply();
                    if (immNotiz != null) {
                        immNotiz.hideSoftInputFromWindow(mInputNotiz.getWindowToken(), 0);
                    }
                });
                mDialogNotiz.setNegativeButton(getString(android.R.string.cancel), (dialog, whichButton) -> {
                    // Abbruchknopf gedrückt
                    if (immNotiz != null) {
                        immNotiz.hideSoftInputFromWindow(mInputNotiz.getWindowToken(), 0);
                    }
                });
                mDialogNotiz.show();
                if (immNotiz != null) {
                    immNotiz.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                }
            } else if (id == R.id.EO_wert_trenner) {
                final InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                final AlertDialog.Builder mDialog = new AlertDialog.Builder(mContext);
                final EditText mInput = new EditText(getActivity());
                mInput.setText(wTrenner.getText());
                mInput.setSelection(wTrenner.getText().length());
                mInput.setMaxLines(1);
                mInput.setInputType(InputType.TYPE_CLASS_TEXT);
                mInput.setFocusableInTouchMode(true);
                mInput.requestFocus();
                mDialog.setTitle(R.string.exp_titel_trenner);
                mDialog.setView(mInput);
                mDialog.setPositiveButton(getString(android.R.string.ok), (dialog, whichButton) -> {
                    wTrenner.setText(mInput.getText());
                    SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
                    mEdit.putString(ISettings.KEY_EXPORT_CSV_TRENNER, wTrenner.getText().toString()).apply();
                    if (imm != null) {
                        imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
                    }
                });
                mDialog.setNegativeButton(getString(android.R.string.cancel), (dialog, whichButton) -> {
                    // Abbruchknopf gedrückt
                    if (imm != null) {
                        imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
                    }
                });
                mDialog.show();
                if (imm != null) {
                    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                }
            } else if (id == R.id.EO_wert_von) {
                CalendarDatePickerDialogFragment vonKalenderPicker =
                        new CalendarDatePickerDialogFragment()
                                .setOnDateSetListener(this)
                                .setFirstDayOfWeek(ASettings.aktJob.getWochenbeginn())
                                .setPreselectedDate(kStarttag.get(Calendar.YEAR),
                                        kStarttag.get(Calendar.MONTH) - 1,
                                        kStarttag.get(Calendar.DAY_OF_MONTH));
                if (ASettings.aktJob.getStartDatum().liegtNach(ASettings.aktDatum)) {
                    vonKalenderPicker.setDateRange(
                            new MonthAdapter.CalendarDay(
                                    ASettings.aktJob.getStartDatum().get(Calendar.YEAR),
                                    ASettings.aktJob.getStartDatum().get(Calendar.MONTH) - 1,
                                    ASettings.aktJob.getStartDatum().get(Calendar.DAY_OF_MONTH)),
                            new MonthAdapter.CalendarDay(
                                    ASettings.aktJob.getStartDatum().get(Calendar.YEAR),
                                    ASettings.aktJob.getStartDatum().get(Calendar.MONTH) - 1,
                                    ASettings.aktJob.getStartDatum().get(Calendar.DAY_OF_MONTH)));
                    vonKalenderPicker.setPreselectedDate(
                            ASettings.aktJob.getStartDatum().get(Calendar.YEAR),
                            ASettings.aktJob.getStartDatum().get(Calendar.MONTH) - 1,
                            ASettings.aktJob.getStartDatum().get(Calendar.DAY_OF_MONTH));

                } else {
                    Datum lt = new Datum(ASettings.letzterAnzeigeTag);
                    lt.add(Calendar.DAY_OF_MONTH, -1);
                    vonKalenderPicker.setDateRange(
                            new MonthAdapter.CalendarDay(
                                    ASettings.aktJob.getStartDatum().get(Calendar.YEAR),
                                    ASettings.aktJob.getStartDatum().get(Calendar.MONTH) - 1,
                                    ASettings.aktJob.getStartDatum().get(Calendar.DAY_OF_MONTH)),
                            new MonthAdapter.CalendarDay(
                                    lt.get(Calendar.YEAR),
                                    lt.get(Calendar.MONTH) - 1,
                                    lt.get(Calendar.DAY_OF_MONTH)));
                    vonKalenderPicker.setPreselectedDate(
                            kStarttag.get(Calendar.YEAR),
                            kStarttag.get(Calendar.MONTH) - 1,
                            kStarttag.get(Calendar.DAY_OF_MONTH));
                }

                if (ASettings.isThemaDunkel) {
                    vonKalenderPicker.setThemeDark();
                } else {
                    vonKalenderPicker.setThemeLight();
                }
                vonKalenderPicker.show(fManager, getString(R.string.von));
            } else if (id == R.id.EO_wert_bis) {
                CalendarDatePickerDialogFragment bisKalenderPicker =
                        new CalendarDatePickerDialogFragment()
                                .setOnDateSetListener(this)
                                .setFirstDayOfWeek(ASettings.aktJob.getWochenbeginn())
                                .setPreselectedDate(kStarttag.get(Calendar.YEAR),
                                        kStarttag.get(Calendar.MONTH) - 1,
                                        kStarttag.get(Calendar.DAY_OF_MONTH));
                Datum d = new Datum(kStarttag);
                d.add(Calendar.DAY_OF_MONTH, 1);
                bisKalenderPicker.setDateRange(
                        new MonthAdapter.CalendarDay(
                                d.get(Calendar.YEAR),
                                d.get(Calendar.MONTH) - 1,
                                d.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)));
                bisKalenderPicker.setPreselectedDate(
                        kEndtag.get(Calendar.YEAR),
                        kEndtag.get(Calendar.MONTH) - 1,
                        kEndtag.get(Calendar.DAY_OF_MONTH));

                if (ASettings.isThemaDunkel) {
                    bisKalenderPicker.setThemeDark();
                } else {
                    bisKalenderPicker.setThemeLight();
                }
                bisKalenderPicker.show(fManager, getString(R.string.bis));
            } else if (id == R.id.EO_wert_anzahl) {
                int mMaxAnzahl;
                try {
                    fManager = getParentFragmentManager();
                    mMaxAnzahl = kStarttag.tageBis(ASettings.letzterAnzeigeTag) + 1;
                    mMaxAnzahl /= (mAnzahlTage);
                    NumberPickerBuilder prozentPicker = new NumberPickerBuilder()
                            .setFragmentManager(fManager)
                            .setStyleResId(ASettings.themePicker)
                            .setMinNumber(BigDecimal.valueOf(1))
                            .setMaxNumber(BigDecimal.valueOf(mMaxAnzahl))
                            .setLabelText(getString(R.string.zeitraeume))
                            //.setCurrentNumber(anzahlJahre)
                            .setPlusMinusVisibility(View.INVISIBLE)
                            .setDecimalVisibility(View.INVISIBLE)
                            .setReference(R.id.EO_wert_anzahl)
                            .setTargetFragment(this);
                    prozentPicker.show();
                } catch (IllegalStateException ise) {
                    ise.printStackTrace();
                }
            } else if (id == R.id.EO_button_edit_spalten) {// Spaltenauswahldialog
                Fragment_Dialog_Spalten mDialogSpalten = new Fragment_Dialog_Spalten(
                        bsSpalten, bsSpaltenDeaktiv, bsZusatzfelder, this
                );
                //mDialogSpalten.setup(bsSpalten, bsSpaltenDeaktiv, bsZusatzfelder, this);
                mDialogSpalten.show(fManager, "EditSpaltenDialog");
            } else if (id == R.id.EO_button_edit_zeilen) {// Zeilenauswahldialog
                Fragment_Dialog_Zeilen mDialogZeilen = new Fragment_Dialog_Zeilen(
                        ASettings.aktJob,
                        bsOptionen,
                        bsOptionenDeaktiv,
                        this,
                        IExport_Basis.PERIODE_EORT);
                /*mDialogZeilen.setup(
                        ASettings.aktJob,
                        bsOptionen,
                        bsOptionenDeaktiv,
                        this,
                        IExport_Basis.PERIODE_EORT);*/
                mDialogZeilen.show(fManager, "EditZeilenDialog");
            }
        } catch (IllegalStateException ignore){
        }
    }

public void onDialogNumberSet(int reference, BigInteger number, double decimal, boolean isNegative, BigDecimal fullNumber) {
        if(reference == R.id.EO_wert_anzahl) {
            updateAnzahlBerichte(number.intValue());
        }
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
        int id = group.getId();
        if (id == R.id.EO_gruppe_groesse){
            bsOptionen.set(IExport_Basis.OPTION_LAYOUT_A3, (checkedId == R.id.EO_button_a3));
            int value = 0;
            for (int i = 0; i <= IExport_Basis.DEF_MAXBIT_OPTION; ++i) {
                value += bsOptionen.get(i) ? (1 << i) : 0;
            }
            mEdit.putInt(KEY_EXP_EO_ZEILEN, value);
        } else if (id == R.id.EO_gruppe_layout) {
            bsOptionen.set(IExport_Basis.OPTION_LAYOUT_QUEER, checkedId == R.id.EO_button_quer);
            int value = 0;
            for (int i = 0; i <= IExport_Basis.DEF_MAXBIT_OPTION; ++i) {
                value += bsOptionen.get(i) ? (1 << i) : 0;
            }
            mEdit.putInt(KEY_EXP_EO_ZEILEN, value);
        } else if (id == R.id.EO_gruppe_typ) {
            if (checkedId == R.id.EO_button_csv) {
                exportDateityp = IExport_Basis.TYP_CSV;
                bTrenner.setVisibility(View.VISIBLE);
                rgGroesse.setVisibility(View.GONE);
                rgLayout.setVisibility(View.GONE);
                bNotiz.setVisibility(View.GONE);
                swTabelleJeOrt.setVisibility(View.GONE);
                cbZusammen.setVisibility(View.GONE);
                if (bsOptionenDeaktiv != null) {
                    bsOptionenDeaktiv.set(IExport_Basis.OPTION_ZEILE_UNTERSCHRIFT, true);
                }
            } else {
                exportDateityp = IExport_Basis.TYP_PDF;
                bTrenner.setVisibility(View.GONE);
                rgGroesse.setVisibility(View.VISIBLE);
                rgLayout.setVisibility(View.VISIBLE);
                bNotiz.setVisibility(View.VISIBLE);
                swTabelleJeOrt.setVisibility(View.VISIBLE);
                cbZusammen.setVisibility(View.VISIBLE);
                if (bsOptionenDeaktiv != null) {
                    bsOptionenDeaktiv.set(IExport_Basis.OPTION_ZEILE_UNTERSCHRIFT, false);
                }
            }
            mEdit.putInt(ISettings.KEY_EXP_TYP_EORT, exportDateityp);
        }

        mEdit.apply();
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
        int id = buttonView.getId();
        if (id == R.id.EO_switch_nur_orte) {
            bsOptionen.set(IExport_Basis.OPTION_NUR_ORTE, isChecked);
            if (isChecked) {
                swTabelleJeOrt.setVisibility(View.GONE);
                bAuswahl.setVisibility(View.GONE);
                spinnerEinastzorte.setVisibility(View.GONE);
                titelSpinnerEinastzorte.setVisibility(View.GONE);
                wBeginn.setEnabled(false);
                wEnde.setEnabled(false);
            } else {
                swTabelleJeOrt.setVisibility(View.VISIBLE);
                bAuswahl.setVisibility(View.VISIBLE);
                spinnerEinastzorte.setVisibility(View.VISIBLE);
                titelSpinnerEinastzorte.setVisibility(View.VISIBLE);
                wBeginn.setEnabled(true);
                wEnde.setEnabled(true);
            }
        } else if (id == R.id.EO_switch_all_jobs) {
            bsOptionen.set(IExport_Basis.OPTION_ALL_JOBS, isChecked);
            spinnerEinastzorte.setItems(initEinsatzortAuswahl(isChecked));
        } else if (id == R.id.EO_switch_seiten) {
            bsOptionen.set(IExport_Basis.OPTION_TABELLE_JE_ORT, isChecked);
        } else if (id == R.id.EO_button_zus) {
            bsOptionen.set(IExport_Basis.OPTION_ZUSAMMENFASSUNG, isChecked);
        }
        int value = 0;
        for (int i = 0; i <= IExport_Basis.DEF_MAXBIT_OPTION; ++i) {
            value += bsOptionen.get(i) ? (1 << i) : 0;
        }
        mEdit.putInt(KEY_EXP_EO_ZEILEN, value);

        mEdit.apply();
    }


    /*
     * Dialogrückgaben
     */
    @Override
    public void onDateSet(CalendarDatePickerDialogFragment dialog, int year, int monthOfYear, int dayOfMonth) {
        if (Objects.equals(dialog.getTag(), getString(R.string.von))) {
            kStarttag.set(year, monthOfYear + 1, dayOfMonth);
            wBeginn.setText(kStarttag.getString_Datum(mContext));
            if (!kStarttag.liegtVor(kEndtag)) {
                kEndtag.set(kStarttag.getCalendar());
                kEndtag.add(Calendar.DAY_OF_MONTH, kEndtag.getAktuellMaximum(Calendar.DAY_OF_MONTH) - 1);
                if (!kEndtag.liegtVor(ASettings.letzterAnzeigeTag))
                    kEndtag.set(ASettings.letzterAnzeigeTag.getCalendar());
                wEnde.setText(kEndtag.getString_Datum(mContext));
            }
        } else {
            kEndtag.set(year, monthOfYear + 1, dayOfMonth);
            wEnde.setText(kEndtag.getString_Datum(mContext));
        }
        updateAnzahlBerichte(mAnzahlBerichte);
    }

    // die ausgewählte Schriftgrösse übernehmen
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        ASettings.mPreferenzen.edit().putInt(ISettings.KEY_EXP_EO_FONTSIZE, position).apply();
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}

    public void action(int action, Arbeitsplatz job, StorageHelper storegeHelper/*String pfad*/) {
        if(kStarttag != null) {
            exportSave(action, job, storegeHelper);
        }
    }

    //
    // die Auswahllistefür Einsatzorte erzeugen
    //
    private ArrayList<MultiSelectItem> initEinsatzortAuswahl(Boolean allJobs) {
        ArrayList<MultiSelectItem> itemsEinsatzorte = new ArrayList<>();
        if (allJobs) {
            for (Arbeitsplatz job : ASettings.jobListe.getListe()) {
                ArrayList<Einsatzort> orte = job.getEinsatzortListe().getAlle();
                for (Einsatzort ort : orte) {
                    itemsEinsatzorte.add(
                            new MultiSelectItem(
                                    ort.getId(),
                                    job.getId(),
                                    ort.getName(),
                                    false));

                }
            }
        } else {
            ArrayList<Einsatzort> orte = ASettings.aktJob.getEinsatzortListe().getAlle();
            for (Einsatzort ort : orte) {
                itemsEinsatzorte.add(
                        new MultiSelectItem(
                                ort.getId(),
                                ASettings.aktJob.getId(),
                                ort.getName(),
                                false)
                );
            }
        }
        itemsEinsatzorte.add(new MultiSelectItem(
                0,
                0,
                "<" + getString(R.string.kein_einsatzort) + ">",
                false));
        return itemsEinsatzorte;
    }

    //
    // die Bitsets für Spalten und Zeilen initialisieren
    //
    private void initSpaltenZeilen() {
        int mWert;

        // auszugebende Spalten
        mWert = ASettings.mPreferenzen.getInt(KEY_EXP_EO_SPALTEN, IExport_Basis.DEF_SPALTEN);
        for (int i = 0; i <= IExport_Basis.DEF_MAXBIT_SPALTE; i++) {
            bsSpalten.set(i, (mWert & (1 << i)) != 0);
        }

        // die daktivierten Spalten
        bsSpaltenDeaktiv.set(0, IExport_Basis.DEF_MAXBIT_SPALTE, false);

        // die daktivierten Zeilen
        bsOptionenDeaktiv.set(0, IExport_Basis.DEF_MAXBIT_OPTION, false);

        // ist kein Stundenlohn hinterlegt, dann die Spalte deaktivieren
        if (ASettings.aktJob.getStundenlohn() == 0) {
            bsSpaltenDeaktiv.set(IExport_Basis.SPALTE_VERDIENST, true);
            bsSpalten.set(IExport_Basis.SPALTE_VERDIENST, false);
        }


        //
        // für die Einsatzortliste nicht benötigte Spalten
        //
        bsSpaltenDeaktiv.set(IExport_Basis.SPALTE_TAGSOLL, true);
        bsSpalten.set(IExport_Basis.SPALTE_TAGSOLL, false);
        bsSpaltenDeaktiv.set(IExport_Basis.SPALTE_TAGSALDO, true);
        bsSpalten.set(IExport_Basis.SPALTE_TAGSALDO, false);
        bsSpaltenDeaktiv.set(IExport_Basis.SPALTE_EORT, true);
        bsSpalten.set(IExport_Basis.SPALTE_EORT, false);

        // auszugebende Zeilen und optionale Tabellen, Zusätze
        mWert = ASettings.mPreferenzen.getInt(KEY_EXP_EO_ZEILEN, IExport_Basis.DEF_OPTIONEN);
        for (int i = 0; i <= IExport_Basis.DEF_MAXBIT_OPTION; i++) {
            bsOptionen.set(i, (mWert & (1 << i)) != 0);
        }

        // Zeilen die generell nichtinteressieren
        bsOptionenDeaktiv.set(IExport_Basis.OPTION_ZEILE_SUMMETAG, true);
        bsOptionen.set(IExport_Basis.OPTION_ZEILE_SUMMETAG, false);

        // in allen Dateien, ausser PDFs die Unterschriften deaktivieren
        if (exportDateityp != IExport_Basis.TYP_PDF) {
            bsOptionenDeaktiv.set(IExport_Basis.OPTION_ZEILE_UNTERSCHRIFT, true);
        }


        // auszugebende Zusatzwerte
        mWert = ASettings.mPreferenzen.getInt(KEY_EXP_EO_ZUSATZ, 0b0);
        for (int i = 0; i < ASettings.aktJob.getZusatzfeldListe().size(); i++) {
            bsZusatzfelder.set(i, (mWert & (1 << i)) != 0);
        }
    }

    @Override
    public void onEditSpaltenPositiveClick(BitSet spalten, BitSet zusatzwerte) {
        int value;

        if (!bsSpalten.equals(spalten)) {
            bsSpalten = (BitSet) spalten.clone();
            value = 0;
            for (int i = 0; i < bsSpalten.size(); ++i) {
                value += bsSpalten.get(i) ? (1 << i) : 0;
            }
            ASettings.mPreferenzen.edit().putInt(KEY_EXP_EO_SPALTEN, value).apply();
        }

        if (!bsZusatzfelder.equals(zusatzwerte)) {
            bsZusatzfelder = (BitSet) zusatzwerte.clone();
            value = 0;
            for (int i = 0; i < bsZusatzfelder.size(); ++i) {
                value += bsZusatzfelder.get(i) ? (1 << i) : 0;
            }
            ASettings.mPreferenzen.edit().putInt(KEY_EXP_EO_ZUSATZ, value).apply();
        }
    }

    @Override
    public void onEditZeilenPositiveClick(BitSet zeilen, String unetrschriftAG, String unterschriftAN) {
        if (!zeilen.equals(bsOptionen)) {
            bsOptionen = (BitSet) zeilen.clone();
            int value = 0;
            for (int i = 0; i < bsOptionen.size(); ++i) {
                value += bsOptionen.get(i) ? (1 << i) : 0;
            }
            ASettings.mPreferenzen.edit().putInt(KEY_EXP_EO_ZEILEN, value).apply();
        }
        ASettings.aktJob.setUnterschrift_AG(unetrschriftAG);
        ASettings.aktJob.setUnterschrift_AN(unterschriftAN);
        ASettings.aktJob.schreibeJob();
    }

    @Override
    public void onMultiSelection(ArrayList<MultiSelectItem> selectedItems) {
        if(selectedItems.size() > 0) {
            listeEinsatzorte = selectedItems;
        } else {
            listeEinsatzorte = null;
        }
    }


    /*
     * Arbeitstask zum erzeugen und speichern des Berichtes
     */
    private void exportSave(final int action, Arbeitsplatz job, final StorageHelper storageHelper/*final String pfad*/) {
        ProgressDialog mDialog;
        //Context mContext = getContext();

        Handler mHandler = new Handler();
        // Fortschritsdialog öffnen
        mDialog = new ProgressDialog(mContext);
        mDialog.setIndeterminate(true);
        mDialog.setIndeterminateDrawable(
                ResourcesCompat.getDrawable(
                        getResources(),
                        R.drawable.progress_dialog_anim,
                        requireActivity().getTheme()
                )
        );
        mDialog.setMessage(getString(R.string.progress_export));
        mDialog.setCancelable(false);
        mDialog.show();

        new Thread(() -> {
            boolean mStatus = true;
            ArrayList<String> mDateinamen = new ArrayList<>();

            for (int i = 0; i < mAnzahlBerichte; i++) {
                if (exportDateityp == IExport_Basis.TYP_CSV) {
                    Export_CSV_Einsatzort mCSVeort;
                    try {
                        mCSVeort = new Export_CSV_Einsatzort(
                                mContext,
                                job,
                                kStarttag,
                                kEndtag,
                                bsOptionen,
                                bsSpalten,
                                bsZusatzfelder,
                                storageHelper,
                                listeEinsatzorte
                        );
                        mDateinamen.add(mCSVeort.getDateiName());
                    } catch (Exception e) {
                        e.printStackTrace();
                        mStatus = false;
                    }
                } else {
                    exportDateityp = IExport_Basis.TYP_PDF;
                    Export_PDF_Einsatzort mPDFeort;
                    try {
                        mPDFeort = new Export_PDF_Einsatzort(
                                mContext,
                                new Zeitraum_Frei(job, kStarttag, kEndtag),
                                bsSpalten,
                                bsOptionen,
                                bsZusatzfelder,
                                ASettings.mPreferenzen.getString(ISettings.KEY_EXP_EO_NOTIZ, ""),
                                storageHelper,
                                listeEinsatzorte);
                        mDateinamen.add(mPDFeort.getDateiName());
                    } catch (Exception e) {
                        e.printStackTrace();
                        mStatus = false;
                    }
                }
                kStarttag.add(Calendar.DAY_OF_YEAR, mAnzahlTage);
                kEndtag.add(Calendar.DAY_OF_YEAR, mAnzahlTage);
            }

            final boolean fStatus = mStatus;
            final ArrayList<String> fDateiname = mDateinamen;
            mHandler.post(()->{
                // Fortschrittsdialog schliessen
                try {
                    if(mDialog.isShowing()) {
                        mDialog.dismiss();
                    }
                }catch (IllegalArgumentException e){
                    e.printStackTrace();
                }

                // Toast ausgeben
                Toast toast = Toast.makeText(
                        mContext,
                        fStatus ?
                                mContext.getString(R.string.export_erfolg) :
                                mContext.getString(R.string.export_miserfolg)
                        , Toast.LENGTH_LONG);
                toast.show();

                // Rückruf wenn speichern erfolgreich war
                if (fStatus) {
                    mCallback.onExportFinisch(
                            action,
                            exportDateityp,
                            IExport_Basis.PERIODE_EORT,
                            fDateiname,
                            kStarttag,
                            kEndtag);
                }
            });

        }).start();
    }

    private void updateAnzahlBerichte(int anzahl){
        mAnzahlTage = kStarttag.tageBis(kEndtag) +1;
        int maxAnzahl = kStarttag.tageBis(ASettings.letzterAnzeigeTag) +1;
        maxAnzahl /= mAnzahlTage;
        mAnzahlBerichte = Math.min(anzahl, maxAnzahl);
        wAnzahlBerichte.setText(String.valueOf(mAnzahlBerichte));
        wNachwort.setText(getString(
                R.string.nachwort,
                mAnzahlBerichte,
                mAnzahlBerichte == 1 ? getString(R.string.zeitraum):getString(R.string.zeitraeume),
                mAnzahlBerichte == 1 ? getString(R.string.datei):getString(R.string.dateien)
        ));
    }
}


