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

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;

import java.util.ArrayList;

import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.arbeitszeiterfassung2.setup.LocaleHelper;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;

/** datenbank Hilfsklasse
 * @author askanimus@gmail.com on 24.01.14.
 * Die datenbank mit den Tabellen
 *  - arbeitsplatz
 *  - Monat
 *  - Wochentag
 *
 */

@SuppressLint("Range")
public class DatenbankHelper extends SQLiteOpenHelper {
    // Konstanten

    //
    // Datenbanktabellen
    //
    public static final String DB_T_TAG = "tag";
    public static final String DB_T_MONAT = "monat";
    public static final String DB_T_JOB = "arbeitsplatz";
    public static final String DB_T_SETTINGS = "einstellungen";
    public static final String DB_T_EORT = "einsatzort";
    public static final String DB_T_ABWESENHEIT = "abwesenheit";
    public static final String DB_T_SCHICHT = "schicht";
    public static final String DB_T_SCHICHT_DEFAULT = "schicht_default";
    public static final String DB_T_JAHR = "jahr";
    public static final String DB_T_AUTOREPORT = "autoreport";
    public static final String DB_T_ZUSATZFELD = "zusatzfeld";
    public static final String DB_T_ZUSATZWERT_DEFAULT = "zusatzwert_default";
    public static final String DB_T_ZUSATZWERT = "zusatzwert";
    public static final String DB_T_ZUSATZWERT_AUSWAHL = "zusatzwert_auswahl";
    public static final String DB_T_NFC_TAG = "nfc_tag";
    public static final String DB_T_STEMPELUHR_STATUS = "stempeluhr_status";
    public static final String DB_T_STEMPELUHR_ZUSATZWERT = "stempeluhr_zusatzwert";
    public static final String DB_T_FEIERTAGE = "feiertage";

