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

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

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;

import java.util.ArrayList;
import java.util.Calendar;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.abwesenheiten.Abwesenheit;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.Arbeitsschicht;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.SchichtDefault;
import askanimus.arbeitszeiterfassung2.datenbank.DatenbankHelper;
import askanimus.arbeitszeiterfassung2.Ics.icsTermin;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzWertListe;

/**
 * @author askanimus@gmail.com on 08.08.15.
 */
public class Arbeitstag {
    private final static String SQL_READ_TAG =
            "select "
                + DatenbankHelper.DB_F_ID
                + " from " + DatenbankHelper.DB_T_TAG
                + " where " + DatenbankHelper.DB_F_JAHR + " = ? AND "
                + DatenbankHelper.DB_F_MONAT + " = ? AND "
                + DatenbankHelper.DB_F_TAG + " = ? AND "
                + DatenbankHelper.DB_F_JOB + " = ?"
                + " limit 1";

    private final static String SQL_READ_SCHICHTEN =
            "select * from "
                    + DatenbankHelper.DB_T_SCHICHT
                    + " where "
                    + DatenbankHelper.DB_F_TAG
                    + " = ?"
                    + " ORDER BY "
                    + DatenbankHelper.DB_F_NUMMER;


    //Variablen
    private long TagId;
    private final Arbeitsplatz mArbeitsplatz;
    private final Datum dTag;
    private final int wochenTag;
    private int tagSoll;  // Sollstunden für diesen Tag
    private int tagSollPauschal;
    private ArrayList<Arbeitsschicht> Schichten;

    private Boolean istGeandert = false;

    @SuppressLint("Range")
    public Arbeitstag(
            Calendar tag,
            Arbeitsplatz job,
            int sollTag,
            int sollTagPauschal
    ){
        dTag = new Datum(tag.getTime(), job.getWochenbeginn());
        wochenTag = dTag.get(Calendar.DAY_OF_WEEK);
        mArbeitsplatz = job;
        tagSoll = sollTag;
        tagSollPauschal = sollTagPauschal;

        Cursor resultTag = ASettings.mDatenbank.rawQuery(SQL_READ_TAG, new String[]{
                Integer.toString(dTag.get(Calendar.YEAR)),
                Integer.toString(dTag.get(Calendar.MONTH)),
                Integer.toString(dTag.get(Calendar.DAY_OF_MONTH)),
                Long.toString(mArbeitsplatz.getId())
        });
        if (resultTag.getCount() > 0) {
            resultTag.moveToFirst();
            TagId = resultTag.getLong(resultTag.getColumnIndex(DatenbankHelper.DB_F_ID));

            // die Schichten eines Tages lesen
            Cursor resultSchichten = ASettings.mDatenbank.rawQuery(SQL_READ_SCHICHTEN,  new String[]{
                    Long.toString(TagId)
            });

            if (resultSchichten.getCount() > 0){
                Schichten = new ArrayList<>();
                // wenn Teilschichten eingestellt sind
                // die Schichtliste mit der Anzahl Teilschichten aber leeren Elementen anlegen
                if(mArbeitsplatz.isTeilschicht()){
                    for (int i = 0; i < mArbeitsplatz.getAnzahlSchichtenTag(); i++) {
                        Schichten.add(null);
                    }
                }

                while (resultSchichten.moveToNext()) {
                    // die Schicht erzeugen
                    Arbeitsschicht neueSchicht = new Arbeitsschicht(
                            mArbeitsplatz,
                            //(byte) wochenTag,
                            resultSchichten,
                            dTag,
                            tagSoll,
                            tagSollPauschal
                    );

                    // im Teilschichtbetrieb die erzeugten Schichten in der Reihenfolge der
                    // Defaultschichten einordnen
                    if (mArbeitsplatz.isTeilschicht()) {
                        SchichtDefault sd = mArbeitsplatz
                                .getDefaultSchichten()
                                .getVonId(neueSchicht.getDefaultSchichtId());
                        if (sd != null
                                && neueSchicht.getNummer() < Schichten.size()
                                && sd.getStatus() == ISettings.STATUS_AKTIV
                                /*&& sd.getPosition() < Schichten.size()
                                && Schichten.get(sd.getPosition()) == null*/)
                        {
                            Schichten.set(sd.getPosition(), neueSchicht);
                        } else {
                            Schichten.add(neueSchicht);
                        }
                    } else {
                       Schichten.add(neueSchicht);
                    }
                }

                if (mArbeitsplatz.isTeilschicht()) {
                    // mit leeren, nicht gespeicherten, Schichten auffüllen
                    for (int i = 0; i < mArbeitsplatz.getAnzahlSchichtenTag(); i++) {
                        if (Schichten.get(i) == null) {
                            Schichten.set(i, new Arbeitsschicht(
                                    i,
                                    mArbeitsplatz,
                                    TagId,
                                    //(byte) wochenTag,
                                    mArbeitsplatz.getDefaultSchichten().getAktive(i),
                                    dTag,
                            tagSoll,
                            tagSollPauschal)
                            );
                        }
                    }
                } else {
                    // eine leere Schicht einfügen wenn die gespeicherte eine von Hand angelegte war
                    // und die erste Schicht leer war, also nicht gespeichert wurde
                    if(Schichten.get(0).getNummer() > 0) {
                        if (mArbeitsplatz.getAnzahlSchichten() == 1) {
                            addSchicht(0, mArbeitsplatz.getDefaultSchichten().getAktive(0));
                        } else {
                            addSchicht(0, "");
                        }
                    }
                }

                // in leere  1. Schicht am Wochenenden "Ruhetag" eintragen
                setWochenende();
            } else {
                // für den Tag sind keine Schichten gespeichert, also leere anlegen
                neueSchichten(ASettings.feiertage.getFeiertag(dTag));
            }
            resultSchichten.close();
        } else {
            // neuen Tag inkl. der Schichten anlegen
            TagId = -1;
            istGeandert = true;
            speichern();
            neueSchichten(ASettings.feiertage.getFeiertag(dTag));
        }

        resultTag.close();
        // ASettings.ASettings.mDatenbank.close();
    }

