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

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.Color;

import androidx.core.graphics.ColorUtils;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.abwesenheiten.AbwesenheitListe;
import askanimus.arbeitszeiterfassung2.arbeitsmonat.Arbeitsmonat;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.SchichtDefaultListe;
import askanimus.arbeitszeiterfassung2.datenbank.DatenbankHelper;
import askanimus.arbeitszeiterfassung2.einsatzort.EinsatzortListe;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzfeldDefinition;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzfeldDefinitionenListe;

/**
 * @author askanimus@gmail.com on 30.03.14.
 */
public class Arbeitsplatz {
    // Konstanten
    public static final float ARBEITSTAGE_MONAT_DURCHSCHNITT = 21.73f;

    //
    // Arbeitszeitmodelle
    //
    public static final int Soll_Monat_pauschal = 0;        // Pauschale monatliche Arbeitszeit für alle Monate gleich
    public static final int Soll_Woche_rollend = 1;         // Wochenstunden, rollende Woche (L-GAV konform)
    public static final int Soll_Woche_5_2 = 2;             // Wochenstunden, fixe Woche Mo-Fr und Sa/So frei
    public static final int Soll_Woche_6_1 = 3;             // Wochenstunden, fixe Woche Mo-Sa und So frei
    public static final int Soll_Woche_flex = 4;            // Wochenstunden vom User anzugebene Tageszahl 0.5 - 7

    // Optionen
    public static final int OPT_WERT_NOTIZ = 1;
    public static final int OPT_WERT_SPESEN = 2;
    public static final int OPT_WERT_STRECKE = 4;
    public static final int OPT_WERT_EORT = 8;
    public static final int OPT_WERT_FAHRZEIT = 16;
    public static final int OPT_BEZ_UEBERSTUNDEN = 32;
    public static final int OPT_RESET_SALDO = 64;
    private static final int OPT_IS_ENDE = 128;
    public static final int OPT_PAUSE_BEZAHLT = 256;
    public static final int OPT_RESTURLAUB_NO_VERFALL = 512;
    public static final int OPT_ANZEIGE_DEZIMAL = 1024;
    public static final int OPT_URLAUB_ALS_STUNDEN = 2048;
    public static final int OPT_AUTO_AUSZAHLUNG = 4096;
    public static final int OPT_NFC_AKTIV = 8192;
    public static final int OPT_RESET_SALDO_MINUS = 16384;
    public static final int OPT_RESET_SALDO_PLUS = 32768;

    private static final String SQL_READ_FIRST_JOB =
            "select * from " +
                    DatenbankHelper.DB_T_JOB +
                    " LIMIT 1";

    private static final String SQL_READ_JOB =
            "select * from " +
                    DatenbankHelper.DB_T_JOB +
                    " where " +
                    DatenbankHelper.DB_F_ID +
                    " = ? LIMIT 1";

    // Variablen
    private long    Id;
    private String          Name;
    private String          Email;
    private String          Emailtext;
    private String          Anschrift;
    private Datum           StartDatum;
    private Datum           EndDatum;
    private int             Monatsbeginn;
    private int             Wochenbeginn;
    private int             Monate_Zukunft;
    private int             SollstundenWoche;// = 2550; 42.5h in Minuten
    private int             Startsaldo;
    private int             UeberstundenPauschal; //lt. Arbeitsvertrag pauschal vergütete Überstunden
    private int             Farbe ; // Basisfarbe
    private int             Farbe_Hintergrund; //Hintergrundfarbe
    private int             Farbe_Zeile_gerade;
    private int             Farbe_Zeile_ungerade;
    private int             Farbe_Schrift_Knopf;
    private int             Farbe_Schrift_Titel;
    private int             Farbe_Schrift_default;
    private int             Farbe_Tag;
    private ColorStateList Farbe_Radio;
    private ColorStateList Farbe_Button;
    private ColorStateList  Farbe_Track;
    private ColorStateList  Farbe_Thumb;
    private int             Modell;
    private boolean         Teilschichten;
    private int             Schichten;
    private final BitSet    Arbeitstage;        // 0= immer false, 1-7 true=arbeitstag, false=Ruhetag
    private final int[]     Soll_Tag;           // Sollstunden für jeden Tag separat

    private float           Soll_Urlaub;        // Anzahl Urlaubstage pro Jahr
    private float           Start_Urlaub;      // Wenn negaiv, dann Wochen- statt Arbeitstage

    private int             Soll_Tag_pauschal;
    private float           Arbeitstage_Monat;  // Anzahl der Arbeitstage eines Monats
    private float           Anzahl_Arbeitstage; // wird nicht in der datenbank gespeichert

    private int             Optionen;             // Erfassen von zusätzlichen Werten
                                                // (Notiz, einsatzort etc.), Anzeigeotionen,
                                                // Auzeichnungsendeschalter

    private int             Erinnerung_interval;
    private int             Erinnerung_zeit;

    private float stundenlohn;
    private String          Unterschrift_AG;
    private String          Unterschrift_AN;

    private int autoAuzahlungAb;   //Anzahl Überstunden ab denen alle weiteren autom. ausbezahlt werden

    //private SQLiteDatabase sqlVerbindung;


    // Defaultwerte für Schichten
    //private ArrayList<SchichtDefault> Schicht_Default = new ArrayList<SchichtDefault>();
    private SchichtDefaultListe DefaultSchichten;

    // Liste der abwesenheiten / Arbeitszeittypen
    //private ArrayList<Abwesenheit> abwesenheiten = new ArrayList<Abwesenheit>();
    private AbwesenheitListe Abwesenheiten;

    // Liste der Einsatzorte
    //private ArrayList<einsatzort> mOrte = new ArrayList<einsatzort>();
    private EinsatzortListe mEinsatzorte;

    // Lista aller definierten Zusatzfelder
    private ZusatzfeldDefinitionenListe mZusatzDefinitionen;

    // Liste der Sollstundenfaktoren
    private SollstundenFaktorenListe mSollstundenFaktoren;

    private boolean isChanged = false;
    private boolean isNeuberechnung = false;

    // Konstruktoren
    // ist id < 0 wird ein neuer leerer Job angelegt
    public Arbeitsplatz(long id) {
        Arbeitstage = new BitSet(15);
        Soll_Tag = new int[8];

        if(id >= 0) {
            // ersten oder bestimmten Job lesen
            leseJob(id);
        } else {
            neuerArbeitsplatz();
        }

        if(Id > 0) {
            mZusatzDefinitionen = new ZusatzfeldDefinitionenListe(Id, isOptionSet(OPT_ANZEIGE_DEZIMAL));

            //ladeSchichtDefault();
            DefaultSchichten = new SchichtDefaultListe(Id, Schichten, Teilschichten, mZusatzDefinitionen);
            //ladeAbwesenheiten();
            Abwesenheiten = new AbwesenheitListe(Id);
            //ladeEinsatzorte();
            mEinsatzorte = new EinsatzortListe(Id);

            mSollstundenFaktoren = new SollstundenFaktorenListe(this);
        }


    }

    protected Arbeitsplatz klone() {
        Id = -1;
        StartDatum = new Datum(new Date(), Wochenbeginn);
        StartDatum.setTag(1);
        EndDatum = new Datum(StartDatum.getDate(), Wochenbeginn);
        isChanged = true;
        schreibeJob();

        mEinsatzorte.ListeKlone(Id);
        Abwesenheiten.ListeKlone(Id);
        mZusatzDefinitionen.ListeKlone(Id);
        DefaultSchichten.ListeKlone(Id);
        return this;
    }