    //
    // Datenfelder
    //
    public static final String DB_F_ID = "id";
    public static final String DB_F_JOB = "arbeitsplatz";
    public static final String DB_F_SCHICHT = DB_T_SCHICHT;
    public static final String DB_F_SCHICHT_DEFAULT = "schicht_default";
    public static final String DB_F_NUMMER = "nummer";
    public static final String DB_F_VON = "von";
    public static final String DB_F_BIS = "bis";
    public static final String DB_F_PAUSE = "pause";
    public static final String DB_F_JAHR = "jahr";
    public static final String DB_F_MONAT = "monat";
    public static final String DB_F_TAG = "tag";
    public static final String DB_F_JAHR_BEGINN = "jahr_beginn";
    public static final String DB_F_MONAT_BEGINN = "monat_beginn";
    public static final String DB_F_MONAT_VERFALL = "monat_verfall";
    public static final String DB_F_TAG_VERFALL = "tag_verfall";
    public static final String DB_F_TAG_BEGINN = "tag_beginn";
    public static final String DB_F_JAHR_ENDE = "jahr_ende";
    public static final String DB_F_MONAT_ENDE = "monat_ende";
    public static final String DB_F_TAG_ENDE = "tag_ende";
    public static final String DB_F_STARTSALDO = "startsaldo";
    public static final String DB_F_UEBER_PAUSCHAL = "ueber_pauschal"; // Mit dem Lohn abgegoltene Überstunden
    public static final String DB_F_AUTO_AUSZAHLUNG_AB = "auto_auszahlung_ab"; // Anzahl autom. ausbezahlter Überstunden ab einen Wert x
    public static final String DB_F_AUSZAHLUNG = "auszahlung_ue"; // ausgezahlte Überstunden
    public static final String DB_F_SOLL_H = "soll_h";
    public static final String DB_F_MODELL = "modell";       // Arbeitszeitmodell
    public static final String DB_F_SOLL_MANUELL = "soll_manuell";     // die Einstellumgen überschreibender Eintrag im Monat
    public static final String[] DB_F_SOLL_TAG = {"", "soll_sonntag", "soll_montag", "soll_dienstag", "soll_mittwoch", "soll_donnerstag", "soll_freitag", "soll_samstag"};
    public static final String DB_F_SOLL_PAUSCHAL = "soll_pauschal";
    public static final String DB_F_IST_H = "ist_h";
    public static final String DB_F_SALDO_H = "saldo_h";
    public static final String DB_F_NAME = "name";
    public static final String DB_F_EMAIL = "email";
    public static final String DB_F_EMAIL_TEXT = "mailtext";
    public static final String DB_F_ANSCHRIFT = "anschrift";
    public static final String DB_F_MONATSBEGINN = "monatsbeginn";
    public static final String DB_F_WOCHENBEGINN = "wochenbeginn";
    public static final String DB_F_ARBEITSTAGE = "arbeitstage";      // Bitfeld 1-7 erste Tageshälfet, 8-15 zweite Tageshälfte
    public static final String DB_F_MONATS_ARBEITSTAGE = "monats_arbeitstage"; // anzahl der durchschnittlichen Arbeitstage pro Monat ( nur Monatsmodell )
    public static final String DB_F_USER = "user";
    public static final String DB_F_VIEW = "view";
    public static final String DB_F_FARBE = "farbe";
    public static final String DB_F_BEMERKUNG = "bemerkung";    // Schichtnotiz
    public static final String DB_F_VERSION = "version";    // Programmversion eingeführt ab 1.4.00
    public static final String DB_F_EORT = "eort"; // einsatzort Schicht
    public static final String DB_F_T_SCHICHTEN = "teilschicht_zahl"; // Anzahl der Teilschichten pro Tag
    public static final String DB_F_SCHICHTEN = "schicht_zahl"; // Anzahl der Arbeitsschichten
    public static final String DB_F_STATUS = "status";          // ein Statuswert
    public static final String DB_F_SPESEN = "spesen";          // Höhe der Spesen
    public static final String DB_F_KM_PRIVAT = "km_privat";   // Anzahl der gefahrenen km mit Privat-PKW fürs Geschäft
    public static final String DB_F_FAHRZEIT = "fahrzeit";     // FAhrzeiten während der Arbeitszeit
    public static final String DB_F_MODULE = "module";       // Module der Zeiterfassung, Optionale eingaben
    public static final String DB_F_ABWESENHEIT = "abwesenheit";  // Nummer der Abwesenheit 0 = Keine Schicht, 1 = Arbeitszeit, 2 = Ruhetag, 3-x frei belegbar
    public static final String DB_F_KATEGORIE = "kategorie";
    public static final String DB_F_KURZ = "kurz";        // Kurzversion der Bezeichnung der Abwesenheit
    public static final String DB_F_WIRKUNG = "wirkung";     // Wirkung auf die Stundenberechnung
    public static final String DB_F_ICON = "icon";        // Icon des Zeitzusatzes
    public static final String DB_F_W_KUERZEL = "w_kurz";       // ISO-Kürzel der Währung
    //public static final String DB_F_W_TRENNER = "w_trenner";    // Trennzeichen für die Währung . oder ,
    public static final String DB_F_E_KUERZEL = "e_kurz";       // Einheite für Entfernungen km, mi etc
    public static final String DB_F_OPTIONEN = "optionen";
    public static final String DB_F_TIMER_INTERVAL = "timer_interval";
    public static final String DB_F_TIMER_ZEIT = "timer_zeit";
    public static final String DB_F_AUTOBACK_FREQ = "autobackup_freq";
    public static final String DB_F_AUTOBACK_SCHRITT = "autobackup_schritt";
    public static final String DB_F_AUTOBACK_ANZAHL = "autobackup_anzahl";
    public static final String DB_F_REPORTTYP = "reporttyp";
    public static final String DB_F_DATEITYP = "dateityp";
    public static final String DB_F_INTERVAL = "interval";
    public static final String DB_F_STICHTAG = "stichtag";
    public static final String DB_F_SOLL_URLAUB = "soll_urlaub";
    public static final String DB_F_IST_URLAUB = "ist_urlaub";
    public static final String DB_F_REST_URLAUB = "rest_urlaub";
    public static final String DB_F_TITEL_SPESEN = "t_spesen";
    public static final String DB_F_TITEL_STRECKE = "t_strecke";
    public static final String DB_F_TITEL_FAHRZEIT = "t_fahrzeit";
    public static final String DB_F_ANZEIGE_ZUKUNFT = "anzeige_zukunft";
    public static final String DB_F_START_URLAUB = "starturlaub";
    public static final String DB_F_PAUSCHAL_SPESEN = "p_spesen";
    public static final String DB_F_PAUSCHAL_STRECKE = "p_strecke";
    public static final String DB_F_PAUSCHAL_FAHRZEIT = "p_fahrzeit";
    public static final String DB_F_BACKUP_DIR = "backup_dir";
    public static final String DB_F_DATEN_DIR = "daten_dir";
    public static final String DB_F_PWD = "passwort";
    public static final String DB_F_DATENTYP = "datentyp";
    public static final String DB_F_EINHEIT = "einheit";
    public static final String DB_F_ZUSATZFELD = "zusatzfeld";
    public static final String DB_F_WERT = "wert";
    public static final String DB_F_SPALTEN = "spalten";
    public static final String DB_F_SPRACHE = "sprache";
    public static final String DB_F_POSITION = "position";
    public static final String DB_F_STUNDENLOHN = "stundenlohn";
    public static final String DB_F_UNTERSCHRIFT_AG = "u_arbeitgeber";
    public static final String DB_F_UNTERSCHRIFT_AN = "u_arbeitnehmer";
    public static final String DB_F_ANZAHL_VERWENDET = "verwendet";
    public static final String DB_F_ZULETZT_VERWENDET = "zuletzt";