    /*
     * Arbeitstag mit all seinen Schichten kopieren
     */
    public Arbeitstag copy(Datum zielDatum) {
        Arbeitstag zielArbeitstag = new Arbeitstag(
                zielDatum.getCalendar(),
                mArbeitsplatz,
                ASettings.aktJob.getSollstundenTag(zielDatum),
                ASettings.aktJob.getSollstundenTagPauschal(zielDatum.get(Calendar.YEAR), zielDatum.get(Calendar.MONTH))
        );
        int mArbeitstag = (int) (ASettings.aktJob.getArbeitstag(zielDatum.get(Calendar.DAY_OF_WEEK)) * 2);
        // Ist der Zieltag kein definierter Ruhetag (halb oder ganz)
        // dann Quellschicht kopieren
        // sonst Ruhetag eintragen und restliche Schichten löschen
        if (mArbeitstag >= 2) {
            // alte Schichten löschen
            for (int i = zielArbeitstag.getSchichtAnzahl(); i > 0; i--) {
                zielArbeitstag.loescheSchicht(i - 1);
            }
            // Daten übertragen und speichern
            for (int i = 0; i < getSchichtAnzahl(); i++) {
                if (ASettings.aktJob.isTeilschicht() ||
                        getSchicht(i).getAbwesenheit().getKategorie() != Abwesenheit.KAT_KEINESCHICHT)
                    zielArbeitstag.copySchicht(getSchicht(i));
            }
        } else {
            zielArbeitstag.getSchicht(0).setAbwesenheit(
                    ASettings.aktJob.getAbwesenheiten().getAktive(Abwesenheit.RUHETAG),
                    mArbeitstag == 0 ? 100 : 50);
            for (int i = zielArbeitstag.getSchichtAnzahl(); i > 1; i--) {
                zielArbeitstag.loescheSchicht(i - 1);
            }
        }

        return zielArbeitstag;
    }

    private void neueSchichten(icsTermin feiertag) {
        //int arbeisschicht = (int)(mArbeitsplatz.getArbeitstag(tag.get(Calendar.DAY_OF_WEEK)) * 2);
        Schichten = new ArrayList<>();
        if (mArbeitsplatz.isTeilschicht()) {
            for (int i = 0; i < mArbeitsplatz.getAnzahlSchichten(); i++) {
                addSchicht(-1, mArbeitsplatz.getDefaultSchichten().getAktive(i));
            }
        } else {
            if (mArbeitsplatz.getAnzahlSchichten() == 1) {
                addSchicht(0, mArbeitsplatz.getDefaultSchichten().getAktive(0));
            } else {
                addSchicht(0, "");
            }
        }
        setWochenende();
        if(feiertag != null) {
            addSchicht(-1, feiertag.getName());
            Schichten.get(Schichten.size() - 1).setAbwesenheit(mArbeitsplatz.getAbwesenheiten().getVonKategorie(Abwesenheit.KAT_FEIERTAG), 100);
        }
    }