    /*
     * neuen Arbeitsplatz anlegen mit Defaultwerten (Struzflug AG)
     */
    private void neuerArbeitsplatz(){
        Id = -1;
        SollstundenWoche = 2550;
        Startsaldo = 0;
        UeberstundenPauschal = 0;
        Teilschichten = true;
        Schichten = 2;
        Optionen = OPT_WERT_NOTIZ | OPT_BEZ_UEBERSTUNDEN | OPT_ANZEIGE_DEZIMAL;
        Modell = Soll_Woche_rollend;
        Monatsbeginn = 1;
        Wochenbeginn = Calendar.MONDAY;
        StartDatum = new Datum(new Date(), Wochenbeginn);
        StartDatum.setTag(1);
        EndDatum = new Datum(StartDatum.getDate(), Wochenbeginn);
        Monate_Zukunft = -1;
        Anzahl_Arbeitstage = 7;
        Arbeitstage.set(0,15, true);
        Soll_Tag_pauschal = SollstundenWoche / 5;
        Soll_Tag[Calendar.MONDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.TUESDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.WEDNESDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.THURSDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.FRIDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.SATURDAY]=Soll_Tag_pauschal;
        Soll_Tag[Calendar.SUNDAY]=Soll_Tag_pauschal;
        Arbeitstage_Monat = 0;
        setFarbe(ASettings.res.getColor(R.color.job_default));
        Erinnerung_interval = ISettings.ERINNERUNG_TAG;
        Erinnerung_zeit = 20*60;//20:00
        Soll_Urlaub = -35;  // 5 Wochen Samstag und Sonntag werden als Urlaubstag gezählt
        Start_Urlaub = 0;

        stundenlohn = 0;

        autoAuzahlungAb = -1;

        isChanged = true;

        schreibeJob();

        new ZusatzfeldDefinition(
                Id,
                ASettings.res.getString(R.string.notiz),
                IZusatzfeld.TYP_TEXT,
                "",
                IZusatzfeld.NEUTRAL,
                0,
                IZusatzfeld.MAX_COLUM,
                isOptionSet(OPT_ANZEIGE_DEZIMAL)).speichern();

    }