    public static final String DB_F_AUTOBACKUP_INTERVALL = "autobackup_freq";
    public static final String DB_F_AUTOBACKUP_SCHRITTE = "autobackup_schritt";
    public static final String DB_F_AUTOBACKUP_ANZAHL = "autobackup_anzahl";

    public static final String DB_F_LETZTE_AENDERUNG = "aenderung";
    public static final String DB_F_ANGELEGT = "angelegt";
    public static final String DB_F_NFC_TAGID = "tagid";
    public static final String DB_F_NFC_AKTION = "aktion";
    public static final String DB_F_STEMPELUHR_STATUS = "stempeluhr_status";

    public static final String DB_F_APP_VERSION = "appversion";


    private final Context context;

    public DatenbankHelper(Context context) {
        super(
                context,
                context.getResources().getString(R.string.dbName),
                null,
                Integer.parseInt(context.getResources().getString(R.string.dbVersion))
        );
        this.context = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // Tabellen erzeugen
        for (String sql : context.getResources().getStringArray(R.array.dbCreate))
            db.execSQL(sql);
    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        switch (oldVersion) {
            case 1:
                zuZwei(db);
            case 2:
                zuDrei(db);
            case 3:
                zuVier(db);
            case 4:
                zuFuenf(db);
            case 5:
                zuSechs(db);
            case 6:
                zuSieben(db);
            case 7:
                zuAcht(db);
            case 8:
                zuNeun(db);
            case 9:
                zuZehn(db);
            case 10:
                zuElf(db);
            case 11:
                zuZwoelf(db);
            case 12:
                zuDreizehn(db);
            case 13:
                zuVierzehn(db);
            case 14:
                zuSechszehn(db);
            case 16:
                zuSiebzehn(db);
            case 17:
                zuAchtzehn(db);
        }

    }

    //
    // Versionsupdats
    //
    private void zuZwei(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE arbeitsplatz ADD starturlaub float;");
        db.execSQL("ALTER TABLE schicht_default ADD p_spesen float;");
        db.execSQL("ALTER TABLE schicht_default ADD p_strecke float;");
        db.execSQL("ALTER TABLE schicht_default ADD p_fahrzeit int;");
    }


    private void zuDrei(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE einstellungen ADD  anschrift varchar(512);");
    }

    private void zuVier(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE arbeitsplatz ADD wochenbeginn byte;");
    }

    private void zuFuenf(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE einstellungen ADD backup_dir varchar(1024);");
        db.execSQL("ALTER TABLE einstellungen ADD daten_dir varchar(1024);");


        SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();

        ContentValues werte = new ContentValues(2);

        String defPfad = Environment.getExternalStorageDirectory().toString();
        defPfad += "/" + ASettings.res.getString(R.string.app_verzeichnis);

        werte.put(DB_F_DATEN_DIR, defPfad);
        mEdit.putString(ISettings.KEY_DATEN_DIR, defPfad);

        werte.put(DB_F_BACKUP_DIR, "");

        db.update(DB_T_SETTINGS, werte, DB_F_ID + "=?", new String[]{String.valueOf(1)});

        mEdit.apply();
    }

    private void zuSechs(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE einstellungen ADD passwort varchar(128);");
        db.execSQL("ALTER TABLE arbeitsplatz ADD passwort varchar(128);");
    }

    private void zuSieben(SQLiteDatabase db) {
        int Sprache;
        ContentValues werte = new ContentValues();
        SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
        db.execSQL("ALTER TABLE einstellungen ADD sprache int;");
        db.execSQL("ALTER TABLE abwesenheit ADD position int;");

        // die momentane Sprache als Standard eintragen

        if (LocaleHelper.getLanguage(context).equals("de")) {
            Sprache = ISettings.OPT_SPRACHE_DE;
        } else {
            Sprache = ISettings.OPT_SPRACHE_EN;
        }

        werte.put(DB_F_SPRACHE, Sprache);
        db.update(DB_T_SETTINGS, werte, DB_F_ID + "=?", new String[]{"1"});

        mEdit.apply();

    }