    //
    // neue Schicht hinzufügen
    //
    public void addSchicht(int position, String name) {
        if (position >= 0) {
            Schichten.add(position, new Arbeitsschicht(
                    position,
                    mArbeitsplatz,
                    TagId,
                    //(byte) wochenTag,
                    name,
                    dTag,
                    tagSoll,
                    tagSollPauschal));
            // Position der Nachfolgenden Schichten verschieben
            position++;
            for (int i = position; i < Schichten.size(); i++) {
                Schichten.get(i).setPositionInListe(position);
            }
        } else
            Schichten.add(new Arbeitsschicht(
                    Schichten.size(),
                    mArbeitsplatz,
                    TagId,
                    //(byte) wochenTag,
                    name,
                    dTag,
                    tagSoll,
                    tagSollPauschal));
    }

    //
    // neue Schicht hinzufügen und daten der übergebenen  kopieren
    //
    void copySchicht(Arbeitsschicht schicht) {
        Schichten.add(new Arbeitsschicht(
                TagId,
                schicht,
                tagSoll,
                tagSollPauschal));
    }

    //
    // neue Schicht hinzufügen
    //
    public void addSchicht(int position, SchichtDefault dSchicht) {
        if (position >= 0) {
            Schichten.add(position, new Arbeitsschicht(
                    position,
                    mArbeitsplatz,
                    TagId,
                    //(byte) wochenTag,
                    dSchicht,
                    dTag,
                    tagSoll,
                    tagSollPauschal));
            // Position der Nachfolgenden Schichten verschieben
            position++;
            for (int i = position; i < Schichten.size(); i++) {
                Schichten.get(i).setPositionInListe(position);
            }
        } else {
            Schichten.add(new Arbeitsschicht(
                    Schichten.size(),
                    mArbeitsplatz,
                    TagId,
                    //(byte) wochenTag,
                    dSchicht,
                    dTag,
                    tagSoll,
                    tagSollPauschal));
        }
    }


    //
    // Ruhetag in die erste Schicht eintragen wenn diese noch leer ist und der Tag ein (festgelegter) Wochenendtag ist
    private void setWochenende() {
        try {
            if (Schichten.get(0).getAbwesenheit().getKategorie() == Abwesenheit.KAT_KEINESCHICHT) {
                int arbeitsschicht = (int) (mArbeitsplatz.getArbeitstag(wochenTag) * 2);
                if (arbeitsschicht < 2) {
                    if (arbeitsschicht == 0) {
                        Schichten.get(0).setAbwesenheit(mArbeitsplatz.getAbwesenheiten().getAktive(Abwesenheit.RUHETAG), 100);
                    } else {
                        Schichten.get(0).setAbwesenheit(mArbeitsplatz.getAbwesenheiten().getAktive(Abwesenheit.RUHETAG), 50);
                        if (!mArbeitsplatz.isTeilschicht() && Schichten.size() == 1) {
                            addSchicht(-1, "");
                        }
                    }
                }
            }
        } catch (NullPointerException ne){
            ne.printStackTrace();
        }

    }

    //
    // Schicht löschen
    //
    public void loescheSchicht(int nummer) {
        if (nummer < Schichten.size()) {
            Schichten.get(nummer).loeschen();
            Schichten.remove(nummer);
        }
    }

    //
    // Daten des Tages in datenbank schreiben
    //
    private void speichern() {
        if (istGeandert) {
            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
            ContentValues werte = new ContentValues();

            werte.put(DatenbankHelper.DB_F_JOB, mArbeitsplatz.getId());
            werte.put(DatenbankHelper.DB_F_JAHR, dTag.get(Calendar.YEAR));
            werte.put(DatenbankHelper.DB_F_MONAT, dTag.get(Calendar.MONTH));
            werte.put(DatenbankHelper.DB_F_TAG, dTag.get(Calendar.DAY_OF_MONTH));

            if (TagId < 0) {
                TagId = ASettings.mDatenbank.insert(DatenbankHelper.DB_T_TAG, null, werte);
            } else {
                // Bestehenden updaten
                ASettings.mDatenbank.update(
                        DatenbankHelper.DB_T_TAG, werte,
                        DatenbankHelper.DB_F_ID + "=?",
                        new String[]{Long.toString(TagId)}
                );
            }
            // ASettings.ASettings.mDatenbank.close();
            istGeandert = false;
        }
    }