    //
    // Job aus der datenbank lesen
    //
    @SuppressLint("Range")
    private void leseJob(long id) {
        // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getReadableDatabase();
        Cursor result;
        if( id > 0)
            result = ASettings.mDatenbank.rawQuery(SQL_READ_JOB, new String[]{Long.toString(id)});
        else
           result = ASettings.mDatenbank.rawQuery(SQL_READ_FIRST_JOB, null);

        // Resultat der Anfrage auswerten
        if (result.getCount() > 0) {
            int mArbeitstage;

            result.moveToFirst();

            // Daten übernehemen
            Id = result.getLong(result.getColumnIndex(DatenbankHelper.DB_F_ID));
            Name = result.getString(result.getColumnIndex(DatenbankHelper.DB_F_NAME));
            Email= result.getString(result.getColumnIndex(DatenbankHelper.DB_F_EMAIL));
            Emailtext = result.getString(result.getColumnIndex(DatenbankHelper.DB_F_EMAIL_TEXT));
            Anschrift = result.getString(result.getColumnIndex(DatenbankHelper.DB_F_ANSCHRIFT));

            Wochenbeginn = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_WOCHENBEGINN));//
            // nur in der Entwicklungsphase notwendig
            // kann vor Veröffentlichung verschwinden
            //
            if(Wochenbeginn < 1) {
                Wochenbeginn = Calendar.MONDAY;
            }
            StartDatum = new Datum(result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_JAHR_BEGINN)),
                    result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MONAT_BEGINN)),
                    result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_TAG_BEGINN)), Wochenbeginn);
            EndDatum = new Datum(result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_JAHR_ENDE)),
                    result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MONAT_ENDE)),
                    result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_TAG_ENDE)), Wochenbeginn);
            SollstundenWoche = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_SOLL_H));
            Startsaldo = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_STARTSALDO));
            UeberstundenPauschal = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_UEBER_PAUSCHAL));
            Teilschichten = (result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_T_SCHICHTEN)) == 1);
            Schichten = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_SCHICHTEN));
            Optionen = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MODULE));
            Modell = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MODELL));
            Monatsbeginn = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MONATSBEGINN));
            Monate_Zukunft = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_ANZEIGE_ZUKUNFT));
            Arbeitstage_Monat = result.getFloat(result.getColumnIndex(DatenbankHelper.DB_F_MONATS_ARBEITSTAGE));
            mArbeitstage = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_ARBEITSTAGE));
            // Arbeitstage in Array aufteilen und Anzahl setzen
            Anzahl_Arbeitstage = 0;
            Arbeitstage.set(0, false);
            for (int i = 1; i <= 14 ; i++) {
                Arbeitstage.set(i, (mArbeitstage & (1 << i)) != 0);
                if(Arbeitstage.get(i))
                    Anzahl_Arbeitstage +=0.5f;
            }
            for (int i = 1; i <= 7 ; i++) {
                Soll_Tag[i] = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_SOLL_TAG[i]));
            }

            setSoll_Tag_pauschal(); // Workaround, weil in älterer Version dieser Wert nicht korrekt in der datenbank gespeichert wurde

            setFarbe(result.getInt(result.getColumnIndexOrThrow(DatenbankHelper.DB_F_FARBE)));

            Erinnerung_interval = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_TIMER_INTERVAL));
            Erinnerung_zeit = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_TIMER_ZEIT));

            Soll_Urlaub = result.getFloat(result.getColumnIndex(DatenbankHelper.DB_F_SOLL_URLAUB));
            Start_Urlaub = result.getFloat(result.getColumnIndex(DatenbankHelper.DB_F_START_URLAUB));

            stundenlohn = result.getFloat(result.getColumnIndex(DatenbankHelper.DB_F_STUNDENLOHN));

            autoAuzahlungAb = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_AUTO_AUSZAHLUNG_AB));

            Unterschrift_AG = result.getString(result.getColumnIndex(DatenbankHelper.DB_F_UNTERSCHRIFT_AG));
            Unterschrift_AN = result.getString(result.getColumnIndex(DatenbankHelper.DB_F_UNTERSCHRIFT_AN));

            isChanged = false;
            isNeuberechnung = false;
            result.close();
        } else {
            result.close();
            // Der Arbeitsplatz mit der angegebenen ID ist nicht (mehr) vorhanden
            // oder es gibt noch keinen gespeicherten Arbeitsplatz
            if(id == 0){
                // es gibt keine gespeicherten Arbeitsplätze, es wird ein neuer Default Arbeitsplatz angelegt
                neuerArbeitsplatz();
            } else {
                // Im zweiten Versuch den ersten Arbeitsplatz in der Liste lesen
                leseJob(0);
            }
        }
    }

    //
    // Job in die Datenbank schreiben
    //
    public void schreibeJob() {
        if(isChanged) {
            isChanged = false;

            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
            ContentValues werte = new ContentValues();

            werte.put(DatenbankHelper.DB_F_NAME, Name);
            werte.put(DatenbankHelper.DB_F_EMAIL, Email);
            werte.put(DatenbankHelper.DB_F_EMAIL_TEXT, Emailtext);
            werte.put(DatenbankHelper.DB_F_ANSCHRIFT, Anschrift);
            werte.put(DatenbankHelper.DB_F_JAHR_BEGINN, StartDatum.get(Calendar.YEAR));
            werte.put(DatenbankHelper.DB_F_MONAT_BEGINN, StartDatum.get(Calendar.MONTH));
            werte.put(DatenbankHelper.DB_F_TAG_BEGINN, StartDatum.get(Calendar.DAY_OF_MONTH));
            werte.put(DatenbankHelper.DB_F_JAHR_ENDE, EndDatum.get(Calendar.YEAR));
            werte.put(DatenbankHelper.DB_F_MONAT_ENDE, EndDatum.get(Calendar.MONTH));
            werte.put(DatenbankHelper.DB_F_TAG_ENDE, EndDatum.get(Calendar.DAY_OF_MONTH));
            werte.put(DatenbankHelper.DB_F_MONATSBEGINN, Monatsbeginn);
            werte.put(DatenbankHelper.DB_F_WOCHENBEGINN, Wochenbeginn);
            werte.put(DatenbankHelper.DB_F_ANZEIGE_ZUKUNFT, Monate_Zukunft);
            werte.put(DatenbankHelper.DB_F_SOLL_H, SollstundenWoche);
            werte.put(DatenbankHelper.DB_F_STARTSALDO, Startsaldo);
            werte.put(DatenbankHelper.DB_F_UEBER_PAUSCHAL, UeberstundenPauschal);
            werte.put(DatenbankHelper.DB_F_FARBE, Farbe);
            werte.put(DatenbankHelper.DB_F_MODELL, Modell);
            werte.put(DatenbankHelper.DB_F_T_SCHICHTEN, (Teilschichten ? 1 : 0));
            werte.put(DatenbankHelper.DB_F_SCHICHTEN, Schichten);
            werte.put(DatenbankHelper.DB_F_MODULE, Optionen);
            werte.put(DatenbankHelper.DB_F_TIMER_INTERVAL, Erinnerung_interval);
            werte.put(DatenbankHelper.DB_F_TIMER_ZEIT, Erinnerung_zeit);
            werte.put(DatenbankHelper.DB_F_SOLL_PAUSCHAL, Soll_Tag_pauschal);
            werte.put(DatenbankHelper.DB_F_MONATS_ARBEITSTAGE, Arbeitstage_Monat);
            werte.put(DatenbankHelper.DB_F_SOLL_URLAUB, Soll_Urlaub);
            werte.put(DatenbankHelper.DB_F_START_URLAUB, Start_Urlaub);
            werte.put(DatenbankHelper.DB_F_STUNDENLOHN, stundenlohn);
            werte.put(DatenbankHelper.DB_F_AUTO_AUSZAHLUNG_AB, autoAuzahlungAb);
            werte.put(DatenbankHelper.DB_F_UNTERSCHRIFT_AG, Unterschrift_AG);
            werte.put(DatenbankHelper.DB_F_UNTERSCHRIFT_AN, Unterschrift_AN);
            //werte.put(Einstellungen.DB_F_UEBER_AUSZAHL_AB, Ueber_Auszahl_ab);


            int value = 0;
            for (int i = 0; i <= 14; ++i) {
                value += Arbeitstage.get(i) ? (1 << i) : 0;
            }
            werte.put(DatenbankHelper.DB_F_ARBEITSTAGE, value);


            for (int i = 1; i <= 7; i++) {
                werte.put(DatenbankHelper.DB_F_SOLL_TAG[i], Soll_Tag[i]);
            }

            if (Id <= 0)
                Id = ASettings.mDatenbank.insert(DatenbankHelper.DB_T_JOB, null, werte);
            else
                ASettings.mDatenbank.update(DatenbankHelper.DB_T_JOB, werte, DatenbankHelper.DB_F_ID + "=?", new String[]{Long.toString(Id)});

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


    //
    // Job aus der datenbank löschen
    //
    @SuppressLint("Range")
    public void delete() {
        // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
        // den Job löschen
        ASettings.mDatenbank.delete(
                DatenbankHelper.DB_T_JOB,
                DatenbankHelper.DB_F_ID + "=?",
                new String[]{Long.toString(Id)}
        );

        // die dazu gehörenden Schichten löschen

         // SQL Anfrage für die Tagesliste zusammen bauen
        String sql = "select "
            + DatenbankHelper.DB_F_ID
            + " from "
            + DatenbankHelper.DB_T_TAG
            + " where "
            + DatenbankHelper.DB_F_JOB
            + "="
            + Id;

        // Anfrage an datenbank
        Cursor result = ASettings.mDatenbank.rawQuery(sql, null);

        if(result.getCount() > 0) {
            result.moveToFirst();
            do {
                // alle Schichten löschen
                ASettings.mDatenbank.delete(
                        DatenbankHelper.DB_T_SCHICHT,
                        DatenbankHelper.DB_F_TAG + "=?",
                        new String[]{Long.toString(
                                result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_ID))
                        )}
                );
            } while (result.moveToNext());
        }
        result.close();

        // die Tage löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_TAG, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // die Monate löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_MONAT, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // die angelegten Jahre löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_JAHR, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // Abwesenheiten löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_ABWESENHEIT, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // die Einsatzorte löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_EORT, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // die Defaultschichten löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_SCHICHT_DEFAULT, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // die Zusatzwerte löschen
        // SQL Anfrage für die Zusatzfeldliste zusammen bauen
        String sqlZusatzwerte = "select "
            + DatenbankHelper.DB_F_ID
            + " from "
            + DatenbankHelper.DB_T_ZUSATZFELD
            + " where "
            + DatenbankHelper.DB_F_JOB
            + "="
            + Id;

        Cursor resultZusatzfelder = ASettings.mDatenbank.rawQuery(sqlZusatzwerte, null);
        while (resultZusatzfelder.moveToNext()){
            long idZusatzfeld = resultZusatzfelder.getLong(
                    resultZusatzfelder.getColumnIndex(DatenbankHelper.DB_F_ID)
            );
            ASettings.mDatenbank.delete(
                    DatenbankHelper.DB_T_ZUSATZWERT_DEFAULT,
                    DatenbankHelper.DB_F_ZUSATZFELD + "=?", new String[]{
                            Long.toString(idZusatzfeld)
                    }
            );
            ASettings.mDatenbank.delete(
                    DatenbankHelper.DB_T_ZUSATZWERT,
                    DatenbankHelper.DB_F_ZUSATZFELD + "=?", new String[]{
                            Long.toString(idZusatzfeld)
                    }
            );
            ASettings.mDatenbank.delete(
                    DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL,
                    DatenbankHelper.DB_F_ZUSATZFELD + "=?", new String[]{
                            Long.toString(idZusatzfeld)
                    }
            );
            ASettings.mDatenbank.delete(
                    DatenbankHelper.DB_T_STEMPELUHR_ZUSATZWERT,
                    DatenbankHelper.DB_F_ZUSATZFELD + "=?", new String[]{
                            Long.toString(idZusatzfeld)
                    }
            );
        }
        resultZusatzfelder.close();
        ASettings.mDatenbank.delete(
                DatenbankHelper.DB_T_ZUSATZFELD,
                DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)}
        );

        // NFC Tags löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_NFC_TAG, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // Stempeluhrstatus löschen
        ASettings.mDatenbank.delete(DatenbankHelper.DB_T_STEMPELUHR_STATUS, DatenbankHelper.DB_F_JOB + "=?", new String[]{Long.toString(Id)});

        // ASettings.mDatenbank.close();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////// Wertzuweisungen ////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////

    // die Monate des Arbeitsplatzes für eine Neuberechnung vorsehen
    public void setNeuberechnung(){
        isNeuberechnung = true;
    }

    // Tag als arbeitstag oder Ruhetag markieren
    public void setArbeitstag(int halbtag, Boolean arbeit) {
        if (Arbeitstage.get(halbtag) != arbeit) {
            Arbeitstage.set(halbtag, arbeit);
            if(arbeit) {
                Anzahl_Arbeitstage += 0.5;
            } else {
                Anzahl_Arbeitstage -= 0.5;
            }
            isChanged = true;
        }
    }

    public void setSollTag(int tag, int soll){
        if(Soll_Tag[tag] != soll) {
            Soll_Tag[tag] = soll;
            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setName(String name){
        if(!name.equals(Name)) {
            Name = name;
            isChanged = true;
        }
    }

    public void setEmail(String mail){
        if(!mail.equals(Email)){
            Email = mail;
            isChanged = true;
        }
    }

    public void setMailText(String text){
        if(!text.equals(Emailtext)){
            Emailtext = text;
            isChanged = true;
        }
    }

    public void setAnschrift(String anschrift){
        if(!anschrift.equals(Anschrift)){
            Anschrift = anschrift;
            isChanged = true;
        }
    }

    public void setSollstundenWoche(int soll, Boolean updatePauschal){
        if(SollstundenWoche != soll){
            /*
             * Sollstunden werden neu gesetzt
             * alle Monate müssen daraufhin angepasst werden
             * der erste Monat wird angepasst und ruft seinerseits alle weiteren Monate auf
             */
            SollstundenWoche = soll;
            if(updatePauschal)
                setSoll_Tag_pauschal();

            isChanged = true;
            isNeuberechnung = true;
        }
    }

    private void setSoll_Tag_pauschal() {
        int soll;
        if (Modell == Soll_Monat_pauschal) {
            if (Arbeitstage_Monat > 0) {
                soll = Math.round(SollstundenWoche / Arbeitstage_Monat);
            } else {
                soll = 0;
            }
        } else {
            if (Modell == Soll_Woche_rollend)
                soll = Math.round(SollstundenWoche / 5.0f);
            else
                soll = Math.round(SollstundenWoche / Anzahl_Arbeitstage);
        }
        if (Soll_Tag_pauschal != soll) {
            Soll_Tag_pauschal = soll;
            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setStartsaldo(int startsaldo){
            /*
             * Startsaldo wird neu gesetzt
             * alle Monate müssen daraufhin angepasst werden
             * der erste Monat wird angepasst und ruft seinerseits alle weiteren Monate auf
             */
        if (startsaldo != Startsaldo) {
            Startsaldo = startsaldo;
            //updateStartsaldo();
            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setUeberstundenPauschal(int ueberstundenPauschal){
            /*
             * pauschal bezahlte Überstunden werden neu gesetzt
             * alle Monate müssen daraufhin angepasst werden
             * der erste Monat wird angepasst und ruft seinerseits alle weiteren Monate auf
             */
        if(ueberstundenPauschal != UeberstundenPauschal){
            UeberstundenPauschal = ueberstundenPauschal;
            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setStundenmodell(int modell, int sollstunden){

        if (Modell != modell || sollstunden != SollstundenWoche) {
            SollstundenWoche = sollstunden;
            Modell = modell;

            if(Modell == Soll_Monat_pauschal ) {
                Arbeitstage_Monat = 21f;
                Anzahl_Arbeitstage = 5;

                //Sollstunden = Math.round(Arbeitstage_Monat * 8 * 60);
                Soll_Tag_pauschal = Math.round(SollstundenWoche / Arbeitstage_Monat);
            } else {
                //Sollstunden = 2550; // 42.5h in Minuten
                if (Modell == Soll_Woche_6_1) {
                    Anzahl_Arbeitstage = 6;
                    Soll_Tag_pauschal = SollstundenWoche / 6;
                } else {
                    Soll_Tag_pauschal = SollstundenWoche / 5;
                    Anzahl_Arbeitstage = 5;
                }
            }


            // die Woche auf Arbeitszeitmodell anpassen
            Arbeitstage.set(Calendar.MONDAY, true);
            Arbeitstage.set(Calendar.MONDAY + 7, true);
            Soll_Tag[Calendar.MONDAY] = Soll_Tag_pauschal;

            Arbeitstage.set(Calendar.TUESDAY, true);
            Arbeitstage.set(Calendar.TUESDAY + 7, true);
            Soll_Tag[Calendar.TUESDAY] = Soll_Tag_pauschal;

            Arbeitstage.set(Calendar.WEDNESDAY, true);
            Arbeitstage.set(Calendar.WEDNESDAY + 7, true);
            Soll_Tag[Calendar.WEDNESDAY] = Soll_Tag_pauschal;

            Arbeitstage.set(Calendar.THURSDAY, true);
            Arbeitstage.set(Calendar.THURSDAY + 7, true);
            Soll_Tag[Calendar.THURSDAY] = Soll_Tag_pauschal;

            Arbeitstage.set(Calendar.FRIDAY, true);
            Arbeitstage.set(Calendar.FRIDAY + 7, true);
            Soll_Tag[Calendar.FRIDAY] = Soll_Tag_pauschal;

            if(Modell == Soll_Woche_rollend || Modell == Soll_Woche_6_1){
                Arbeitstage.set(Calendar.SATURDAY, true);
                Arbeitstage.set(Calendar.SATURDAY + 7, true);
                Soll_Tag[Calendar.SATURDAY] = Soll_Tag_pauschal;
            } else {
                Arbeitstage.set(Calendar.SATURDAY, false);
                Arbeitstage.set(Calendar.SATURDAY + 7, false);
                Soll_Tag[Calendar.SATURDAY] = 0;
            }

            if(Modell == Soll_Woche_rollend){
                Arbeitstage.set(Calendar.SUNDAY, true);
                Arbeitstage.set(Calendar.SUNDAY + 7, true);
                Soll_Tag[Calendar.SUNDAY] = Soll_Tag_pauschal;
            } else {
                Arbeitstage.set(Calendar.SUNDAY, false);
                Arbeitstage.set(Calendar.SUNDAY + 7, false);
                Soll_Tag[Calendar.SUNDAY] = 0;
            }

            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setSartdatum(Date beginn, boolean init) {
        Datum altStartdatum = new Datum(StartDatum);

        StartDatum.set(beginn);
        isChanged = !altStartdatum.istGleich(StartDatum, Calendar.DAY_OF_MONTH);
        isNeuberechnung = isChanged;

        if(!init) {
            Arbeitsmonat mMonat;

            // Neuen Startsaldo setzen
            mMonat = new Arbeitsmonat(this, StartDatum.get(Calendar.YEAR), StartDatum.get(Calendar.MONTH) - 1, true,false);
            Startsaldo = mMonat.getSaldo();

            // alle Monate vor Startmonat löschen
            while (StartDatum.liegtNach(altStartdatum)) {
                mMonat = new Arbeitsmonat(this, altStartdatum.get(Calendar.YEAR), altStartdatum.get(Calendar.MONTH), true, false);
                mMonat.loeschen();
                altStartdatum.add(Calendar.MONTH, 1);
            }
        }

        // Das Auzeichnungsende verschieben oder abstellen
        if (isOptionSet(OPT_IS_ENDE)) {
            if (!StartDatum.liegtVor(EndDatum)) {
                //isEnde = false;
                setOption(OPT_IS_ENDE, false);
                //EndDatum.setTime(StartDatum.getTime());
            }
        } /*else{
               EndDatum.setTime(StartDatum.getTime());
            }*/
        //}
    }

    public void setEnddatum(Date ende) {
        // alle Zeiten auf 0
        //ende.setTime((ende.getTime() / 100000) * 100000);
        EndDatum.set(ende);

        //isEnde = true;
        //EndDatum.setTime(StartDatum.getTime());
        //isEnde = false;
        setOption(OPT_IS_ENDE, EndDatum.liegtNach(StartDatum));
        isChanged = true;
        isNeuberechnung = true;
    }

    public void setNoEnde(){
        //EndDatum.setTime(StartDatum.getTime());
        if(isOptionSet(OPT_IS_ENDE)) {
            setOption(OPT_IS_ENDE, false);
            isChanged = true;
            isNeuberechnung = true;
        }
        //isEnde = false;
    }

    public void setFarbe(int farbe) {
        // Basisfarbe
        if (Farbe != farbe) {
            isChanged = true;
            float[] hsl = new float[3];
            float[] hsl_back = new float[3];

            boolean isThemeDunkel = ASettings.isThemaDunkel;

            Farbe = farbe;

            // alle anderen Farben ableiten
            ColorUtils.colorToHSL(Farbe, hsl_back);
            hsl_back[2] = isThemeDunkel ? 0.09f : 0.99f;
            Farbe_Hintergrund = ColorUtils.HSLToColor(hsl_back);

            Farbe = ColorUtils.compositeColors(Farbe, Farbe_Hintergrund);
            ColorUtils.colorToHSL(Farbe, hsl);

            if (isThemeDunkel) {
                Farbe_Schrift_Titel = (ColorUtils.calculateContrast(Farbe, Farbe_Hintergrund) < 3) ? 0xaaffffff : 0xaa000000;
                Farbe_Schrift_default = 0xaaffffff;
            } else {
                Farbe_Schrift_Titel = (ColorUtils.calculateContrast(Farbe, Farbe_Hintergrund) < 3) ? 0xaa000000 : 0xaaffffff;
                Farbe_Schrift_default = 0xaa000000;
            }
            Farbe_Schrift_Knopf = Farbe_Schrift_Titel;


            hsl_back[2] = isThemeDunkel ? 0.19f : 0.89f;
            Farbe_Tag = ColorUtils.HSLToColor(hsl_back);

            hsl_back[2] = isThemeDunkel ? 0.23f : 0.93f;
            Farbe_Zeile_gerade = ColorUtils.HSLToColor(hsl_back);

            hsl_back[2] = isThemeDunkel ? 0.27f : 0.97f;
            Farbe_Zeile_ungerade = ColorUtils.HSLToColor(hsl_back);

            // Buttonfarben erzeugen
            int cHellgrau = 0xffaaaaaa;
            int cDunkelgrau = 0xff777777;

            int[][] states_radio = new int[][]{
                    new int[]{-android.R.attr.state_checked}, //unchecket
                    new int[]{android.R.attr.state_checked}, // checked
                    new int[]{-android.R.attr.state_enabled}, //disabled
                    new int[]{android.R.attr.state_enabled} //enabled

            };

            int[][] states_button = new int[][]{
                    new int[]{-android.R.attr.state_selected}, //unselected
                    new int[]{android.R.attr.state_selected}, //unselected
                    new int[]{-android.R.attr.state_enabled}, //disabled
                    new int[]{android.R.attr.state_pressed}, //pressed
                    new int[]{android.R.attr.state_focused}, //focused
                    new int[] {android.R.attr.state_enabled}// empty
            };

            int[][] states_track = new int[][]{
                    new int[]{-android.R.attr.state_enabled}, // disabled
                    new int[]{android.R.attr.state_checked}, // checked
                    new int[0]  // enabled

            };

            int[] colors_radio = new int[]{
                    isThemeDunkel ? cDunkelgrau : cHellgrau,//disabled
                    Farbe, //enabled
                    isThemeDunkel ? cDunkelgrau : cHellgrau,//disabled
                    Farbe //enabled
            };

            int[] colors_button = new int[]{
                    Farbe,
                    isThemeDunkel ? cDunkelgrau : cHellgrau,
                    Farbe,
                    Farbe,
                    Farbe,
                    Farbe
            };

            int[] colors_track = new int[]{
                    cHellgrau,
                    Color.argb(88, Color.red(Farbe), Color.green(Farbe), Color.blue(Farbe)),
                    cDunkelgrau
            };

            Farbe_Button = new ColorStateList(states_button, colors_button);
            Farbe_Radio = new ColorStateList(states_radio, colors_radio);
            Farbe_Track = new ColorStateList(states_track, colors_track);
            Farbe_Thumb = new ColorStateList(
                    new int[][]{
                            new int[]{android.R.attr.state_checked},
                            new int[]{}
                    },
                    new int[]{
                            Farbe,
                            cHellgrau
                    });
        }
    }

    public void setMonatsbeginn(int tag){
        if(Monatsbeginn != tag){
            Monatsbeginn = tag;
            isChanged = true;
            isNeuberechnung = isChanged;
        }
    }

    public void setWochenbeginn(int tag){
        if(Wochenbeginn != tag) {
            Wochenbeginn = tag;
            isChanged = true;
        }
    }

    public void setAnzeige_Zukunft(int monate){
        if(Monate_Zukunft != monate){
            Monate_Zukunft = monate;
            isChanged = true;
            isNeuberechnung = true;
        }
    }

    public void setArbeitstage_Monat(float tage){
        if(Arbeitstage_Monat != tage) {
            Arbeitstage_Monat = tage;
            if(tage > 0) {
                Soll_Tag_pauschal = Math.round(SollstundenWoche / Arbeitstage_Monat);
            } else {
               Soll_Tag_pauschal = 0;
            }
            isChanged = true;
            isNeuberechnung = isChanged;
        }
    }

    public void setUrlaubAlsStunden(boolean set){
        if(set != isOptionSet(OPT_URLAUB_ALS_STUNDEN)) {
            setOption(OPT_URLAUB_ALS_STUNDEN, set);
            if (set) {
                setSoll_Urlaub(getSoll_Urlaub() * getSollstundenTagPauschal());
                setStart_Urlaub(getStart_Urlaub() * getSollstundenTagPauschal());
            } else {
                setSoll_Urlaub(getSoll_Urlaub() / getSollstundenTagPauschal());
                setStart_Urlaub(getStart_Urlaub() / getSollstundenTagPauschal());
            }
            isNeuberechnung = isChanged;
        }
    }

    public void setSoll_Urlaub(float tage){
        if(Soll_Urlaub != tage){
            Soll_Urlaub = tage;
            isChanged = true;
        }
    }

    public void setStart_Urlaub(float urlaubstage){
        if(Start_Urlaub != urlaubstage){
            Start_Urlaub = urlaubstage;
            isChanged = true;
        }
    }

    public void setOption(int option, boolean set){
        int oldOptionen = Optionen;
        boolean oldPauseBezahlt = isOptionSet(OPT_PAUSE_BEZAHLT);
        if(set)
            Optionen = Optionen | option;
        else
            Optionen = Optionen & ~option;

        if(oldOptionen != Optionen) {
            isChanged = true;
            isNeuberechnung = (isOptionSet(OPT_PAUSE_BEZAHLT) != oldPauseBezahlt);
        }
    }

    public void setStundenlohn(float lohn){
        if(stundenlohn != lohn) {
            stundenlohn = lohn;
            isChanged = true;
            isNeuberechnung = isChanged;
        }
    }

    public void setAutoAuszahlung(boolean autoAuszahlung){
        if(autoAuszahlung != isAutoAuszahlung()){
            setOption(OPT_AUTO_AUSZAHLUNG, autoAuszahlung);
            isChanged = true;
            isNeuberechnung = isChanged;
        }
    }
    public void setAutoAuszahlungAb(int stunden){
        if(autoAuzahlungAb != stunden) {
            autoAuzahlungAb = stunden;
            isChanged = true;
            isNeuberechnung = isChanged;
        }
    }

    public void setUnterschrift_AG(String unterschrift){
        if(!unterschrift.equals(Unterschrift_AG)) {
            Unterschrift_AG = unterschrift;
            isChanged = true;
        }
    }

    public void setUnterschrift_AN(String unterschrift){
        if(!unterschrift.equals(Unterschrift_AN)) {
            Unterschrift_AN = unterschrift;
            isChanged = true;
        }
    }


    public void resetNeuberechnung(){
        isNeuberechnung = false;
    }

    public void setSchichtzahl(int anzahl){
        isChanged = anzahl != Schichten;
        Schichten = anzahl;
    }

    public void setIsTeilschicht(Boolean isTeilschicht){
        isChanged = Teilschichten != isTeilschicht;
        Teilschichten = isTeilschicht;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////// Wertrückgaben ///////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////
    public boolean istGeaendert(){
        return isChanged;
    }

    public boolean istNeuberechnung(){
        return isNeuberechnung;
    }


    public long getId() {return Id;}

    public String getName(){

        return Name == null?
                ASettings.res.getString(R.string.default_jobname) :
                Name;
    }

    public String getAnschrift(){
        return Anschrift == null ?
                ASettings.res.getString(R.string.default_anschrift) :
                Anschrift;
    }

    public String getEmail() {
        return Email == null ?
                ASettings.res.getString(R.string.default_eMail) :
                Email;
    }

    public String getEmailText(){
        return Emailtext == null ?
               ASettings.res.getString(R.string.mailtext) + " " + ASettings.res.getString(R.string.default_user) :
                Emailtext;
    }

    public int getFarbe(){
        return Farbe;
    }

    public int getFarbe_Hintergrund(){
        return Farbe_Hintergrund;
    }

    public int getFarbe_Tag(){
        return Farbe_Tag;
    }


    public int getFarbe_Schicht_gerade(){
        return Farbe_Zeile_gerade;
    }

    public int getFarbe_Schicht_ungerade(){
        return Farbe_Zeile_ungerade;
    }

    public int getFarbe_Zeile_gerade(){
        return 0x00000000;
    }

    public int getFarbe_Zeile_ungerade(){
        return ASettings.isThemaDunkel ? 0x22ffffff : 0x22000000;
    }

    public int getFarbe_Schrift_Titel(){
        return Farbe_Schrift_Titel;
    }

    public int getFarbe_Schrift_Button(){
        return Farbe_Schrift_Knopf;
    }

    public int getFarbe_Widget_Titel_Background(){
        return ColorUtils.setAlphaComponent(Farbe, 175);
    }

    /*int getFarbe_Widget_Background(){
        return ColorUtils.setAlphaComponent(ASettings.res.getColor(R.color.bpblack), 100);
    }*/

    public int getFarbe_Schrift_default(){
        return Farbe_Schrift_default;
    }

    public ColorStateList getFarbe_Radio(){
        return Farbe_Radio;
    }

    public ColorStateList getFarbe_Button(){
        return Farbe_Button;
    }

    public ColorStateList getFarbe_Trak(){
        return Farbe_Track;
    }

    public ColorStateList getFarbe_Thumb(){
        return Farbe_Thumb;
    }

    public Datum getStartDatum() {
        return(StartDatum);
    }

    /*protected Date getEndDatum(){
        return EndDatum.getTime();
    }*/

    public boolean isStartAufzeichnung(Datum datum) {
        return (StartDatum.tageBis(datum) >= 0);
    }

    public boolean isSetEnde(){
        return isOptionSet(OPT_IS_ENDE);
    }

    public boolean isEndeAufzeichnung(Datum datum){
        return (isOptionSet(OPT_IS_ENDE) && datum.liegtNach(EndDatum));
    }
    public Datum getEndDatum(){
        //if(isOptionSet(Einstellungen.OPT_IS_ENDE))
            return EndDatum;
        //else
            //return Einstellungen.getletzterAnzeigeTag(this);
    }

    public int getStartsaldo(){
        return Startsaldo;
    }

    public int getUeberstundenPauschal(){
        return UeberstundenPauschal;
    }

    public int getModell(){
        return Modell;
    }

    public float getArbeitstage_Monat() {
        return Arbeitstage_Monat;
    }

    private int getSollstundenTagManuell(int jahr, int monat, int wochentag){
        int mSoll;
        float mTage;
        float anteilArbeitstag;

        if(wochentag < 0){
            anteilArbeitstag = 1;
        } else {
            anteilArbeitstag = getArbeitstag(wochentag);
        }

        // das Datum des Monats(Abrechnungsmonts-)beginns festlegen
        Datum mBeginn = new Datum(
                jahr,
                monat,
                getMonatsbeginn(), getWochenbeginn());

        // den letzten Tag des Abrechnungsmonats festlegen
        Datum mEnde = new Datum(mBeginn);
        mEnde.add(Calendar.DAY_OF_MONTH, mBeginn.getAktuellMaximum(Calendar.DAY_OF_MONTH) - 1);

        // den Monatsbeginn verschieben, wenn Aufzeichnungsbeginn später
        if (getStartDatum().liegtNach(mBeginn)) {
            mBeginn.set(getStartDatum().getDate());
        }

        // das Monatsende verschieben, wenn Aufzeichnungsende früher
        if (isSetEnde()) {
            if (getEndDatum().liegtVor(mEnde)) {
                mEnde.set(getEndDatum().getDate());
            }
        }
        mEnde.add(Calendar.DAY_OF_MONTH, 1);

        if ( getModell() == Soll_Woche_rollend ){
            mTage = mBeginn.tageBis(mEnde);
            mTage /= 7;// Anzahl Wochen in diesen Monat
            mTage *= 5;// Anzahl Arbeitstage in diesen Monat
            mSoll = mSollstundenFaktoren.getSollManuell(jahr, monat);
            mSoll = Math.round(mSoll / mTage);
        } else if ( getModell() == Soll_Monat_pauschal ){
            float arbeitstageMonat = getArbeitstage_Monat()>0 ? getArbeitstage_Monat() : ARBEITSTAGE_MONAT_DURCHSCHNITT;
            mSoll = 0;
            mTage = mBeginn.tageBis(mEnde);
            if (mTage < mBeginn.getAktuellMaximum(Calendar.DAY_OF_MONTH)) {
                mTage = mTage / (30.42f / arbeitstageMonat);
                if (mTage > 0) {
                    anteilArbeitstag = (mSollstundenFaktoren.getSollManuell(jahr, monat) / mTage)*anteilArbeitstag;
                    mSoll = Math.round(anteilArbeitstag);
                }
            } else {
                    anteilArbeitstag = (mSollstundenFaktoren.getSollManuell(jahr, monat) / arbeitstageMonat)*anteilArbeitstag;
                    mSoll = Math.round(anteilArbeitstag);
            }
        } else {
            if(anteilArbeitstag == 0){
                mSoll = 0;
            } else {
                mTage = 0;
                do {
                    mTage += getArbeitstag(mBeginn.get(Calendar.DAY_OF_WEEK));
                    mBeginn.add(Calendar.DAY_OF_MONTH, 1);
                } while (mEnde.liegtNach(mBeginn));
                anteilArbeitstag = (mSollstundenFaktoren.getSollManuell(jahr, monat) / mTage)*anteilArbeitstag;
                mSoll = Math.round(anteilArbeitstag);
            }
        }
        return Math.max(mSoll, 0);
    }

    /** Sollstunden eines Wochentages wie in den Einstellungen festgelegt, korigiert damit diese
     * zu einen evtl. in diesen Monat manuell überschriebenen Monatssoll passt
     * @param tag Wochentag
     * @return Sollstunden des betreffenden Wochentages in Minuten, korrigiert damit er zu den
     * evtl. manuell überschriebenen Monatssollstunden passt
     */
    public int getSollstundenTag(int tag){
        return Soll_Tag[tag];
    }

    /** Sollstunden eines Wochentages für einen bestimmten Monat, korrigiert damit er zu den
     * evtl. manuell überschriebenen Monatssollstunden
     * @param tagDatum Datum des betreffenden Tages
     * @return Sollstunden des betreffenden Wochentages in Minuten, korrigiert damit er zu den
     * evtl. manuell überschriebenen Monatssollstunden passt
     */
    public int getSollstundenTag(Datum tagDatum){
        int mSoll;
        Datum mTag = new Datum(tagDatum);
        int jahr = mTag.get(Calendar.YEAR);
        int monat = mTag.get(Calendar.MONTH);
        float mFaktor = mSollstundenFaktoren.getSollstundenFaktor(jahr,monat);

        if(mFaktor >= 0){
            /*if(getModell() == Soll_Woche_rollend){
               mSoll = Math.round(mFaktor * Soll_Tag_pauschal);
            } else {*/
                mSoll = Math.round(mFaktor * Soll_Tag[mTag.get(Calendar.DAY_OF_WEEK)]);
            //}
        } else {
            mSoll = getSollstundenTagManuell(jahr, monat, mTag.get(Calendar.DAY_OF_WEEK));
        }
        return Math.max(mSoll, 0);
    }

    /**
     * gibt durchschnittliche Sollstunden für einen Arbeitstag zurück
     * @return Sollstunden eines durchschnittlichen Arbeitstages in Minuten
     */
    public int getSollstundenTagPauschal(){
        return Soll_Tag_pauschal;
    }

    /**
     * gibt durchschnittliche Sollstunden für einen Arbeitstag zurück, korigiert damit diese
     * zu einen evtl. in diesen Monat manuell überschriebenen Monatssoll passt
     * @param jahr Jahr in welchen der betreffende Monat liegt
     * @param monat betreffender Monat
     * @return Sollstunden eines durchschnittlichen Arbeitstages in Minuten, korigiert damit diese
     * zu einen evtl. in diesen Monat manuell überschriebenen Monatssoll passt
     */
    public int getSollstundenTagPauschal(int jahr, int monat){
        int mSoll;
        float mFaktor = mSollstundenFaktoren.getSollstundenFaktor(jahr,monat);

        if(mFaktor >= 0){
            mSoll = Math.round(mFaktor * Soll_Tag_pauschal);
        } else {
            mSoll = getSollstundenTagManuell(jahr, monat, -1);
        }
        return Math.max(mSoll, 0);
    }

    /**
     * Sollstunden einer Arbeitswoche in Minuten
     * (im Arbeitszeitmodell "Monatsstunden" die monatl. Sollstunden in Minuten)
     * @return Sollstunden einer Arbeitswoche (Arbeitsmonats) in Minuten
     */
    public int getSollstundenWoche(){
        return SollstundenWoche;
    }

    // die pauschaelne Monatssollstunden
    /* public int getMonatsSollstunden(){
        return SollstundenWoche;
    }*/

    /**
     * gibt die Sollstunden eines konkreten Monats zurück, der in diesen Monat eingetragene
     * manuelle Soll wird nicht berücksichtigt
     * @param monat der Monat für den die Sollstunden berechnet werden sollen
     * @param abzugTage Summe der Abwesenheitstage(abziehen von Arbeitstagen) beeinflussen das 7-Tage Modell und das Monatsmodell
     * @param abzugTageInMinuten Summe der Abwesenheitstage(abziehen von Arbeitstagen) in Minuten umgerechnet beeinflussen die x-Tage Modelle
     * @param abzugAbwesenheitMinuten Summe der Abwesenheiten (abziehen von Sollstunden) in Minuten
     * @return Sollstunden an Hand der Einstellungen des Arbeitszplatzes in Minuten
     */
    public int getSollstundenMonat(Datum monat, float abzugTage, int abzugTageInMinuten, int abzugAbwesenheitMinuten) {
        int mSoll;
        float mTage;
        Datum mBeginn= getAbrechnungsmonat(monat);

        // den Beginn auf den ersten Tag des Abrechnungsmonats setzen
        mBeginn.setTag(getMonatsbeginn());

        // den letzten Tag des Abrechnungsmonats festlegen
        Datum mEnde = new Datum(mBeginn);
        mEnde.add(Calendar.DAY_OF_MONTH, mBeginn.getAktuellMaximum(Calendar.DAY_OF_MONTH) - 1);

        // den Monatsbeginn verschieben, wenn Aufzeichnungsbeginn später
        if (getStartDatum().liegtNach(mBeginn)) {
            mBeginn.set(getStartDatum().getDate());
        }
        // das Monatsende verschieben, wenn Aufzeichnungsende früher
        if (isSetEnde()) {
            if (getEndDatum().liegtVor(mEnde)) {
                mEnde.set(getEndDatum().getDate());
            }
        }
        mEnde.add(Calendar.DAY_OF_MONTH, 1);

        // Sollstunden des Monats an Hand des Arbeitszeitmodells berechnen
        switch (getModell()) {
            case Arbeitsplatz.Soll_Woche_rollend:
                mTage = mBeginn.tageBis(mEnde) - abzugTage;
                mTage /= 7;
                mSoll = Math.round(mTage * getSollstundenWoche());
                break;
            case Arbeitsplatz.Soll_Monat_pauschal:
                float arbeitstageMonat = getArbeitstage_Monat()>0 ? getArbeitstage_Monat() : ARBEITSTAGE_MONAT_DURCHSCHNITT;
                mSoll = 0;
                mTage = mBeginn.tageBis(mEnde);
                if (mTage < mBeginn.getAktuellMaximum(Calendar.DAY_OF_MONTH)) {
                    mTage = mTage / (30.42f / arbeitstageMonat);
                    if (mTage > 0) {
                        mSoll = Math.round(mTage * getSollstundenTagPauschal());
                    }
                } else {
                    mSoll = getSollstundenWoche();
                }
                mSoll -= (abzugTage * getSollstundenTagPauschal());
                break;
            default:
                mSoll = 0;
                int m;
                do {
                    m = getSollstundenTag(mBeginn.get(Calendar.DAY_OF_WEEK));
                    mSoll += m;
                    mBeginn.add(Calendar.DAY_OF_MONTH, 1);
                } while (mEnde.liegtNach(mBeginn));
                mSoll -= abzugTageInMinuten;
        }
        mSoll -= abzugAbwesenheitMinuten;
        return Math.max(mSoll, 0);
    }

    // 0, 0.5 oder 1 arbeitstag
    public float getArbeitstag(int Tag){
        float mTag = 0;
        if(Arbeitstage.get(Tag))
            mTag += 0.5;
        if(Arbeitstage.get(Tag + 7))
            mTag += 0.5;

        return mTag;
    }

    // Anzahl der Arbeitstage einer Woche 0.5 - 7
    public float getAnzahl_Arbeitstage_Woche(){
        return Anzahl_Arbeitstage;
    }

    // Tag an dem der Abrechnungsmonat beginnt
    public int getMonatsbeginn(){
        return Monatsbeginn;
    }

    // gibt den Abrechnungsmonat zum zugehörigen Kalendermonat
    public Datum getAbrechnungsmonat(Datum datum){
        Datum d = new Datum(datum);
        if(d.get(Calendar.DAY_OF_MONTH) < Monatsbeginn)
            d.add(Calendar.MONTH, -1);
        return d;
    }

    public int getWochenbeginn(){
        return Wochenbeginn;
    }

    public float getSoll_Urlaub(){
        if(Soll_Urlaub < 0)
            return 0- Soll_Urlaub;
        else
            return Soll_Urlaub;
    }

    public float getStart_Urlaub(){
        return Start_Urlaub;
    }

    public float getStundenlohn(){
        return stundenlohn;
    }

    public int getAutoAuzahlungAb() {
        return autoAuzahlungAb;
    }

    public String getUnterschrift_AG(){
        if(Unterschrift_AG == null){
            return  ASettings.res.getString(R.string.visum_arbeitgeber);
        }return Unterschrift_AG;
    }

    public String getUnterschrift_AN(){
        if(Unterschrift_AN == null){
            return  ASettings.res.getString(R.string.visum_arbeitnehmer);
        }return Unterschrift_AN;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////// Optionsrückgaben////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////
    public Boolean isOptionSet(int option){
        return (Optionen & option) != 0;
    }


    public int getMonate_Zukunft(){
        return Math.max(Monate_Zukunft, 0);
    }

    public boolean isAnzeigeZukunft(){
        return (Monate_Zukunft >= 0);
    }

    public  boolean isAutoAuszahlung(){
        return isOptionSet(OPT_AUTO_AUSZAHLUNG);
    }

    public boolean isNfcAktiv() {
        return isOptionSet(OPT_NFC_AKTIV);
    }

    public boolean isIgnoreSaldo() {
        return isOptionSet(OPT_RESET_SALDO);
    }

    public boolean isIgnoreSaldoMinus() {
        return isOptionSet(OPT_RESET_SALDO_MINUS);
    }

    public boolean isIgnoreSaldoPlus() {
        return isOptionSet(OPT_RESET_SALDO_PLUS);
    }

    public boolean isIgnoreSaldoAll() {
        return isOptionSet(OPT_RESET_SALDO_PLUS) && isOptionSet(OPT_RESET_SALDO_MINUS);
    }

////////////////////////////////////////////////////////////////////////////////////////////////////


    /**********************************************************************************************
     *                Funktionen zur Liste der Defaultwerte der Schichten                         *
     * ********************************************************************************************/
    public SchichtDefaultListe getDefaultSchichten(){
        return DefaultSchichten;
    }


    // Wertrückgaben
    public boolean isTeilschicht(){
        return Teilschichten;
    }

    public int getAnzahlSchichtenTag(){
        // gibt Anzahl der Teilschichten aus
        if(Teilschichten)
            //return Schichten;
            return DefaultSchichten.getSizeAktive();
        else
            return 1;
    }

    public int getAnzahlSchichten(){
        // gibt Anzahl aller definierten Schichten aus
        //return Schichten;
        return DefaultSchichten.getSizeAktive();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////

    public EinsatzortListe getEinsatzortListe(){
        return mEinsatzorte;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////


    /**********************************************************************************************
    *                     Funktionen für abwesenheiten / Arbeitszeittypen
    ***********************************************************************************************/
    public AbwesenheitListe getAbwesenheiten(){
        return Abwesenheiten;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**********************************************************************************************
    *                     Funktionen für Zusatzwert definitionen
    ***********************************************************************************************/
    public ZusatzfeldDefinition getZusatzDefinition(int index){
        return mZusatzDefinitionen.get(index);
    }
    public ZusatzfeldDefinition getZusatzDefinition(long id){
        return mZusatzDefinitionen.get(id);
    }

    public ZusatzfeldDefinitionenListe getZusatzfeldListe(){
        return mZusatzDefinitionen;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////



    /***********************************************************************************************
     *                  Klasse und Funktionen für Sollstundenfaktor
     **********************************************************************************************/
    private static class SollstundenFaktor {
        private int jahr_monat;
        private int sollManuell;
        private float sollFaktor;
    }

    private static class SollstundenFaktorenListe {

        private static final String SQL_READ_MONAT_SOLL_MANUELL =
                "select " +
                        DatenbankHelper.DB_F_SOLL_MANUELL + ", " +
                        DatenbankHelper.DB_F_MONAT + ", " +
                        DatenbankHelper.DB_F_JAHR +
                        " from " +
                        DatenbankHelper.DB_T_MONAT +
                        " where " +
                        DatenbankHelper.DB_F_JOB +
                        " = ? AND " +
                        DatenbankHelper.DB_F_SOLL_MANUELL +
                        " >= 0";

        ArrayList<SollstundenFaktor> mFaktorenliste;

        @SuppressLint("Range")
        SollstundenFaktorenListe(Arbeitsplatz job) {
            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getReadableDatabase();

            mFaktorenliste = new ArrayList<>();

            Cursor result = ASettings.mDatenbank.rawQuery(SQL_READ_MONAT_SOLL_MANUELL, new String[]{Long.toString(job.getId())});
            while (result.moveToNext()) {
                SollstundenFaktor f = new SollstundenFaktor();
                int jahr = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_JAHR));
                int monat = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_MONAT));
                f.jahr_monat = jahr * 100 + monat;

                f.sollManuell = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_SOLL_MANUELL));
                int sollMonat = job.getSollstundenMonat(
                        new Datum(
                                jahr,
                                monat,
                                job.getMonatsbeginn(), job.getWochenbeginn()),
                        0,
                        0,
                        0);

                if (sollMonat == 0) {
                    f.sollFaktor = -1;
                    mFaktorenliste.add(f);
                } else if (f.sollManuell > 0) {
                    f.sollFaktor = (float)f.sollManuell / sollMonat;
                    mFaktorenliste.add(f);
                }

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

        void updateFaktor(Arbeitsplatz job, int jahr, int monat, int newSollManuell) {
            SollstundenFaktor mFaktor = null;
            int jahr_monat = jahr * 100 + monat;

            for (SollstundenFaktor f : mFaktorenliste) {
                if (jahr_monat == f.jahr_monat) {
                    mFaktor = f;
                    break;
                }
            }

            // der bestehende manuelle Sollstundenwert wurde zurück gesetzt
            if (mFaktor != null && newSollManuell < 0) {
                mFaktorenliste.remove(mFaktor);
            } else {
                if (newSollManuell >= 0) {
                    if (mFaktor == null) {
                        mFaktor = new SollstundenFaktor();
                        mFaktor.jahr_monat = jahr * 100 + monat;
                    }
                    mFaktor.sollManuell = newSollManuell;
                    int sollMonat = job.getSollstundenMonat(
                            new Datum(
                                    jahr,
                                    monat,
                                    job.getMonatsbeginn(), job.getWochenbeginn()),
                            0,
                            0,
                            0);
                    if (newSollManuell == 0) {
                        mFaktor.sollFaktor = 0;
                    } else if (sollMonat == 0) {
                        mFaktor.sollFaktor = -1;
                    } else {
                        mFaktor.sollFaktor = (float) newSollManuell / sollMonat;
                    }
                    mFaktorenliste.add(mFaktor);
                }
            }
        }

        float getSollstundenFaktor(int jahr, int monat) {
            float faktor = 1;
            int jahr_monat = jahr * 100 + monat;

            for (SollstundenFaktor f : mFaktorenliste) {
                if (jahr_monat == f.jahr_monat) {
                    faktor = f.sollFaktor;
                    break;
                }
            }
            return faktor;
        }

        int getSollManuell(int jahr, int monat){
            int soll = 0;
            int jahr_monat = jahr * 100 + monat;

            for (SollstundenFaktor f : mFaktorenliste) {
                if (jahr_monat == f.jahr_monat) {
                    soll = f.sollManuell;
                }
            }
            return soll;
        }
    }

    public void updateSollStundenFaktor(int jahr, int monat, int newSollManuell){
        mSollstundenFaktoren.updateFaktor(this, jahr, monat, newSollManuell);
    }
}