    public static void zuAcht(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE arbeitsplatz ADD stundenlohn float;");
        db.execSQL("ALTER TABLE arbeitsplatz ADD u_arbeitgeber varchar(32);");
        db.execSQL("ALTER TABLE arbeitsplatz ADD u_arbeitnehmer varchar(32);");
        db.execSQL("ALTER TABLE einsatzort ADD verwendet int;");
        db.execSQL("ALTER TABLE einsatzort ADD zuletzt long;");

        class eort {
            private final long id;
            private int verwendung;

            private eort(long i) {
                id = i;
                verwendung = 0;
            }
        }

        String sql;
        Cursor result;
        ArrayList<eort> eo_Liste = new ArrayList<>();
        sql = "select " + DB_F_ID +
                " from " + DB_T_EORT;

        result = db.rawQuery(sql, null);
        if (result.getCount() > 0) {
            result.moveToFirst();
            do {
                eo_Liste.add(new eort(result.getLong(result.getColumnIndex(DB_F_ID))));
            } while (result.moveToNext());
        }
        result.close();


        if (eo_Liste.size() > 0) {
            sql = "select " + DB_F_EORT +
                    " from " + DB_T_SCHICHT;

            result = db.rawQuery(sql, null);
            if (result.getColumnCount() > 0) {
                long eo_id;
                while (result.moveToNext()) {
                    eo_id = result.getLong(result.getColumnIndex(DB_F_EORT));
                    if (eo_id > 0) {
                        for (eort ort : eo_Liste) {
                            if (ort.id == eo_id) {
                                ort.verwendung++;
                                break;
                            }
                        }
                    }
                }
            }
            result.close();

            ContentValues werte = new ContentValues();
            for (eort ort : eo_Liste) {
                if (ort.verwendung > 0) {
                    werte.put(DB_F_ANZAHL_VERWENDET, ort.verwendung);
                    db.update(DB_T_EORT, werte, DB_F_ID + "=?", new String[]{Long.toString(ort.id)});
                }
            }
        }


    }