    //
    // Daten eines Tages aus der datenbank löschen
    //
    public void loeschen() {
        // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
        // alle Schichten des Tages löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_SCHICHT, DatenbankHelper.DB_F_TAG + "=?", new String[]{Long.toString(TagId)});
        // den Tag löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_TAG, DatenbankHelper.DB_F_ID + "=?", new String[]{Long.toString(TagId)});

        // ASettings.mDatenbank.close();
    }


    //
    // Werte einer Schicht haben sich geändert
    //
    protected void updateSchicht(long schicht) {
        for (int i = 0; i < Schichten.size(); i++) {
            if (schicht == Schichten.get(i).getID()) {
                Schichten.get(i).reload();
                break;
            }
        }
    }

    //
    // die berechnet Werte eines Tages aktuallisieren weil sich die Sollstundeneinstellungen geändert haben
    //
    public void updateSollTag(int sollPauschal){
        tagSollPauschal = sollPauschal;
        tagSoll = mArbeitsplatz.getSollstundenTag(dTag);

        for (Arbeitsschicht schicht : Schichten ) {
            schicht.setTagSoll(tagSoll, tagSollPauschal);
        }
    }


    // Werteingaben

    // Wertrückgaben und Berechnungen
    public long getTagId() {
        return TagId;
    }

    public Arbeitsplatz getArbeitsplatz(){
        return mArbeitsplatz;
    }

    protected int getJahr() {
        return dTag.get(Calendar.YEAR);
    }

    protected int getMonat() {
        return dTag.get(Calendar.MONTH);
    }

    /*public int getTagimMonat() {
        return dTag.get(Calendar.DAY_OF_MONTH);
    }*/

    public int getWochentag() {
        return wochenTag;
    }

    public Datum getKalender() {
        return dTag;
    }

    protected int getBis(int schicht) {
        return Schichten.get(schicht).getBis();
    }

    protected int getVon(int schicht) {
        return Schichten.get(schicht).getVon();
    }

    protected int getPause(int schicht) {
        return Schichten.get(schicht).getPause();
    }

    protected String getName(int schicht) {
        return Schichten.get(schicht).getName();
    }

    public Arbeitsschicht getSchicht(int schicht) {
        if (Schichten.size() > schicht)
            return Schichten.get(schicht);
        else
            return null;
    }

    public Arbeitsschicht getSchicht(long schichtID){
        if(schichtID == 0){
            addSchicht(Schichten.size(), "");
            return Schichten.get(Schichten.size()-1);
        } else {
            for (Arbeitsschicht s : Schichten) {
                if(s.getID() == schichtID){
                    return s;
                }
            }
        }
        return null;
    }

    /**
     * gibt die Brutto Sollstunden des Tages zurück
     * @return Sollstunden in Minuten
     */
    public int getTagSollBrutto(){
        return tagSoll;
    }

    /**
     * gibt die Netto Sollstunden des Tages zurück
     * Brutto Sollstunden minus die Zeiten von Abwesenheiten, die Sollstunden bzw. Solltage verringern
     * @return Sollstunden in Minuten
     */
    public int getTagSollNetto() {
        int mSoll = tagSoll;

        if (mSoll > 0) {
            if (mArbeitsplatz.getModell() == Arbeitsplatz.Soll_Woche_rollend) {
                float anteilRuhetag = getKategorieTag(Abwesenheit.KAT_RUHETAG);
                mSoll -= Math.round(tagSoll * anteilRuhetag);
            }

            if (mSoll > 0) {
                mSoll -= ((getAbzugTag() * tagSoll));
                mSoll -= getAbzugMinuten();
            }
        }

        return Math.max(mSoll, 0);
    }

    /**
     * Brutto Arbeitszeit des Tages
     * @return Arbeitszeit in Minuten
     */
    public int getTagBrutto() {
        int wert = 0;
        for (int i = 0; i < Schichten.size(); i++) {
            wert += Schichten.get(i).getBrutto();
        }
        return wert;
    }

