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

import com.pdfjet.Align;
import com.pdfjet.Cell;
import com.pdfjet.Table;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.Zeitraum.IZeitraum;
import askanimus.arbeitszeiterfassung2.abwesenheiten.Abwesenheit;
import askanimus.arbeitszeiterfassung2.arbeitsjahr.Arbeitsjahr_summe;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.Arbeitsschicht;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.SchichtListeZeitraum;
import askanimus.arbeitszeiterfassung2.arbeitstag.Arbeitstag;
import askanimus.arbeitszeiterfassung2.einsatzort.Einsatzort;
import askanimus.arbeitszeiterfassung2.feiertage.Feiertag;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzWertListe;

abstract class AExport_Zeitraum_PDF extends AExportBasis_PDF implements IExport_Zeitraum_PDF{
    protected ArrayList<TabellenArbeitsplatz> mTabellen;
    IZeitraum mZeitraum;
    protected ArrayList<Arbeitsplatz> mArbeitsplatzListe;
    Arbeitsplatz mArbeitsplatz;
    protected ArrayList<MultiSelectItem> mListeOrteAuswahl;
    protected ArrayList<Einsatzort> mListeOrteArbeitsplatzAuswahl;
    protected BitSet mOptionen;
    BitSet mSpalten;
    protected BitSet mZusatzwerte;
    ArrayList<Spalte> mSpaltenSatz; // Namen und Positionen der einzelnen Spalten
    boolean isDezimal;
    int posSchichtname;

    //Formater für Wochentag
    //DateFormat fWochentag = new SimpleDateFormat("E", Locale.getDefault());

    // Formater für kurzes Datum
    DateFormat fDatum = new SimpleDateFormat("E d.M.yyyy", Locale.getDefault());


    AExport_Zeitraum_PDF(
            Context context,
            IZeitraum zeitraum,
            BitSet spalten,
            BitSet optionen,
            BitSet zusatzwerte,
            ArrayList<MultiSelectItem> listeOrte
    ) {
        super(context);
        mZeitraum = zeitraum;
        mListeOrteAuswahl = listeOrte;
        mSpalten = spalten;
        posSchichtname = mSpalten.get(SPALTE_DATUM) ? 1 : 0;
        mZusatzwerte = zusatzwerte;
        mOptionen = optionen;

        if (mOptionen.get(OPTION_ALL_JOBS)) {
            mArbeitsplatzListe = ASettings.jobListe.getListe();
        } else {
            mArbeitsplatzListe = new ArrayList<>();
            mArbeitsplatzListe.add(mZeitraum.getArbeitsplatz());
        }
    }