    /*
     * Ab App Version 2.00.00 und Datenbankversion 9 werden alle Zusatzfelder
     * (Notiz, Strecke, Spesen, Fahrzeit) in eine Extratabelle verschoben.
     * Das wurde notwendig, damit der User beliebige Felder neu erstellen oder löschen kann.
     * zusatzfeld - nimmt die Felddefinition auf
     * zusatzwert_default - Tabelle mit in den Defaultschichten hinterlegten Zusatzwerten
     * zusatzwert - in den Schichten eingetragene Zusatzwerte
     */
    public static void zuNeun(SQLiteDatabase db) {
        StringBuilder sql = new StringBuilder();
        ContentValues werte = new ContentValues();

        ArrayList<job> mJobliste = new ArrayList<>();
        float f;
        int i;

        // Neue Tabelle für Zusatzfelder erstellen
        db.execSQL("CREATE TABLE IF NOT EXISTS zusatzfeld (" +
                "id integer primary key autoincrement," +
                " arbeitsplatz integer," +
                " name varchar(40)," +
                " datentyp int," +
                " einheit varchar(3)," +
                " wirkung int," +
                " position int," +
                " spalten int" +
                ");");

        // Neue Tabelle für die Default Werte der Zusatzfelder erstellen
        db.execSQL("CREATE TABLE IF NOT EXISTS zusatzwert_default (" +
                "id integer primary key autoincrement," +
                " zusatzfeld integer," +
                " schicht_default integer not null," +
                " wert varchar(512)" +
                ");");

        // Neue Tabelle für die Werte der Zusatzfelder erstellen
        db.execSQL("CREATE TABLE IF NOT EXISTS zusatzwert (" +
                "id integer primary key autoincrement," +
                " zusatzfeld integer," +
                " schicht integer not null," +
                " wert varchar(512)" +
                ");");

        // Felder aus den Einstellungen des Arbeitsplatz übertragen
        sql.append("select ");
        sql.append(DB_F_ID + ", ");
        sql.append(DB_F_MODULE + ", ");
        sql.append(DB_F_OPTIONEN + ", ");
        sql.append(DB_F_TITEL_SPESEN + ", ");
        sql.append(DB_F_TITEL_STRECKE + ", ");
        sql.append(DB_F_TITEL_FAHRZEIT + " ");
        sql.append("from ");
        sql.append(DB_T_JOB);
        Cursor result = db.rawQuery(sql.toString(), null);

        /*if (result.getCount() > 0) {
            result.moveToFirst();
            do {*/
        while (result.moveToNext()) {
            job mJob = new job();
            mJob.id = result.getLong(result.getColumnIndex(DB_F_ID));
            mJob.Optionen = result.getInt(result.getColumnIndex(DB_F_MODULE));

            if (mJob.isOptionSet(Arbeitsplatz.OPT_WERT_NOTIZ)) {
                mJob.Titel_Notiz = ASettings.res.getString(R.string.notiz);
                werte.put(DB_F_JOB, mJob.id);
                werte.put(DB_F_NAME, mJob.Titel_Notiz);
                werte.put(DB_F_DATENTYP, IZusatzfeld.TYP_TEXT);
                werte.put(DB_F_EINHEIT, "");
                werte.put(DB_F_WIRKUNG, IZusatzfeld.NEUTRAL);
                werte.put(DB_F_POSITION, 3);
                werte.put(DB_F_SPALTEN, IZusatzfeld.MAX_COLUM);

                mJob.ID_Notiz =
                        db.insert(DB_T_ZUSATZFELD, null, werte);
                werte.clear();
            }

            if (mJob.isOptionSet(Arbeitsplatz.OPT_WERT_STRECKE)) {
                mJob.Titel_Strecke = result.getString(result.getColumnIndex(DB_F_TITEL_STRECKE));
                if (mJob.Titel_Strecke == null)
                    mJob.Titel_Strecke = ASettings.res.getString(R.string.strecke);
                werte.put(DB_F_JOB, mJob.id);
                werte.put(DB_F_NAME, mJob.Titel_Strecke);
                werte.put(DB_F_DATENTYP, IZusatzfeld.TYP_ZAHL);
                werte.put(DB_F_EINHEIT, ASettings.sEntfernung);
                werte.put(DB_F_WIRKUNG, IZusatzfeld.NEUTRAL);
                werte.put(DB_F_POSITION, 1);
                werte.put(DB_F_SPALTEN, 1);

                mJob.ID_Strecke =
                        db.insert(DB_T_ZUSATZFELD, null, werte);
                werte.clear();
            }

            if (mJob.isOptionSet(Arbeitsplatz.OPT_WERT_FAHRZEIT)) {
                mJob.Titel_Fahrzeit = result.getString(result.getColumnIndex(DB_F_TITEL_FAHRZEIT));
                if (mJob.Titel_Fahrzeit == null)
                    mJob.Titel_Fahrzeit = ASettings.res.getString(R.string.fahrzeit);
                werte.put(DB_F_JOB, mJob.id);
                werte.put(DB_F_NAME, mJob.Titel_Fahrzeit);
                werte.put(DB_F_DATENTYP, IZusatzfeld.TYP_ZEIT);
                werte.put(DB_F_EINHEIT, ASettings.res.getString(R.string.k_stunde));
                int w = result.getInt(result.getColumnIndex(DB_F_OPTIONEN));
                // w kann 0,1 oder 2 sein. Wenn 2 dann auf 3 umstellen
                if (w == 2) {
                    w = IZusatzfeld.SUB_ISTSTUNDEN;
                }
                werte.put(DB_F_WIRKUNG, w);
                werte.put(DB_F_POSITION, 2);
                werte.put(DB_F_SPALTEN, 1);

                mJob.ID_Fahrzeit =
                        db.insert(DB_T_ZUSATZFELD, null, werte);
                werte.clear();
            }

            if (mJob.isOptionSet(Arbeitsplatz.OPT_WERT_SPESEN)) {
                mJob.Titel_Spesen = result.getString(result.getColumnIndex(DB_F_TITEL_SPESEN));
                if (mJob.Titel_Spesen == null)
                    mJob.Titel_Spesen = ASettings.res.getString(R.string.spesen);
                werte.put(DB_F_JOB, mJob.id);
                werte.put(DB_F_NAME, mJob.Titel_Spesen);
                werte.put(DB_F_DATENTYP, IZusatzfeld.TYP_ZAHL);
                werte.put(DB_F_EINHEIT, ASettings.sWaehrung);
                werte.put(DB_F_WIRKUNG, IZusatzfeld.NEUTRAL);
                werte.put(DB_F_POSITION, 0);
                werte.put(DB_F_SPALTEN, 1);

                mJob.ID_Spesen =
                        db.insert(DB_T_ZUSATZFELD, null, werte);
                werte.clear();
            }
            mJobliste.add(mJob);
        }
        //}
        result.close();
        sql = new StringBuilder();

        // Default Feldwerte aus den Default Schichten übertragen
        sql.append("select ");
        sql.append(DB_F_ID + ", ");
        sql.append(DB_F_PAUSCHAL_SPESEN + ", ");
        sql.append(DB_F_PAUSCHAL_STRECKE + ", ");
        sql.append(DB_F_PAUSCHAL_FAHRZEIT);
        sql.append(" from ");
        sql.append(DB_T_SCHICHT_DEFAULT);
        sql.append(" where ");
        sql.append(DB_F_JOB);
        sql.append(" = ?");

        for (job j : mJobliste) {
            if (j.isOptionSet(Arbeitsplatz.OPT_WERT_STRECKE) ||
                    j.isOptionSet(Arbeitsplatz.OPT_WERT_SPESEN) ||
                    j.isOptionSet(Arbeitsplatz.OPT_WERT_FAHRZEIT) ||
                    j.isOptionSet(Arbeitsplatz.OPT_WERT_NOTIZ)) {

                result = db.rawQuery(sql.toString(), new String[]{Long.toString(j.id)});

                /*if (result.getCount() > 0) {
                    result.moveToFirst();

                    do {*/
                while (result.moveToNext()) {
                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_SPESEN)) {
                        f = result.getFloat(
                                result.getColumnIndex(DB_F_PAUSCHAL_SPESEN)
                        );
                        werte.put(DB_F_ZUSATZFELD, j.ID_Spesen);
                        werte.put(DB_F_SCHICHT_DEFAULT,
                                result.getLong(result.getColumnIndex(DB_F_ID))
                        );
                        werte.put(DB_F_WERT, f);
                        db.insert(DB_T_ZUSATZWERT_DEFAULT, null, werte);
                        werte.clear();
                    }

                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_STRECKE)) {
                        f = result.getFloat(
                                result.getColumnIndex(DB_F_PAUSCHAL_STRECKE)
                        );
                        werte.put(DB_F_ZUSATZFELD, j.ID_Strecke);
                        werte.put(DB_F_SCHICHT_DEFAULT,
                                result.getLong(result.getColumnIndex(DB_F_ID))
                        );
                        werte.put(DB_F_WERT, f);
                        db.insert(DB_T_ZUSATZWERT_DEFAULT, null, werte);
                        werte.clear();
                    }

                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_FAHRZEIT)) {
                        i = result.getInt(
                                result.getColumnIndex(DB_F_PAUSCHAL_FAHRZEIT)
                        );
                        werte.put(DB_F_ZUSATZFELD, j.ID_Fahrzeit);
                        werte.put(DB_F_SCHICHT_DEFAULT,
                                result.getLong(result.getColumnIndex(DB_F_ID))
                        );
                        werte.put(DB_F_WERT, i);
                        db.insert(DB_T_ZUSATZWERT_DEFAULT, null, werte);
                        werte.clear();
                    }

                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_NOTIZ)) {
                        werte.put(DB_F_ZUSATZFELD, j.ID_Notiz);
                        werte.put(DB_F_SCHICHT_DEFAULT,
                                result.getLong(result.getColumnIndex(DB_F_ID))
                        );
                        werte.put(DB_F_WERT, "");
                        db.insert(DB_T_ZUSATZWERT_DEFAULT, null, werte);
                        werte.clear();
                    }


                }

                result.close();
                //}
            }
            // Die Zusatzwerte aus den Schichten in die Zusatzwert Tabelle übertragen
            moveTask m = new moveTask(db, j);
            m.run();
        }

    }

    /*
     * Zusatzwerte der Schichten in Zusatzwertliste übertragen
     */
    static class moveTask implements Runnable {

        job mArbeitsplatz;
        SQLiteDatabase mDatenbank;

        moveTask(SQLiteDatabase db, job j) {
            mArbeitsplatz = j;
            mDatenbank = db;
        }

        @Override
        public void run() {
            moveZusatzwerte(mDatenbank, mArbeitsplatz);
        }
    }

    private static void moveZusatzwerte(SQLiteDatabase db, job j) {
        boolean isNotiz = j.isOptionSet(Arbeitsplatz.OPT_WERT_NOTIZ);
        boolean isSpesen = j.isOptionSet(Arbeitsplatz.OPT_WERT_SPESEN);
        boolean isStrecke = j.isOptionSet(Arbeitsplatz.OPT_WERT_STRECKE);
        boolean isFahrzeit = j.isOptionSet(Arbeitsplatz.OPT_WERT_FAHRZEIT);

        StringBuilder sqlTag = new StringBuilder();
        sqlTag.append("select ");
        sqlTag.append(DB_F_ID);
        sqlTag.append(" from ");
        sqlTag.append(DB_T_TAG);
        sqlTag.append(" where ");
        sqlTag.append(DB_F_JOB);
        sqlTag.append(" = ?");

        ContentValues werteSchicht = new ContentValues();
        StringBuilder sqlSchicht = new StringBuilder();
        sqlSchicht.append("select ");
        sqlSchicht.append(DB_F_ID + ", ");
        sqlSchicht.append(DB_F_BEMERKUNG + ", ");
        sqlSchicht.append(DB_F_SPESEN + ", ");
        sqlSchicht.append(DB_F_KM_PRIVAT + ", ");
        sqlSchicht.append(DB_F_FAHRZEIT);
        sqlSchicht.append(" from ");
        sqlSchicht.append(DB_T_SCHICHT);
        sqlSchicht.append(" where ");
        sqlSchicht.append(DB_F_TAG);
        sqlSchicht.append(" = ?");

        if (isNotiz || isSpesen || isStrecke || isFahrzeit) {
            Cursor resultTag = db.rawQuery(sqlTag.toString(), new String[]{Long.toString(j.id)});
            /*if(resultTag.getCount() > 0){
                resultTag.moveToFirst();

                do{*/
            while (resultTag.moveToNext()) {
                String s;
                float f;
                int i;
                Cursor resultSchicht = db.rawQuery(sqlSchicht.toString(), new String[]{Long.toString(resultTag.getLong(resultTag.getColumnIndex(DB_F_ID)))});
                while (resultSchicht.moveToNext()) {
                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_SPESEN)) {
                        f = resultSchicht.getFloat(
                                resultSchicht.getColumnIndex(DB_F_SPESEN)
                        );
                        werteSchicht.put(DB_F_ZUSATZFELD, j.ID_Spesen);
                        werteSchicht.put(DB_F_SCHICHT,
                                resultSchicht.getLong(resultSchicht.getColumnIndex(DB_F_ID))
                        );
                        werteSchicht.put(DB_F_WERT, f);
                        db.insert(DB_T_ZUSATZWERT, null, werteSchicht);
                    }

                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_STRECKE)) {
                        f = resultSchicht.getFloat(
                                resultSchicht.getColumnIndex(DB_F_KM_PRIVAT)
                        );
                        werteSchicht.put(DB_F_ZUSATZFELD, j.ID_Strecke);
                        werteSchicht.put(DB_F_SCHICHT,
                                resultSchicht.getLong(resultSchicht.getColumnIndex(DB_F_ID))
                        );
                        werteSchicht.put(DB_F_WERT, f);
                        db.insert(DB_T_ZUSATZWERT, null, werteSchicht);
                    }

                    if (j.isOptionSet(Arbeitsplatz.OPT_WERT_FAHRZEIT)) {
                        i = resultSchicht.getInt(
                                resultSchicht.getColumnIndex(DB_F_FAHRZEIT)
                        );
                        werteSchicht.put(DB_F_ZUSATZFELD, j.ID_Fahrzeit);
                        werteSchicht.put(DB_F_SCHICHT,
                                resultSchicht.getLong(resultSchicht.getColumnIndex(DB_F_ID))
                        );
                        werteSchicht.put(DB_F_WERT, i);
                        db.insert(DB_T_ZUSATZWERT, null, werteSchicht);
                    }

                    if (isNotiz) {
                        s = resultSchicht.getString(
                                resultSchicht.getColumnIndex(DB_F_BEMERKUNG)
                        );
                        if (s == null)
                            s = "";
                        werteSchicht.put(DB_F_ZUSATZFELD, j.ID_Notiz);
                        werteSchicht.put(DB_F_SCHICHT,
                                resultSchicht.getLong(resultSchicht.getColumnIndex(DB_F_ID))
                        );
                        werteSchicht.put(DB_F_WERT, s);
                        db.insert(DB_T_ZUSATZWERT, null, werteSchicht);
                    }
                }

                resultSchicht.close();
            }
            resultTag.close();
        }
    }

    /*
     * Zwichenspeicher der Zusatzwerte und der alten Job IDs für zu migrierende Arbeitsplätze
     */
    static class job {
        private long id;
        private int Optionen;
        private String Titel_Notiz;
        private long ID_Notiz = -1;
        private String Titel_Spesen;
        private long ID_Spesen = -1;
        private String Titel_Fahrzeit;
        private long ID_Fahrzeit = -1;
        private String Titel_Strecke;
        private long ID_Strecke = -1;

        private Boolean isOptionSet(int option) {
            return (Optionen & option) != 0;
        }
    }

    private void zuZehn(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE schicht_default ADD position int;");
    }

    private void zuElf(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE arbeitsplatz ADD ueber_pauschal int;");
        db.execSQL("UPDATE arbeitsplatz SET  ueber_pauschal = 0");
    }

    private void zuZwoelf(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE schicht ADD aenderung integer;");
        db.execSQL("UPDATE schicht SET aenderung = 0");
    }

    private void zuDreizehn(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE schicht ADD angelegt integer;");
        db.execSQL("UPDATE schicht SET angelegt = 0");
    }

    public static void zuVierzehn(SQLiteDatabase db) {
        // Neue Tabelle für die Auswahlwerte der Zusatzfelder erstellen
        db.execSQL("CREATE TABLE IF NOT EXISTS zusatzwert_auswahl (" +
                "id integer primary key autoincrement," +
                " zusatzfeld integer," +
                " wert varchar(512)," +
                " verwendet int" +
                ");");

        // automatische Ausztahlung von Überstunden ab einem bestimmten Wert
        try {
            db.execSQL("ALTER TABLE arbeitsplatz ADD auto_auszahlung_ab integer;");
        } catch (SQLiteException ex) {
            ex.printStackTrace();
        }
        db.execSQL("UPDATE arbeitsplatz SET auto_auszahlung_ab = 0");

        // alle Monate mit 0 ausbezahlten Überstunden auf -1 ausbezahlten Überstunden setzen
        // -1 heisst, autom. berechnet, wenn die autom. Auszahlung eingestellt wurde
        String sqlAuszahlung = "select " +
                DB_F_ID + ", " +
                DB_F_AUSZAHLUNG +
                " from " +
                DB_T_MONAT +
                " where " +
                DB_F_AUSZAHLUNG +
                " = ? ";

        Cursor resultAuszahlung = db.rawQuery(sqlAuszahlung, new String[]{"0"});
        ContentValues wertAuszahlung = new ContentValues();
        wertAuszahlung.put(DB_F_AUSZAHLUNG, -1);
        long id;
        while (resultAuszahlung.moveToNext()) {
            id = resultAuszahlung.getLong(resultAuszahlung.getColumnIndex(DB_F_ID));
            db.update(
                    DB_T_MONAT,
                    wertAuszahlung,
                    DB_F_ID + " = ?",
                    new String[]{Long.toString(id)}
            );
        }
        resultAuszahlung.close();
    }

    public static void zuSechszehn(SQLiteDatabase db) {
        // Zusatzwerte Auswahl Tabelle korrigieren
        try {
            db.execSQL("ALTER TABLE zusatzwert_auswahl ADD verwendet int;");
            db.execSQL("UPDATE zusatzwert_auswahl SET verwendet = 0");
        } catch (SQLiteException ex) {
            ex.fillInStackTrace();
        }

        // Neue Tabelle für die registrierten NFC Tags
        db.execSQL("CREATE TABLE IF NOT EXISTS nfc_tag (" +
                "id integer primary key autoincrement," +
                " tagid integer," +
                " name varchar(40)," +
                " arbeitsplatz integer," +
                " aktion int" +
                ");");

        // neue Tabelle mit den Stempeluhren
        db.execSQL("CREATE TABLE IF NOT EXISTS stempeluhr_status (" +
                " id integer primary key autoincrement," +
                " arbeitsplatz integer not null," +
                " schicht_default integer," +
                " name varchar(40)," +
                " abwesenheit integer," +
                " eort integer" +
                ");");

        // neue Tabelle mit Zusatzwerten für die Stempeluhren
        db.execSQL("CREATE TABLE IF NOT EXISTS stempeluhr_zusatzwert (" +
                " id integer primary key autoincrement," +
                " stempeluhr_status integer," +
                " zusatzfeld integer," +
                " wert varchar(512)" +
                ");");
    }

    /*
     * Setzt bei allen Arbeitsplätzen, in denen das Ignorieren des Saldos vom Vormonat gesetzt wurde
     * auch die beiden neuen Unteroptionen für positiven und negativen Saldo,
     * damit die App ab Version 2.09.013 weiter korrekt rechnet
     */
    public static void zuSiebzehn(SQLiteDatabase db) {
        ContentValues newOptionen = new ContentValues();
        int optionen;

        // alle Arbeitsplätze einlesen
        String sql = "select " +
                DB_F_ID + ", " +
                DB_F_MODULE + " "  +
                "from " +
                DB_T_JOB;
        Cursor result = db.rawQuery(sql, null);

        while (result.moveToNext()) {
            optionen = result.getInt(result.getColumnIndex(DB_F_MODULE));

            // Wenn die Option zum ignorieren des Saldos vom Vormonat gesetzt ist
            // beide Unterotionen setzen (+/-)
            if ((optionen & Arbeitsplatz.OPT_RESET_SALDO) != 0) {
                optionen = optionen
                        | Arbeitsplatz.OPT_RESET_SALDO_MINUS
                        | Arbeitsplatz.OPT_RESET_SALDO_PLUS;

                newOptionen.put(DB_F_MODULE, optionen);
                db.update(
                        DB_T_JOB,
                        newOptionen,
                        DB_F_ID + " = ?",
                        new String[]{Long.toString(result.getLong(result.getColumnIndex(DB_F_ID)))}
                );
                newOptionen.clear();
            }
        }
        result.close();
    }

    /*
     * Führt eine Tabelle "Feiertage" ein
     * In diese werden importierte Feiertage gespeichert
     */
    private void zuAchtzehn(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS feiertage (" +
                " id integer primary key autoincrement," +
                " jahr int," +
                " monat int," +
                " tag int," +
                " name varchar(64)" +
                ");");
    }
}