    /**
     * Netto Tagesarbeitszeit des Tages
     * Brutto minus Pausenzeit, wenn es Arbeitszeit ist und Pausen von der Arbeitszeit abgezogen werden sollen
     * @return Arbeitszeit in Minuten
     */
    public int getTagNetto() {
        int wert = 0;
        for (int i = 0; i < Schichten.size(); i++) {
            wert += Schichten.get(i).getNetto();
        }
        return wert;
    }

    /**
     * Pausenzeiten des Tages
     * @return Pausenzeit in Minuten
     */
    public int getTagPause() {
        int wert = 0;
        for (int i = 0; i < Schichten.size(); i++) {
            wert += Schichten.get(i).getPause();
        }
        return wert;
    }

    /**
     * Der Saldo des Tages
     * Netto Arbeitszeit minus Netto Sollstunden
     * @return Saldo in Minuten
     */
    public int getTagSaldo(){
        return getTagNetto() - getTagSollNetto();
    }

   public IZusatzfeld getTagZusatzwert(int i){
       IZusatzfeld wert = mArbeitsplatz.getZusatzDefinition(i).makeNewZusatzfeld();
       for (Arbeitsschicht schicht : Schichten) {
           wert.add(schicht.getZusatzwert(i));
       }
       return wert;
   }

    //
    // gibt eine Liste der summierten Zusatzeinträge zurück
    //
    public ZusatzWertListe getTagZusatzwerte(int TextOption) {
        // Zusatzwerteliste mit 0-Werten anlegen
        ZusatzWertListe werte = new ZusatzWertListe(mArbeitsplatz.getZusatzfeldListe(), TextOption > IZusatzfeld.TEXT_NO);
        for (Arbeitsschicht schicht : Schichten) {
            ZusatzWertListe liste = schicht.getZusatzfelder(TextOption);
            if( liste.size() > 0) {
                werte.addListenWerte(liste);
            }
        }

        return werte;
    }


    /**
     * Verdienst des Tages berechen.
     * Gearbeitete Stunden werden alle zur Berechnung hearan gezogen.
     * Korrigiert wird der Verdienst ncoh durch evtl. vorhandene Zusatzeinträge
     * die Einfluss auf den Verdienst nehmen
     * @return Verdienst
     */
    public float getTagVerdienst(){
        float verdienstMinuten = 0;
        float korrekturVerdienst = 0;
        float verdienst;
        // Anzahl Minuten die für den Verdienst relevant sind ermitteln
        // Summe der, den Verdienst korrigierenten Zusatzwerte lesen
        for (Arbeitsschicht s: Schichten) {
            verdienstMinuten += s.getVerdienstMinuten();
            // Überstunden werden nicht zum Verdienst gerechnet
            // diese werden erst am Monatsende angerechnet wenn bezahlte Überstzunden eingetragen werden
            /* if (getTagSollBrutto() > 0){
                verdienstMinuten = Math.min(getTagSollBrutto(), verdienstMinuten);
            } */
            korrekturVerdienst += s.getKorrekturVerdienst(verdienstMinuten);
        }
        // Minuten in Stunden umrechnen
        float stunden = verdienstMinuten / 60;

        // verdienst berechnen
        verdienst = stunden * mArbeitsplatz.getStundenlohn();
        verdienst += korrekturVerdienst;

        // Verdienst auf zwei Nachkommastellen runden
        verdienst = Math.round(verdienst * 100.0f) / 100.0f;

        return verdienst;
    }

    /*
     * Verdienst des Tages berechen.
     * Gearbeitete Stunden werden max. bis zu den Sollstunden des Tages gewertet
     * Überstunden werden erst ausbezahlt,
     * wenn Sie in der Monatsansicht als bezahlt eingetragen werden.
     * Korrigiert wird der Verdienst noch durch evtl. vorhandene Zusatzeinträge
     * die Einfluss auf den Verdienst nehmen
     * @return Verdienst
     */
    /*public float getTagVerdienstBisMaximalSoll() {
        float verdienstMinuten = 0;
        float korrekturVerdienst = 0;
        float verdienst;
        // Anzahl Minuten die für den Verdienst relevant sind ermitteln
        // Summe der, den Verdienst korrigierenten Zusatzwerte lesen
        for (Arbeitsschicht s: Schichten) {
            verdienstMinuten += s.getVerdienstMinuten();
            korrekturVerdienst += s.getKorrekturVerdienst();
        }
        // Anzahl Minuten auf Sollminuten reduzieren
        if(verdienstMinuten > tagSoll){
           verdienstMinuten = tagSoll;
        }
        // Minuten in Stunden umrechnen
        float stunden = verdienstMinuten / 60;

        // verdienst berechnen
        verdienst = stunden * mArbeitsplatz.getStundenlohn();
        verdienst += korrekturVerdienst;

        // Verdienst auf zwei Nachkommastellen runden
        verdienst = Math.round(verdienst * 100.0f) / 100.0f;

        return verdienst;
    }*/