    @Override
    public ArrayList<TabellenArbeitsplatz> erzeugeTabellen() throws Exception {
        boolean farbeHintergrund = false;
        int wochenNummer;
        mTabellen = new ArrayList<>();
        TabellenArbeitsplatz mTabellenArbeitsplatz;
        List<List<Cell>> mTabelData;

        for (int i = 0; i < mArbeitsplatzListe.size(); i++) {
            wochenNummer = 0;
            mArbeitsplatz = mArbeitsplatzListe.get(i);
            mListeOrteArbeitsplatzAuswahl = makeEinsatzortListeAuswahl(mArbeitsplatz, mListeOrteAuswahl);
            mSpaltenSatz = makeSpaltenSet(mSpalten, mZusatzwerte, mArbeitsplatz);
            if (i > 0) {
                mZeitraum = mZeitraum.wechselArbeitsplatz(mArbeitsplatz);
            }
            isDezimal = mArbeitsplatz.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL);
            // neuen Tabellensatz für diesen Arbeitsplatz anlegen
            mTabellenArbeitsplatz = new TabellenArbeitsplatz();
            mTabellenArbeitsplatz.arbeitsplatz = mArbeitsplatz;
            mTabelData = new ArrayList<>();

            // Haupttabelle erzeugen

            // die Kopfzeile der Tabelle
            makeTabellenKopf(mTabelData);

            // Datenzeilen Tage/Schichten
            for (Arbeitstag tag : mZeitraum.getTage()) {
                // wenn die Wochennummer angezeigt werden soll
                // am Beginn einer neuen Woche eine Zeile mit der Wochennummer einfügen
                if(mOptionen.get(OPTION_WOCHENNUMMER) && tag.getKalender().getWoche() != wochenNummer){
                    wochenNummer = tag.getKalender().getWoche();
                    makeTitel(
                            mTabelData,
                            mContext.getString(R.string.woche_nummer, wochenNummer),
                            mSpaltenSatz.size()
                    );
                    mTabelData.get(mTabelData.size()-1).get(0).setTextAlignment(Align.LEFT);
                }
                makeTageszeile(mTabelData, tag, farbeHintergrund);
                farbeHintergrund = !farbeHintergrund;
            }
            // die Summenzeile der Tabelle
            makeSummenzeile(mTabelData);

            // Tabelle speichern
            mTabellenArbeitsplatz.einzeltabelle = makeTabelle(
                            mTabelData,
                            Table.DATA_HAS_1_HEADER_ROWS,
                            true,
                            mSpaltenSatz);

            // Zusammenfassung erzeugen wenn gewünscht
            if (mOptionen.get(OPTION_ZUSAMMENFASSUNG)) {
                mTabellenArbeitsplatz.zusammenfassung = makeTabelle(
                        makeZusammenfassung(),
                        Table.DATA_HAS_0_HEADER_ROWS,
                        false,
                        mSpaltenSatz);
                mTabellenArbeitsplatz.zusammenfassung.setNoCellBorders();
            }

            // Extratabelle nach Einsatzorten sortiert wenn gewünscht
            if (mOptionen.get(OPTION_ZUSATZTABELLE_EORT)) {
                mTabellenArbeitsplatz.multitabelle = new ArrayList<>();
                mTabellenArbeitsplatz.multitabelle.addAll(makeTabelle_EorteSchichtenListe(true));
            }
            mTabellen.add(mTabellenArbeitsplatz);
        }
        return mTabellen;
    }

    @Override
    public void makeTabellenKopf(List<List<Cell>> tableData) {
        ArrayList<Cell> row = new ArrayList<>();
        for (Spalte spalte : mSpaltenSatz) {
            row.add(makeZelleKopf(spalte.mName));
        }
        tableData.add(row);
    }


    @Override
    public void makeTageszeile(List<List<Cell>> tableData, Arbeitstag tag, boolean farbeHintergrund) {
        Uhrzeit mZeit = new Uhrzeit(0);
        ArrayList<Cell> row;
        boolean sindSchichten = false;

        Cell zelleSoll = null;
        Cell zelleDifferenz = null;

        for (Arbeitsschicht aSchicht : tag.getSchichten()) {
            if ( aSchicht.getAbwesenheit().getKategorie() != Abwesenheit.KAT_KEINESCHICHT ) {
                row = new ArrayList<>();
                for (Spalte spalte : mSpaltenSatz) {
                    switch (spalte.mSpalte) {
                        case SPALTE_DATUM:
                            if (!sindSchichten) {
                                row.add(makeZelleKopf(fDatum.format(tag.getKalender().getDate())));
                                int wochenTag = tag.getWochentag();
                                if(wochenTag == Calendar.SATURDAY){
                                    row.get(row.size() - 1).setBgColor(cSamstag);
                                } else if(wochenTag == Calendar.SUNDAY){
                                    row.get(row.size() - 1).setBgColor(cSonntag);
                                } else {
                                    row.get(row.size() - 1).setBgColor(farbeHintergrund ? cGrau : cLeer);
                                }
                            } else {
                                row.add(makeZelleLeer(true));
                            }
                            break;
                        case SPALTE_SCHICHTNAME:
                            int kategorie = aSchicht.getAbwesenheit().getKategorie();
                            if ( kategorie == Abwesenheit.KAT_ARBEITSZEIT) {
                                row.add(makeZelleString(aSchicht.getName(), farbeHintergrund));
                            } else {
                                if(kategorie == Abwesenheit.KAT_FEIERTAG){
                                    Feiertag feiertag = ASettings.feiertage.getFeiertag(tag.getKalender());
                                    if(feiertag != null){
                                      row.add(makeZelleString(feiertag.getName(), farbeHintergrund));
                                    } else {
                                     row.add(makeZelleString(aSchicht.getAbwesenheit().getName(), farbeHintergrund));
                                    }
                                } else {
                                    row.add(makeZelleString(aSchicht.getAbwesenheit().getName(), farbeHintergrund));
                                }
                            }
                            break;
                        case SPALTE_EORT:
                            row.add(makeZelleString(aSchicht.getNameEinsatzort(), farbeHintergrund));
                            break;
                        case SPALTE_VON:
                            if (aSchicht.getAbwesenheit().getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                                row.add(makeZelleUhrzeit(aSchicht.getVon(), farbeHintergrund));
                            } else {
                                // wenn keine Arbeitszeit, kein Einsatzort und die Spalte Schichtname angezeigt wird
                                // dann Schichtname, Eort und von verbinden
                                if (aSchicht.getIdEinsatzort() <= 0 && mSpalten.get(SPALTE_SCHICHTNAME)) {
                                    row.add(makeZelleLeer(false));
                                    row.get(posSchichtname).setColSpan(row.size() - posSchichtname);
                                } else {
                                    row.add(makeZelleString("", farbeHintergrund));
                                }
                            }
                            break;
                        case SPALTE_BIS:
                            if (aSchicht.getAbwesenheit().getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                                row.add(makeZelleUhrzeit(aSchicht.getBis(), farbeHintergrund));
                            } else {
                                // wenn keine Arbeitszeit, kein Einsatzort und die Spalte Schichtname angezeigt wird
                                // dann Schichtname, Eort, von und bis verbinden
                                if (aSchicht.getIdEinsatzort() <= 0 && mSpalten.get(SPALTE_SCHICHTNAME)) {
                                    row.add(makeZelleLeer(false));
                                    row.get(posSchichtname).setColSpan(row.size() - posSchichtname);
                                } else {
                                    row.add(makeZelleString("", farbeHintergrund));
                                }
                            }
                            break;
                        case SPALTE_BRUTTO:
                            row.add(makeZelleStunden(aSchicht.getBrutto(), isDezimal, false, farbeHintergrund));
                            break;
                        case SPALTE_PAUSE:
                            row.add(makeZelleStunden(aSchicht.getPause(), isDezimal, false, farbeHintergrund));
                            break;
                        case SPALTE_NETTO:
                            row.add(makeZelleStunden(aSchicht.getNetto(), isDezimal, false, farbeHintergrund));
                            break;
                        case SPALTE_TAGSOLL:
                            row.add(makeZelleString("", farbeHintergrund));
                            if(!mOptionen.get(OPTION_ZEILE_SUMMETAG)){
                                zelleSoll = row.get(row.size()-1);
                                //row.add(makeZelleStunden(tag.getSoll(), isDezimal, false, farbeHintergrund));
                            }
                            break;
                        case SPALTE_TAGSALDO:
                            row.add(makeZelleString("", farbeHintergrund));
                            if(!mOptionen.get(OPTION_ZEILE_SUMMETAG)){
                                zelleDifferenz = row.get(row.size()-1);
                            }
                            break;
                        case SPALTE_ANGELEGT:
                            row.add(makeZelleString(
                                    aSchicht.getEintragAngelegtAlsString(mContext),
                                    farbeHintergrund)
                            );
                            break;
                        case SPALTE_AENDERUNG:
                            row.add(makeZelleString(
                                    aSchicht.getLetzteAenderungAlsString(mContext),
                                    farbeHintergrund)
                            );
                            break;
                        case SPALTE_VERDIENST:
                            mZeit.set(aSchicht.getNetto());
                            row.add(makeZelleWert(
                                    mZeit.getAlsDezimalZeit() * mArbeitsplatz.getStundenlohn(),
                                    ASettings.waehrungformat,
                                    farbeHintergrund));
                            break;
                        default:
                            if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                                row.add(
                                        makeZelleZusatzwert(
                                                aSchicht.getZusatzwert(spalte.mSpalte - SPALTE_ZUSATZ),
                                                isDezimal,
                                                farbeHintergrund,
                                                true
                                        )
                                );
                            }
                    }
                }
                tableData.add(row);
                //farbeHintergrund = !farbeHintergrund;
                sindSchichten = true;
            }
        }
        // Zellenwerte für Tagsoll und Tagesdifferenz eintragen
        if(zelleSoll != null){
            Uhrzeit uz = new Uhrzeit(tag.getTagSollNetto());
            zelleSoll.setText(uz.getStundenString(false, isDezimal));
            zelleSoll.setTextAlignment(Align.RIGHT);
        }
        if(zelleDifferenz != null){
            Uhrzeit uz = new Uhrzeit(tag.getTagNetto() - tag.getTagSollNetto());
            zelleDifferenz.setText(uz.getStundenString(false, isDezimal));
            zelleDifferenz.setTextAlignment(Align.RIGHT);
            zelleDifferenz.setBgColor(cSumme);
            if(uz.getAlsMinuten() < 0) {
                zelleDifferenz.setBrushColor(cNegativ);
            } else if (uz.getAlsMinuten() > 0) {
                zelleDifferenz.setBrushColor(cPositiv);
            }
        }



        // die Tageszusammenfassung
        if (sindSchichten && mOptionen.get(OPTION_ZEILE_SUMMETAG)) {
            boolean isSetSumme = false;
            row = new ArrayList<>();

            for (Spalte spalte : mSpaltenSatz) {
                switch (spalte.mSpalte) {
                    case SPALTE_BRUTTO:
                        isSetSumme = true;
                        row.add(makeZelleSummeStunden(tag.getTagBrutto(), isDezimal, false, false));
                        break;
                    case SPALTE_PAUSE:
                        isSetSumme = true;
                        row.add(makeZelleSummeStunden(tag.getTagPause(), isDezimal, false, false));
                        break;
                    case SPALTE_NETTO:
                        isSetSumme = true;
                        row.add(makeZelleSummeStunden(tag.getTagNetto(), isDezimal, false, false));
                        break;
                    case SPALTE_TAGSOLL:
                        isSetSumme = true;
                        row.add(makeZelleSummeStunden(tag.getTagSollNetto(), isDezimal, false, false));
                        break;
                    case SPALTE_TAGSALDO:
                        isSetSumme = true;
                        row.add(makeZelleSummeStunden((tag.getTagNetto() - tag.getTagSollNetto()), isDezimal, false, false));
                        break;
                    case SPALTE_VERDIENST:
                        isSetSumme = true;
                        mZeit.set(tag.getTagNetto());
                        row.add(makeZelleSummeWert(
                                mZeit.getAlsDezimalZeit() * mArbeitsplatz.getStundenlohn(),
                                ASettings.waehrungformat,
                                false));
                        break;
                    case SPALTE_ANGELEGT:
                        row.add(makeZelleLeer(true));
                        break;
                    case SPALTE_AENDERUNG:
                        row.add(makeZelleLeer(true));
                        break;
                    default:
                        if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                            isSetSumme = true;
                            row.add(
                                    makeZelleSummeZusatzwert(
                                    tag.getTagZusatzwert(spalte.mSpalte - SPALTE_ZUSATZ),
                                    isDezimal
                                    )
                            );
                        } else {
                            if (row.size() == 0) {
                                row.add(makeZelleKopf(ASettings.res.getString(R.string.summe)));
                                row.get(0).setNoBorders();
                                row.get(0).setTextAlignment(Align.RIGHT);
                                row.get(0).setRightPadding(4f);
                            } else {
                                row.add(makeZelleLeer(true));
                                row.get(0).setColSpan(row.get(0).getColSpan() + 1);
                            }
                        }
                }
            }
            if (isSetSumme) {
                //row.get(0).setColSpan(span);
                tableData.add(row);
            }
        }
    }

    @Override
    public void makeSummenzeile(List<List<Cell>> tableData) {
        boolean isSetGesamt = false;
        int posTitelSaldo = 0;
        Uhrzeit mZeit = new Uhrzeit(0);
        ArrayList<Cell> row;
        // Gesamt des Zeitraums
        if (mOptionen.get(OPTION_ZEILE_SUMMEZEITRAUM)) {
            row = new ArrayList<>();

            for (Spalte spalte : mSpaltenSatz) {
                switch (spalte.mSpalte) {
                    case SPALTE_BRUTTO:
                        isSetGesamt = true;
                        posTitelSaldo = row.size() - 1;
                        row.add(makeZelleSummeStunden(mZeitraum.getBrutto(), isDezimal, false, false));
                        break;
                    case SPALTE_PAUSE:
                        isSetGesamt = true;
                        posTitelSaldo = row.size() - 1;
                        row.add(makeZelleSummeStunden(mZeitraum.getPause(), isDezimal, false, false));
                        break;
                    case SPALTE_NETTO:
                        isSetGesamt = true;
                        posTitelSaldo = row.size() - 1;
                        row.add(makeZelleSummeStunden(mZeitraum.getIstNetto(), isDezimal, false, false));
                        break;
                    case SPALTE_TAGSOLL:
                        isSetGesamt = true;
                        posTitelSaldo = row.size() - 1;
                        row.add(makeZelleSummeStunden(mZeitraum.getSoll(), isDezimal, false, false));
                        break;
                    case SPALTE_TAGSALDO:
                        isSetGesamt = true;
                        posTitelSaldo = row.size() - 1;
                        row.add(makeZelleSummeStunden((mZeitraum.getDifferenz()), isDezimal, false, !mZeitraum.isMonat()));
                        break;
                    case SPALTE_VERDIENST:
                        isSetGesamt = true;
                        mZeit.set(mZeitraum.getIstNetto());
                        row.add(makeZelleSummeWert(
                                mZeit.getAlsDezimalZeit() * mArbeitsplatz.getStundenlohn(),
                                ASettings.waehrungformat,
                                false));
                        break;
                    case SPALTE_ANGELEGT:
                        row.add(makeZelleLeer(true));
                        break;
                    case SPALTE_AENDERUNG:
                        row.add(makeZelleLeer(true));
                        break;
                    default:
                        if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                            isSetGesamt = true;
                            row.add(makeZelleSummeZusatzwert(
                                    mZeitraum.getZusatzeintragSummenListe().get(spalte.mSpalte - SPALTE_ZUSATZ),
                                    isDezimal));
                        } else {
                            posTitelSaldo = row.size() - 1;
                            if (row.size() == 0) {
                                row.add(makeZelleKopf(ASettings.res.getString(R.string.gesamt)));
                                row.get(0).setNoBorders();
                                row.get(0).setTextAlignment(Align.RIGHT);
                                row.get(0).setRightPadding(4f);
                            } else {
                                row.add(makeZelleLeer(true));
                                row.get(0).setColSpan(row.get(0).getColSpan() + 1);
                            }
                        }
                }
            }
            if (isSetGesamt) {
                tableData.add(row);
            }
        } else {
            for (int s = 0; s < mSpaltenSatz.size(); s++) {
                if (mSpaltenSatz.get(s).mSpalte < SPALTE_ZUSATZ) {
                    if (mSpaltenSatz.get(s).mSpalte <= SPALTE_TAGSALDO) {
                        posTitelSaldo = s;
                    }
                } else {
                    break;
                }
            }
            posTitelSaldo--;
        }

        // die Saldozeilen anschliessen
        // aber nur die die nicht schon in der Monatssumme stehen
        // Die Zeile Soll, wenn sie nicht schon in der Monatssumme steht
        if (mOptionen.get(OPTION_ZEILE_SOLLZEITRAUM) && posTitelSaldo > 0) {
            if (!mOptionen.get(OPTION_ZEILE_SUMMEZEITRAUM) || !mSpalten.get(SPALTE_TAGSOLL)) {
                // Sollstunden
                tableData.add(addSummeZeile(
                        posTitelSaldo,
                        mSpaltenSatz.size(),
                        ASettings.res.getString(R.string.soll),
                        mZeitraum.getSoll(),
                        isDezimal,
                        false));
            }
        }

        // die Saldo Zeilen
        if (mOptionen.get(OPTION_ZEILE_SALDOZEITRAUM) && posTitelSaldo > 0) {
            // wenn die Soll/Ist Differenz nicht angezeigt
            if (!mOptionen.get(OPTION_ZEILE_SUMMEZEITRAUM) || !mSpalten.get(SPALTE_NETTO)) {
                // Iststunden
                tableData.add(addSummeZeile(
                        posTitelSaldo,
                        mSpaltenSatz.size(),
                        ASettings.res.getString(R.string.ist),
                        mZeitraum.getIst(),
                        isDezimal,
                        false));
            }
            if (!mOptionen.get(OPTION_ZEILE_SUMMEZEITRAUM) || !mSpalten.get(SPALTE_TAGSALDO)) {
                // Differenz
                tableData.add(addSummeZeile(
                        posTitelSaldo,
                        mSpaltenSatz.size(),
                        ASettings.res.getString(R.string.diff),
                        mZeitraum.getDifferenz(),
                        isDezimal,
                        !mZeitraum.isMonat()));
            }

            if (mZeitraum.isMonat()) {
                // wenn ein Teil Überstunden mit dem Lohn pauschal abgegolten werden,
                // diese hier anziegen
                int uep = mZeitraum.getIstNetto() - mZeitraum.getIst();
                if (uep < 0) {
                tableData.add(addSummeZeile(
                        posTitelSaldo,
                        mSpaltenSatz.size(),
                        ASettings.res.getString(R.string.ueber_pauschal),
                        uep,
                        isDezimal,
                        false));
                }

                // Saldo Vormonat
                tableData.add(addSummeZeile(
                        posTitelSaldo,
                        mSpaltenSatz.size(),
                        ASettings.res.getString(R.string.saldo_vm),
                        mZeitraum.getSaldoUebertrag(),
                        isDezimal,
                        false));
                // Ausbezahlte Überstunden
                if (mZeitraum.getAuszahlung() > 0)
                    tableData.add(addSummeZeile(
                            posTitelSaldo,
                            mSpaltenSatz.size(),
                            ASettings.res.getString(R.string.ueberstunden_ausbezahlt),
                            -mZeitraum.getAuszahlung(),
                            isDezimal,
                            false));
            }
            //Saldo
            tableData.add(addSummeZeile(
                    posTitelSaldo,
                    mSpaltenSatz.size(),
                    ASettings.res.getString(R.string.saldo),
                    mZeitraum.getSaldo(),
                    isDezimal,
                    true));
        }
    }

    @Override
    public ArrayList<Table> makeTabelle_EorteSchichtenListe(boolean seiteJeOrt) throws Exception {
        ArrayList<Table> tabellen = new ArrayList<>();
        List<List<Cell>> tableData = new ArrayList<>();
        BitSet origSpalten = (BitSet) mSpalten.clone();
        mSpalten.set(SPALTE_EORT, false);
        mSpalten.set(SPALTE_TAGSOLL, false);
        mSpalten.set(SPALTE_TAGSALDO, false);
        mSpaltenSatz = makeSpaltenSet(mSpalten, mZusatzwerte, mArbeitsplatz);

        if (seiteJeOrt) {
            // die Liste der Einsatzorte
            for (Einsatzort o : mListeOrteArbeitsplatzAuswahl) {
                makeTableEortSchichten(tableData, o);
                if (tableData.size() > 0) {
                    tabellen.add(
                            makeTabelle(
                                    tableData,
                                    Table.DATA_HAS_2_HEADER_ROWS,
                                    true,
                                    mSpaltenSatz)
                    );
                    tableData = new ArrayList<>();
                }
            }
            // Tage ohne einsatzort auflisten
            /*makeTableEortSchichten(tableData, null);

            if (tableData.size() > 0) {
                tabellen.add(
                        makeTabelle(
                                tableData,
                                Table.DATA_HAS_1_HEADER_ROWS,
                                true,
                                mSpaltenSatz));
            }*/

        } else {
            // die Liste der Einsatzorte
            for (Einsatzort o : mListeOrteArbeitsplatzAuswahl) {
                makeTableEortSchichten(tableData, o);
            }

            // Tage ohne einsatzort auflisten
            //makeTableEortSchichten(tableData, null);

            // Alle Einsatzorte in einer Tabelle
            if (tableData.size() > 0) {
                tabellen.add(
                        makeTabelle(
                                tableData,
                                Table.DATA_HAS_0_HEADER_ROWS,
                                true,
                                mSpaltenSatz
                        ));
            }
        }

        mSpalten = (BitSet) origSpalten.clone();
        mSpaltenSatz = makeSpaltenSet(mSpalten, mZusatzwerte, mArbeitsplatz);

        return tabellen;
    }


    protected void makeTableEortSchichten(List<List<Cell>> tableData, Einsatzort Eort) {
        int ges_brutto = 0;
        int ges_pause = 0;
        int ges_netto = 0;
        ZusatzWertListe ges_zusatzfelder = new ZusatzWertListe(mArbeitsplatz.getZusatzfeldListe(), true);
        boolean farbeHintergrund = false;
        boolean isErster = true;
        boolean schreibeSumme = false;
        int wochenNummer = 0;

        long idEORT = (Eort == null) ? 0 : Eort.getId();

        for (Arbeitstag aTag : mZeitraum.getTage()) {
            for (Arbeitsschicht schicht : aTag.getSchichten()) {
                if (schicht.getIdEinsatzort() == idEORT) {
                    if (schicht.getAbwesenheit().getKategorie() != Abwesenheit.KAT_KEINESCHICHT) {
                        // die Summen für den Einsatzort aktuallisieren
                        if (schicht.getBrutto() > 0) {
                            ges_brutto += schicht.getBrutto();
                            ges_pause += schicht.getPause();
                            ges_netto += schicht.getNetto();
                        }
                        // die Werte aller Zusatzeinträge summieren
                        ges_zusatzfelder.addListenWerte(schicht.getZusatzfelder(IZusatzfeld.TEXT_LEER));

                        // die Zeile erzeugen
                        if (!mSpaltenSatz.isEmpty()) {
                            // ist es der erste Tag für diesen einsatzort, dann Tabellenkopf zeichnen
                            if (isErster) {
                                // Titelzeile mit dem Name des Einsatzortes einfügen
                                if (Eort == null) {
                                    makeTitel(
                                            tableData,
                                            "<" + ASettings.res.getString(R.string.kein_einsatzort) + ">",
                                            mSpaltenSatz.size());
                                } else {
                                    makeTitel(tableData, Eort.getName(), mSpaltenSatz.size());
                                }
                                // Tabellenkopf erstellen
                                ArrayList<Cell> row = new ArrayList<>();
                                for (Spalte spalte : mSpaltenSatz) {
                                    row.add(makeZelleKopf(spalte.mName));
                                }
                                tableData.add(row);
                                isErster = false;
                            }

                            // wenn die Wochennummer angezeigt werden soll
                            // am Beginn einer neuen Woche eine Zeile mit der Wochennummer einfügen
                            if (mOptionen.get(OPTION_WOCHENNUMMER) && aTag.getKalender().getWoche() != wochenNummer) {
                                wochenNummer = aTag.getKalender().getWoche();
                                makeTitel(
                                        tableData,
                                        mContext.getString(R.string.woche_nummer, wochenNummer),
                                        mSpaltenSatz.size()
                                );
                                tableData.get(tableData.size()-1).get(0).setTextAlignment(Align.LEFT);
                            }

                            // Zeile zusammensetzen
                            List<Cell> row = new ArrayList<>();
                            for (Spalte spalte : mSpaltenSatz) {
                                switch (spalte.mSpalte) {
                                    case SPALTE_DATUM:
                                        row.add(makeZelleKopf(fDatum.format(aTag.getKalender().getDate())));
                                        int wochenTag = aTag.getWochentag();
                                        if (wochenTag == Calendar.SATURDAY) {
                                            row.get(row.size() - 1).setBgColor(cSamstag);
                                        } else if (wochenTag == Calendar.SUNDAY) {
                                            row.get(row.size() - 1).setBgColor(cSonntag);
                                        } else {
                                            row.get(row.size() - 1).setBgColor(farbeHintergrund ? cGrau : cLeer);
                                        }
                                        break;
                                    case SPALTE_SCHICHTNAME:
                                        int kategorie = schicht.getAbwesenheit().getKategorie();
                                        if (kategorie == Abwesenheit.KAT_ARBEITSZEIT) {
                                            row.add(makeZelleString(schicht.getName(), farbeHintergrund));
                                        } else {
                                            if (kategorie == Abwesenheit.KAT_FEIERTAG) {
                                                Feiertag feiertag = ASettings.feiertage.getFeiertag(aTag.getKalender());
                                                if (feiertag != null) {
                                                    row.add(makeZelleString(feiertag.getName(), farbeHintergrund));
                                                } else {
                                                    row.add(makeZelleString(schicht.getAbwesenheit().getName(), farbeHintergrund));
                                                }
                                            } else {
                                                row.add(makeZelleString(schicht.getAbwesenheit().getName(), farbeHintergrund));
                                            }
                                        }
                                        break;
                                    case SPALTE_VON:
                                        if (schicht.getAbwesenheit().getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                                            row.add(makeZelleUhrzeit(schicht.getVon(), farbeHintergrund));
                                        } else {
                                            row.add(makeZelleLeer(false));
                                            if (mSpalten.get(SPALTE_SCHICHTNAME)) {
                                                row.get(posSchichtname).setColSpan(row.size() - posSchichtname);
                                            }
                                        }
                                        break;
                                    case SPALTE_BIS:
                                        if (schicht.getAbwesenheit().getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                                            row.add(makeZelleUhrzeit(schicht.getBis(), farbeHintergrund));
                                        } else {
                                            row.add(makeZelleLeer(false));
                                            if (mSpalten.get(SPALTE_SCHICHTNAME)) {
                                                row.get(posSchichtname).setColSpan(row.size() - posSchichtname);
                                            }
                                        }
                                        break;
                                    case SPALTE_BRUTTO:
                                        row.add(makeZelleStunden(schicht.getBrutto(), isDezimal, false, farbeHintergrund));
                                        break;
                                    case SPALTE_PAUSE:
                                        row.add(makeZelleStunden(schicht.getPause(), isDezimal, false, farbeHintergrund));
                                        break;
                                    case SPALTE_NETTO:
                                        row.add(makeZelleStunden(schicht.getNetto(), isDezimal, false, farbeHintergrund));
                                        break;
                                    case SPALTE_ANGELEGT:
                                        row.add(
                                                makeZelleString(
                                                        schicht.getEintragAngelegtAlsString(mContext),
                                                        farbeHintergrund)
                                        );
                                        break;
                                    case SPALTE_AENDERUNG:
                                        row.add(
                                                makeZelleString(
                                                        schicht.getLetzteAenderungAlsString(mContext),
                                                        farbeHintergrund)
                                        );
                                        break;
                                    case SPALTE_VERDIENST:
                                        Uhrzeit mZeit = new Uhrzeit(schicht.getNetto());
                                        row.add(makeZelleWert(
                                                mZeit.getAlsDezimalZeit() * mArbeitsplatz.getStundenlohn(),
                                                ASettings.waehrungformat,
                                                farbeHintergrund));
                                        break;
                                    default:
                                        if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                                            int zusatzSpalte = spalte.mSpalte - SPALTE_ZUSATZ;
                                            IZusatzfeld zfeld = schicht.getZusatzfelder(IZusatzfeld.TEXT_VOLL).get(zusatzSpalte);
                                            switch (zfeld.getDatenTyp()) {
                                                case IZusatzfeld.TYP_BEREICH_ZAHL:
                                                case IZusatzfeld.TYP_ZAHL:
                                                    row.add(makeZelleWert(
                                                            (float) zfeld.getWert(),
                                                            zfeld.getFormater(),
                                                            farbeHintergrund));
                                                    break;
                                                case IZusatzfeld.TYP_BEREICH_ZEIT:
                                                case IZusatzfeld.TYP_ZEIT:
                                                    row.add(makeZelleStunden((int) zfeld.getWert(), isDezimal, false, farbeHintergrund));
                                                    break;
                                                default:
                                                    row.add(makeZelleString(zfeld.getString(false), farbeHintergrund));
                                            }
                                        } else {
                                            row.add(makeZelleString("", farbeHintergrund));
                                        }
                                }
                            }
                            tableData.add(row);
                            schreibeSumme = true;
                            farbeHintergrund = !farbeHintergrund;
                        }
                    }
                }
            }
        }
        // die Summenzeile
        if (schreibeSumme) {
            ArrayList<Cell> row = new ArrayList<>();

            for (Spalte spalte : mSpaltenSatz) {
                switch (spalte.mSpalte) {
                    case SPALTE_BRUTTO:
                        row.add(makeZelleSummeStunden(ges_brutto, isDezimal, false, false));
                        break;
                    case SPALTE_PAUSE:
                        row.add(makeZelleSummeStunden(ges_pause, isDezimal, false, false));
                        break;
                    case SPALTE_NETTO:
                        row.add(makeZelleSummeStunden(ges_netto, isDezimal, false, false));
                        break;
                    case SPALTE_VERDIENST:
                        Uhrzeit mZeit = new Uhrzeit(ges_netto);
                        row.add(makeZelleSummeWert(
                                mZeit.getAlsDezimalZeit() * mArbeitsplatz.getStundenlohn(),
                                ASettings.waehrungformat,
                                false));
                        break;
                    default:
                        if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                            int zusatzSpalte = spalte.mSpalte - SPALTE_ZUSATZ;
                            IZusatzfeld zfeld = ges_zusatzfelder.get(zusatzSpalte);
                            switch (zfeld.getDatenTyp()) {
                                case IZusatzfeld.TYP_BEREICH_ZAHL:
                                case IZusatzfeld.TYP_ZAHL:
                                    row.add(makeZelleSummeWert(
                                            (float) zfeld.getWert(),
                                            zfeld.getFormater(),
                                            farbeHintergrund));
                                    break;
                                case IZusatzfeld.TYP_BEREICH_ZEIT:
                                case IZusatzfeld.TYP_ZEIT:
                                    row.add(makeZelleSummeStunden((int) zfeld.getWert(), isDezimal, false, true));
                                    break;
                                default:
                                    row.add(makeZelleLeer(true));
                            }
                        } else {
                            if (row.size() == 0) {
                                row.add(makeZelleKopf(ASettings.res.getString(R.string.summe)));
                                row.get(0).setNoBorders();
                                row.get(0).setTextAlignment(Align.RIGHT);
                                row.get(0).setRightPadding(4f);
                            } else {
                                row.add(makeZelleLeer(true));
                                row.get(0).setColSpan(row.get(0).getColSpan() + 1);
                            }
                        }
                }
            }
            tableData.add(row);
            makeLeerzeile(tableData, Math.max(mSpaltenSatz.size(), 1), true);
        }
    }

    ArrayList<Einsatzort> makeEinsatzortListeAuswahl(
            Arbeitsplatz job, ArrayList<MultiSelectItem> auswahl
    ) {
        ArrayList<Einsatzort> liste;
        // die gesamte Einsatzortliste des Arbeitsplatzes oder
        // nur die ausgewählten Orte dieses Arbeitsplatzes
        if (mListeOrteAuswahl == null) {
            liste = new ArrayList<>(job.getEinsatzortListe().getAlle());
            // für alle Schichten ohne Einsatzort
            liste.add(null);
        } else {
            liste = new ArrayList<>();
            for (MultiSelectItem ort : auswahl) {
                if (ort.getIdArbeitsplatz() == job.getId()) {
                    liste.add(job.getEinsatzortListe().getOrt(ort.getIdOrt()));
                } else if (ort.getIdArbeitsplatz() == 0){
                    //alle Schichten ohne Einsatzort
                    liste.add(null);
                }
            }
        }
        return liste;
    }

    // die, neben der Haupttabelle angezeigte, Zusammenfassung
    @Override
    public List<List<Cell>> makeZusammenfassung(){
        List<List<Cell>> tableData = new ArrayList<>();
        ArrayList<Cell> row;

        // Titel
        tableData.add(
                makeZusammenfassungTitel(ASettings.res.getString(R.string.exp_zusam_zeitraum), true)
        );

        //Kalendertage
        row = new ArrayList<>();
        row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.kalendertage)));
        row.add(makeZelleWert(mZeitraum.getKalendertage(), ASettings.tageformat, false));
        tableData.add(row);

        // Arbeitstage Brutto
        row = new ArrayList<>();
        row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.arbeitstage)));
        row.add(makeZelleWert(mZeitraum.getArbeitstage(), ASettings.tageformat, false));
        tableData.add(row);

        // Abwesenheitstage
        float at = mZeitraum.getAbwesenheitstage();
        if (at > 0) {
            row = new ArrayList<>();
            row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.abwesend)));
            row.add(makeZelleWert(at, ASettings.tageformat, false));
            tableData.add(row);

            // Arbeitstage Netto
            at = mZeitraum.getArbeitstage() - at;
            if (at < 0) {
                at = 0;
            }
            row = new ArrayList<>();
            row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.arbeisttage_eff)));
            row.add(makeZelleWert(at, ASettings.tageformat, false));
            tableData.add(row);
        }

        // Sollstunden
        row = new ArrayList<>();
        Cell cel = makeZelleBezeichnung(ASettings.res.getString(R.string.sollstunden));
        cel.setTopPadding(16f);
        row.add(cel);
        cel = makeZelleStunden(
                mZeitraum.getSoll(),
                isDezimal,
                true,
                false);
        cel.setTopPadding(16f);
        row.add(cel);
        tableData.add(row);

        // Ist Stunden
        row = new ArrayList<>();
        row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.iststunden)));
        row.add(makeZelleStunden(
                mZeitraum.getIst(),
                isDezimal,
                true,
                false));
        tableData.add(row);

        // Differenz
        row = new ArrayList<>();
        row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.diff)));
        row.add(makeZelleStunden(
                mZeitraum.getIst() - mZeitraum.getSoll(),
                isDezimal,
                true,
                false));
        tableData.add(row);

        // wenn ein Teil Überstunden mit dem Lohn pauschal abgegolten wird,
        // diese hier anziegen
        if(mZeitraum.isMonat() && mArbeitsplatz.getUeberstundenPauschal() > 0) {
            int uep = mZeitraum.getIstNetto() - mZeitraum.getIst();
            if (uep < 0) {
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(
                        ASettings.res.getString(R.string.ueber_pauschal)));
                row.add(makeZelleStunden(
                        uep,
                        isDezimal,
                        true,
                        false));
                tableData.add(row);
            }
        }

        // Saldo Vormonat und ausbezahlte Überstunden
        if (mZeitraum.isMonat()) {
            int x = mZeitraum.getSaldoUebertrag();
            if (x != 0) {
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.saldo_vm)));
                row.add(makeZelleStunden(
                        x,
                        isDezimal,
                        true,
                        false));
                tableData.add(row);
            }

            //Ausbezahlte Überstunden
            x = mZeitraum.getAuszahlung();
            if (x != 0) {
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.ueberstunden_ausbezahlt)));
                row.add(makeZelleStunden(
                        -x,
                        isDezimal,
                        true,
                        false));
                tableData.add(row);
            }
        }

        // Saldo
        row = new ArrayList<>();
        row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.saldo)));
        row.add(makeZelleSummeStunden(
                mZeitraum.getSaldo(),
                isDezimal,
                true,
                true));
        tableData.add(row);

        // Verdienst
        if (mSpalten.get(SPALTE_VERDIENST)) {
            row = new ArrayList<>();
            row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.gehalt)));
            row.add(makeZelleWert(
                    mZeitraum.getVerdienst(),
                    ASettings.waehrungformat,
                    false
            ));
            tableData.add(row);
        }

        // Abwesenheiten auflisten
        tableData.add(makeZusammenfassungTitel(ASettings.res.getString(R.string.summe_tage), false));

        // die abwesenheiten - nur wenn nicht 0
        float mTage;
        Abwesenheit mAbwesenheit;
        String sAbwesenheit;
        Uhrzeit mStunden = new Uhrzeit(0);

        for (int i = Abwesenheit.ARBEITSZEIT; i < mArbeitsplatz.getAbwesenheiten().sizeAktive(); i++) {
            //mStunden.set(0);
            mAbwesenheit = mArbeitsplatz.getAbwesenheiten().getAktive(i);
            mTage = mZeitraum.getSummeAlternativTage(mAbwesenheit.getID());


            if (mTage > 0) {
                row = new ArrayList<>();
                sAbwesenheit = mAbwesenheit.getName();
                if (mAbwesenheit.getWirkung() == Abwesenheit.WIRKUNG_SOLL_MINUS_EFFEKTIV ||
                        mAbwesenheit.getWirkung() == Abwesenheit.WIRKUNG_SOLL_MINUS_STUNDEN) {
                    sAbwesenheit += ASettings.res.getString(R.string.exp_sollstunden_abzug);
                } else if (mAbwesenheit.getWirkung() == Abwesenheit.WIRKUNG_SOLL_MINUS_TAGE) {
                    sAbwesenheit += ASettings.res.getString(R.string.exp_solltage_abzug);
                }
                row.add(makeZelleBezeichnung(sAbwesenheit));
                row.add(makeZelleWert(mTage, ASettings.tageformat, false));
                if (mAbwesenheit.getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV) {
                    mStunden.set(mZeitraum.getSummeAlternativMinuten(mAbwesenheit.getID()));
                    row.add(
                            makeZelleString(
                                    " ("
                                            + mStunden.getStundenString(true, isDezimal)
                                            + ")",
                                    false
                            ));
                } else if (mAbwesenheit.getWirkung() == Abwesenheit.WIRKUNG_IST_PLUS_PAUSCHAL) {
                    mStunden.set(Math.round(mTage * mArbeitsplatz.getSollstundenTagPauschal(mZeitraum.getBeginn().getJahr(), mZeitraum.getBeginn().getMonat())));
                    row.add(
                            makeZelleStunden(
                                    mStunden.getAlsMinuten(),
                                    mArbeitsplatz.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL),
                                    true,
                                    false
                            ));
                }
                tableData.add(row);
            }
        }

        // Schichten auflisten
        // Schichtenliste erstellen
        SchichtListeZeitraum mSchichtliste = new SchichtListeZeitraum(mZeitraum.getTage());

        if (mSchichtliste.size() > 0) {
            //Überschrift
            tableData.add(makeZusammenfassungTitel(ASettings.res.getString(R.string.summe_schichten), false));

            // die Schichten wenn gearbeitet
            for (SchichtListeZeitraum.Schicht mSchicht : mSchichtliste.getListe()) {
                row = new ArrayList<>();

                if ("".equals(mSchicht.getName()))
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.no_name)));
                else
                    row.add(makeZelleBezeichnung(mSchicht.getName()));

                row.add(makeZelleStunden(
                        mSchicht.getMinuten().getAlsMinuten(),
                        isDezimal,
                        true,
                        false));
                row.add(makeZelleString(
                        " ("
                                + ASettings.tageformat.format(mSchicht.getAnzahl())
                                + ")",
                        false
                ));
                tableData.add(row);
            }
        }


        // Urlaubsübersicht
        if (mZeitraum.isMonat()) {
            if (mArbeitsplatz.getSoll_Urlaub() > 0) {
                Arbeitsjahr_summe mJahr = new Arbeitsjahr_summe(
                        mZeitraum.getBeginn().get((Calendar.YEAR)),
                        mArbeitsplatz
                );
                int monat = mZeitraum.getBeginn().get(Calendar.MONTH);
                Datum mAktuell = mArbeitsplatz.getAbrechnungsmonat(ASettings.aktDatum);

                float mRestSoll = mJahr.getResturlaub();
                float mRestBezogen = mJahr.bezogenRest[monat];
                float mRestIst = mJahr.restUrlaubIstMonat[monat];
                float mRestSaldo = mRestSoll - mRestIst;

                float mBezogenMonat = mJahr.bezogenUrlaub[monat];
                float mBezogenGesamt = mJahr.istUrlaubMonat[monat];
                float mAnspruch = mJahr.getUrlaubSoll();
                float mGeplant = mJahr.getUrlaubGeplant();
                float mGeplantMonat;
                float mGeplantResturlaub;
                boolean isVerfallen = mJahr.isUrlaubVerfallen(monat);
                DecimalFormat anzeigeFormat =
                        mArbeitsplatz.isOptionSet(Arbeitsplatz.OPT_URLAUB_ALS_STUNDEN) ?
                                ASettings.stundenformat :
                                ASettings.tageformat;

                // aufteilen des geplanten Urlaubs für diesen Monat
                // in Anteil zum Abbau von Resturlaub und regulären Urlaubsanspruch
                if (mZeitraum.getBeginn().istGleich(mAktuell, Calendar.MONTH)) {
                    mGeplantMonat = mJahr.geplanterUrlaubAktMonat;

                    if (mRestSaldo > 0) {
                        mGeplantResturlaub = mGeplantMonat;
                        // den zuviel vom Resturlaub abgezogenen Urlaub auf den geplanten Urlaub übertragen
                        if (mRestSaldo - mGeplantResturlaub < 0) {
                            mGeplantMonat = 0 - (mRestSaldo - mGeplantResturlaub);
                            mGeplantResturlaub -= mGeplantMonat;
                        } else {
                            mGeplantMonat = 0;
                        }
                        // den bezogenen Resturlaub korrigieren
                        mRestBezogen += mGeplantResturlaub;

                        mRestIst += mGeplantResturlaub;
                        mRestSaldo -= mGeplantResturlaub;
                    }
                }

                // Titel
                if (mArbeitsplatz.isOptionSet(Arbeitsplatz.OPT_URLAUB_ALS_STUNDEN)) {
                    tableData.add(
                            makeZusammenfassungTitel(ASettings.res.getString(R.string.urlaub_stunden), false)
                    );
                } else {
                    tableData.add(
                            makeZusammenfassungTitel(ASettings.res.getString(R.string.urlaub_tage), false)
                    );
                }

                // Resturlaub
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(
                        ASettings.res.getString(R.string.titel_resturlaub, mJahr.Jahr-1)
                ));
                tableData.add(row);

                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.resturlaub)));
                row.add(makeZelleWert(mRestSoll, anzeigeFormat, false));
                tableData.add(row);

                // Resturlaub bezogen in diesen Monat
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.abgebaut_monat)));
                if (mRestSoll > 0)
                    row.add(makeZelleWert(mRestBezogen, anzeigeFormat, false));
                tableData.add(row);

                // Resturlaub bezogen
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.abgebaut_gesamt)));
                row.add(makeZelleWert(mRestIst, anzeigeFormat, false));
                tableData.add(row);

                // Resturlaub Saldo
                if (mRestSaldo < 0)
                    mRestSaldo = 0;
                row = new ArrayList<>();
                if (isVerfallen)
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.verfallen)));
                else
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.rest)));
                row.add(makeZelleWert(mRestSaldo, anzeigeFormat, false));
                if (mJahr.isUrlaubVerfallen(monat))
                    row.get(row.size() - 1).setStrikeout(true);
                tableData.add(row);

                // Urlaubsanspruch
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(
                        ASettings.res.getString(R.string.titel_anspruch, mJahr.Jahr)
                ));
                row.get(0).setTopPadding(8f);
                tableData.add(row);
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.anspruch)));
                row.add(makeZelleWert(mAnspruch, anzeigeFormat, false));
                tableData.add(row);

                // Urlaub bezogen diesen Monat
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.bezogen_monat)));
                row.add(makeZelleWert(mBezogenMonat, anzeigeFormat, false));
                tableData.add(row);

                // Urlaub bezogen bis zu diesen Monat
                row = new ArrayList<>();
                row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.bezogen_gesamt)));
                row.add(makeZelleWert(mBezogenGesamt, anzeigeFormat, false));
                tableData.add(row);

                // Urlaub Saldo + Resturlaub Saldo
                if (mRestSaldo > 0 && !isVerfallen) {
                    // Saldo Urlaubsanspruch
                    mAnspruch -= mBezogenGesamt;
                    row = new ArrayList<>();
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.rest)));
                    row.add(makeZelleWert(mAnspruch, anzeigeFormat, false));
                    tableData.add(row);

                    // Saldo Urlaubsanspruch + Resturlaub
                    row = new ArrayList<>();
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.restanspruch)));
                    row.add(makeZelleSummeWert(mAnspruch + mRestSaldo, anzeigeFormat, true));
                    row.get(0).setTopPadding(8f);
                    row.get(1).setTopPadding(8f);
                    tableData.add(row);
                } else {
                    // Saldo Urlaubsanspruch
                    row = new ArrayList<>();
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.restanspruch)));
                    row.add(makeZelleSummeWert(mAnspruch - mBezogenGesamt, anzeigeFormat, isVerfallen));
                    tableData.add(row);
                }


                // wenn noch geplanter Urlaub offen ist und es der aktuelle Monat ist
                if (mZeitraum.getBeginn().istGleich(mAktuell, Calendar.MONTH) && mGeplant > 0) {
                    row = new ArrayList<>();
                    row.add(makeZelleBezeichnung(ASettings.res.getString(R.string.geplant_urlaub)));
                    row.add(makeZelleWert(mGeplant, anzeigeFormat, false));
                    row.get(1).setFgColor(ASettings.res.getColor(R.color.bpDarker_blue));
                    row.get(0).setTopPadding(8f);
                    row.get(1).setTopPadding(8f);
                    tableData.add(row);
                }
            }
        }

        // Zusatzwerte anzeigen, wenn Sie auch in der Tabelle angezeigt werden und nicht 0 sind
        if (mZeitraum.getZusatzeintragSummenListe().size() > 0) {
            ArrayList<IZusatzfeld> zusatzWerteSummen = mZeitraum.getZusatzeintragSummenListe().getListe();

            // wenn in der Tabelle Zusatzwerte angezeigt werden, dann diese hier auch anzeigen
            boolean werteListe = false;
            int index = 0;
            for (Spalte spalte : mSpaltenSatz) {
                if (spalte.mSpalte >= SPALTE_ZUSATZ) {
                    werteListe = true;
                    tableData.add(makeZusammenfassungTitel(
                            ASettings.res.getString(R.string.sonstige), false)
                    );
                    break;
                }
                index++;
            }
            /*for (IZusatzfeld feld : zusatzWerteSummen) {
                if (feld.getDatenTyp() > 0) {
                    werteListe = true;
                    tableData.add(makeZusammenfassungTitel(ASettings.res.getString(R.string.sonstige), false));
                    break;
                }
            }*/
            if (werteListe) {
                Spalte aktSpalte;
                IZusatzfeld aktFeld;
                for (int i = index; i < mSpaltenSatz.size(); i++) {
                    aktSpalte = mSpaltenSatz.get(i);
                    if(aktSpalte.mSpalte >= SPALTE_ZUSATZ) {
                        aktFeld = zusatzWerteSummen.get(aktSpalte.mSpalte - SPALTE_ZUSATZ);
                        switch (aktFeld.getDatenTyp()) {
                            case IZusatzfeld.TYP_BEREICH_ZAHL:
                            case IZusatzfeld.TYP_ZAHL:
                                row = new ArrayList<>();
                                row.add(makeZelleBezeichnung(aktFeld.getName()));
                                row.add(makeZelleWert(
                                        (float) aktFeld.getWert(),
                                        ASettings.zahlenformat,
                                        false));
                                row.add(makeZelleString(aktFeld.getEinheit(), false));
                                tableData.add(row);
                                break;
                            case IZusatzfeld.TYP_BEREICH_ZEIT:
                            case IZusatzfeld.TYP_ZEIT:
                                row = new ArrayList<>();
                                row.add(makeZelleBezeichnung(aktFeld.getName()));
                                row.add(makeZelleStunden(
                                        (int) aktFeld.getWert(),
                                        isDezimal,
                                        false,
                                        false));
                                row.add(makeZelleString(aktFeld.getEinheit(), false));
                                tableData.add(row);
                                break;
                        }
                    }
                }
                /*for (IZusatzfeld zFeld : zusatzWerteSummen) {
                    switch (zFeld.getDatenTyp()) {
                        case IZusatzfeld.TYP_BEREICH_ZAHL:
                        case IZusatzfeld.TYP_ZAHL:
                            row = new ArrayList<>();
                            row.add(makeZelleBezeichnung(zFeld.getName()));
                            row.add(makeZelleWert(
                                    (float) zFeld.getWert(),
                                    ASettings.zahlenformat,
                                    false));
                            row.add(makeZelleString(zFeld.getEinheit(), false));
                            tableData.add(row);
                            break;
                        case IZusatzfeld.TYP_BEREICH_ZEIT:
                        case IZusatzfeld.TYP_ZEIT:
                            row = new ArrayList<>();
                            row.add(makeZelleBezeichnung(zFeld.getName()));
                            row.add(makeZelleStunden(
                                    (int) zFeld.getWert(),
                                    isDezimal,
                                    false,
                                    false));
                            row.add(makeZelleString(zFeld.getEinheit(), false));
                            tableData.add(row);
                            break;
                    }
                }*/
            }
        }
        return tableData;
    }

}