    /**
      * Summe der, den Verdienst korigierenden, Zusatzeinträge
      * @return Summe der Korrekturen
      */
    public float getTagVerdienstKorrektur(float verdienstMinuten){
        float korrektur = 0;
        for (Arbeitsschicht s: Schichten) {
            korrektur += s.getKorrekturVerdienst(verdienstMinuten);
        }
        return korrektur;
    }

    /**
      * Anzahl der Minuten des Tages, die als Verdienst gerechnet werden
      * Summe der Korrekturen aus den Zusatzeinträgen
      * @return VerdienstWerte[Minuten, Korrektursumme]
     */
    public float[] getTagVerdienstWerte() {
        float verdienstMinuten;
        float[] verdienstWerte = {0, 0};
        for (Arbeitsschicht s : Schichten) {
            verdienstMinuten = s.getVerdienstMinuten();
            verdienstWerte[0] += verdienstMinuten;
            verdienstWerte[1] += s.getKorrekturVerdienst(verdienstMinuten);
        }
        return verdienstWerte;
    }

    //
    // Anzahl der realen Schichten des Tages
    //
    public int getSchichtAnzahl() {
        return Schichten.size();
    }


    //
    // Berechnet den Anteil in Minuten
    //  mit der Wirkung ZUS_SOLL_MINUS_SUNDEN, ZUS_SOLL_MINUS_EFFEKTIV
    //
    public int getAbzugMinuten() {
        int wert = 0;

        for (int i = 0; i < Schichten.size(); i++) {
            wert += Schichten.get(i).getMinusSollMinuten();
        }
        return (Math.min(wert, tagSoll));
    }

    public int getAlternativMinuten(long ZusatzID) {
        int wert = 0;
        Abwesenheit abw;

        for (Arbeitsschicht s : Schichten) {
            abw = s.getAbwesenheit();
            if (abw.getID() == ZusatzID) {
                switch (abw.getWirkung()) {
                    case Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_IST_PLUS_PAUSCHAL:
                        wert += s.getNetto();
                        break;
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_STUNDEN:
                        wert += s.getMinusSollMinuten();
                        break;
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_TAGE:
                        wert += Math.round(s.getMinusSollTage() * tagSoll);
                }
            }
        }

        return wert;
    }


    // gibt die Abwesenheit in Tagen zurück
    // Zählt alle Abwesenheitstage d. h. Tage in der ein Zusatz mit der Wirkung ZUS_SOLL_MINUS_TAGE
    public float getAbzugTag() {
        float wert = 0;

        for (int i = 0; i < Schichten.size(); i++) {
            wert += Schichten.get(i).getMinusSollTage();
        }

        return ((wert >= 1) ? 1 : wert);
    }

    /**
     *
     * gibt den Anteil der An-/Abwesenheit am Tag zurück
     *
     * @param abwesenheit  id der gesuchten An-/Abwesenheit
     * @return wert zwischen 0 und 1
     */
    public float getAlternativTag(long abwesenheit) {
        float wert = 0;
        Abwesenheit abw;
        int ist;

        for (int i = 0; i < Schichten.size(); i++) {
            abw = Schichten.get(i).getAbwesenheit();
            if (abw.getID() == abwesenheit) {
                // die gesuchte Abwesenheit bewerten
                switch (abw.getWirkung()) {
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV:
                        if(tagSollPauschal > 0) {
                            float einProzentSoll = tagSoll;
                            if (einProzentSoll == 0)
                                einProzentSoll = tagSollPauschal;

                            einProzentSoll /= 100;
                            if (Schichten.get(i).getBis() > 0 || Schichten.get(i).getVon() > 0) {
                                ist = Schichten.get(i).getBis() - Schichten.get(i).getVon();
                                if (ist <= 0)
                                    ist += ISettings.Minuten_TAG;
                                wert += ist * einProzentSoll;
                            }
                        } else {
                            // wenn 0 Sollstunden eingestellt sind wird das einmalige Vorkommen
                            // der Abwesenheit als ein Tag gezählt
                            return 1;
                        }
                        break;
                    default:
                        wert += Schichten.get(i).getBis();
                        break;
                }
            }
        }

        if (wert > 100)
            wert = 100;

        return wert / 100;
    }

    //
    // Anteil des Tages mit einer bestimmten Kategorie zurück geben
    //
    public float getKategorieTag(int kategorie){
        //int schwellwert = 100;
        float wert = 0;
        //float einProzentSoll = (tagSoll == 0) ? tagSollPauschal : tagSoll;
        //einProzentSoll /= 100;

        for (Arbeitsschicht schicht : Schichten) {
            if (schicht.getAbwesenheit().getKategorie() == kategorie) {
                int w = schicht.getWirkung();
                int ist;

                switch (w) {
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV:
                        float einProzentSoll = (tagSoll == 0) ? tagSollPauschal : tagSoll;
                        einProzentSoll /= 100;
                        if (schicht.getBis() > 0 || schicht.getVon() > 0) {
                            ist = schicht.getBis() - schicht.getVon();
                            if (ist <= 0)
                                ist = ISettings.Minuten_TAG + ist;
                            wert += ist / einProzentSoll;
                        }
                        break;
                    default:
                        wert += (schicht.getBis() * mArbeitsplatz.getArbeitstag(wochenTag));
                        // wenn in den Einstellungen dieser Tag eine geringere Sollstundenzahl
                        // als die durchschnittliche hat, wird dieser Tag anteilig berechnet.
                        // z.B.: 40h Woche Mo.-Do. 9h und Freitag 4h,
                        // dann Freitag als halben Tag zählen
                        /*if (tagSoll > 0 && tagSollPauschal > tagSoll) {
                            float soll = tagSoll;
                            wert += (soll / tagSollPauschal) * schicht.getBis();
                            schwellwert = 51;
                        } else {
                            wert += (schicht.getBis());
                        }*/
                        break;
                }
            }
        }

        // ab einen Schwellwert ist es ein ganzer Tag
        /*if(wert > schwellwert)
            wert = 100;*/
        if(wert > 0) {
            wert = Math.min(wert, 100);

            return wert / 100;
        }
        return wert;
    }

    //
    // Anzahl Minuten mit einer bestimmten Kategorie zurück geben
    //
    public int getKategorieMinuten(int kategorie){
        int wert = 0;

        for (Arbeitsschicht schicht : Schichten) {
            if (schicht.getAbwesenheit().getKategorie() == kategorie) {
                switch (schicht.getWirkung()) {
                    case Abwesenheit.WIRKUNG_IST_PLUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_IST_PLUS_PAUSCHAL:
                        wert += schicht.getNetto();
                        break;
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_EFFEKTIV:
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_STUNDEN:
                        wert += schicht.getMinusSollMinuten();
                        break;
                    case Abwesenheit.WIRKUNG_SOLL_MINUS_TAGE:
                        wert += Math.round( schicht.getMinusSollTage() * tagSoll );
                }
            }
        }

        return wert;
    }

    public ArrayList<Arbeitsschicht> getSchichten(){
        return Schichten;
    }

    public int getEortSchichtNetto(long eortID, String schichtname){
        int n = 0;
        for (Arbeitsschicht schicht : Schichten) {
            if(schichtname.equals(schicht.getName())) {
                n += schicht.getEortNetto(eortID);
            }
        }
        return n;
    }

    public int getEortTag(long eortID, String schichtname){
        int t = 0;
        for (Arbeitsschicht schicht : Schichten) {
            if(schichtname.equals(schicht.getName())) {
                if(schicht.getEortNetto(eortID) > 0){
                    t = 1;
                    break;
                }
            }
        }
        return t;
    }


    //
    // zeigt ob mindestens eine Schicht ohne Wirkung auf den Saldo aber kein freier Tag ist
    //
    /*boolean isFrei() {
        Abwesenheit mAbwesenheit;

        for (int i = 0; i < Schichten.size(); i++) {

            mAbwesenheit = getSchicht(i).getAbwesenheit();

            //if (mArbeitsplatz.getAbwesenheiten().getIndexAktive(mAbwesenheit.getPosition()) == Einstellungen.RUHETAG) {
            if (mAbwesenheit.getKategorie() == Abwesenheit.KAT_RUHETAG) {
                return  true;
            }
        }
        return false;
    }*/
}
