/* Copyright 2014-2019 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.widget;

import static androidx.core.content.ContextCompat.getString;
import static androidx.core.content.res.TypedArrayUtils.getText;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.Toast;

import androidx.annotation.NonNull;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import askanimus.arbeitszeiterfassung2.MainActivity;
import askanimus.arbeitszeiterfassung2.abwesenheiten.Abwesenheit;
import askanimus.arbeitszeiterfassung2.arbeitswoche.Arbeitswoche;
import askanimus.arbeitszeiterfassung2.arbeitsmonat.Arbeitsmonat;
import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.Arbeitsschicht;
import askanimus.arbeitszeiterfassung2.arbeitstag.Arbeitstag;
import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.arbeitsschicht.SchichtDefault;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;


/**
 * Implementation of App Widget functionality.
 * App Widget Configuration implemented in {@link WidgetConfigureActivity StempeluhrConfigureActivity}
 */
public class Widget extends AppWidgetProvider {
    private static final int PUFFER = 60;

    public static final String START_CLICKED = "askanimus.StempeluhrStart";
    public static final String PAUSE_CLICKED = "askanimus.StempeluhrPause";
    public static final String STOP_CLICKED = "askanimus.StempeluhrStop";
    private static final String BACKGROUND_CLICKED = "askanimus.StempeluhrOpenApp";
    private static final String ZEIT_CLICKED = "askanimus.StempeluhrChangeStart";
    private static final String ZEIT_CHANGED = "askanimus.StempeluhrSetStart";
    public static final String OPEN_ZEITAUSWAHL= "askanimus.StempeluhrOpenZeitAuswahl";
    public static final String CLOSE_ZEITAUSWAHL= "askanimus.StempeluhrCloseZeitAuswahl";
    public static final String UPDATE = "askanimus.StempeluhrUpdate";
    public static final String TIMER = "askanimus.StempeluhrTIMER";
    public static final String OPEN_SCHICHTAUSWAHL= "askanimus.StempeluhrOpenSchichtAuswahl";
    public static final String CLOSE_SCHICHTAUSWAHL= "askanimus.StempeluhrCloseSchichtAuswahl";
    public static final String KEY_WIDGET_ID = AppWidgetManager.EXTRA_APPWIDGET_ID;
    public static final String KEY_WIDGET_CONFIG = AppWidgetManager.EXTRA_APPWIDGET_OPTIONS;
    public static final String KEY_VON = "stempel_von";
    public static final String KEY_BIS = "stempel_bis";
    public static final String KEY_PAUSE = "stempel_pause";
    public static final String KEY_DEFSCHICHT = "stempel_defschicht_id";
    public static final String KEY_ADDSCHICHT = "add_extraschicht";

    private static AlarmManager mAlarmManager;
    //private static NfcAdapter nfcAdapter = null;


    public static void updateAppWidget(
            Context context,
            AppWidgetManager appWidgetManager,
            int addWidgetID
    ) {

        // den momentanen Status, die Einstellungen des Widges lesen
        WidgetStatus wStatus = WidgetConfigureActivity.loadPref(context, addWidgetID, UPDATE);

        // das Widget Layout laden
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget2x4);

        // den Button zum Configurieren des Widget beleben
        Intent configurationIntent = new Intent(context, WidgetConfigureActivity.class);
        configurationIntent.putExtra(Widget.KEY_WIDGET_ID, addWidgetID);
        configurationIntent.putExtra(KEY_WIDGET_CONFIG, true);
        int flags = PendingIntent.FLAG_UPDATE_CURRENT;
        flags = flags | PendingIntent.FLAG_IMMUTABLE;

        views.setOnClickPendingIntent(
                R.id.WS_button_einstellungen,
                PendingIntent.getActivity(
                        context,
                        addWidgetID,
                        configurationIntent,
                        flags));


        // Die Ansicht des Widgets aktuallisieren
        if (wStatus != null) {
            // beim Click auf den Widgethintergrund, die App öffnen
            // aktueller Tag des betreffenden Arbeitsplatzes
            views.setOnClickPendingIntent(
                    R.id.WS_box_widget,
                    getPendingSelfIntent(context, BACKGROUND_CLICKED, (int)wStatus.mID)
            );

            Uhrzeit mNetto = new Uhrzeit(0);
            Datum mCal = new Datum(new Date(), wStatus.mJob.getWochenbeginn());
            Uhrzeit mEnde = new Uhrzeit();

            // Werte aktuallisieren und Buttons zeigen bzw. verbergen
            switch (wStatus.mStatus) {
                case WidgetStatus.WIDGET_STATUS_RUN:
                    // Bruttozeit berechnen = Laufzeit des Widgets
                    mNetto.set((mEnde.getAlsMinuten() - wStatus.mBeginn.getAlsMinuten()) + (wStatus.mTag.tageBis(mCal) * ISettings.Minuten_TAG));

                    // Wenn ein Timer gesetzt wurde, prüfen ob er schon erreicht ist
                    /*StempeluhrStatus.TimerEintrag mTimerEintrag = wStatus.getNextTimer(mNetto.getAlsMinuten());
                    if (mTimerEintrag != null && mNetto.getAlsMinuten() >= mTimerEintrag.minuten) {
                        // Alarm ausgeben
                        openTimerAlarm(context, wStatus);
                    }*/

                    // Wenn 24h erreicht oder überschritten wurden, ausstempeln
                    if (mNetto.getAlsMinuten() >= ISettings.Minuten_TAG) {
                        ausstempeln(context, wStatus);
                    } else {
                        if (!wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_PAUSE_BEZAHLT))
                            mNetto.add(-wStatus.mPauseSumme.getAlsMinuten());

                        // Sichtbarkeiten einstellen
                        views.setViewVisibility(R.id.WS_button_pause, View.VISIBLE);
                        views.setViewVisibility(R.id.WS_button_stop, View.VISIBLE);
                        views.setViewVisibility(R.id.WS_button_start, View.INVISIBLE);

                        views.setViewVisibility(R.id.WS_box_zeiten, View.VISIBLE);

                        // Klickhandler registrieren bzw. erneuern
                        views.setOnClickPendingIntent(R.id.WS_button_pause, getPendingSelfIntent(context, PAUSE_CLICKED, (int)wStatus.mID));
                        views.setOnClickPendingIntent(R.id.WS_button_stop, getPendingSelfIntent(context, STOP_CLICKED, (int)wStatus.mID));
                        views.setOnClickPendingIntent(R.id.WS_wert_von_bis, getPendingSelfIntent(context, ZEIT_CLICKED, (int)wStatus.mID));

                    }
                    break;
                case WidgetStatus.WIDGET_STATUS_PAUSE:
                    wStatus.updatePause(mEnde.getAlsMinuten());

                    mNetto.set(mEnde.getAlsMinuten() - wStatus.mBeginn.getAlsMinuten() + (wStatus.mTag.tageBis(mCal) * ISettings.Minuten_TAG));

                    // Wenn 24h erreicht oder überschritten wurden ausstempeln
                    if (mNetto.getAlsMinuten() >= ISettings.Minuten_TAG) {
                        ausstempeln(context, wStatus);
                    } else {
                        if (!wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_PAUSE_BEZAHLT))
                            mNetto.set(mNetto.getAlsMinuten() - wStatus.mPauseSumme.getAlsMinuten());

                        views.setViewVisibility(R.id.WS_button_pause, View.INVISIBLE);
                        views.setViewVisibility(R.id.WS_button_stop, View.VISIBLE);
                        views.setViewVisibility(R.id.WS_button_start, View.VISIBLE);

                        // Klickhandler registrieren bzw. erneuern
                        views.setOnClickPendingIntent(R.id.WS_button_start, getPendingSelfIntent(context, START_CLICKED, (int)wStatus.mID));
                        views.setOnClickPendingIntent(R.id.WS_button_stop, getPendingSelfIntent(context, STOP_CLICKED, (int)wStatus.mID));
                        views.setOnClickPendingIntent(R.id.WS_wert_von_bis, getPendingSelfIntent(context, ZEIT_CLICKED, (int)wStatus.mID));
                    }
                    break;
                default:
                    wStatus.mTag.set(mCal.getDate());
                    views.setViewVisibility(R.id.WS_button_pause, View.INVISIBLE);
                    views.setViewVisibility(R.id.WS_button_stop, View.INVISIBLE);
                    views.setViewVisibility(R.id.WS_button_start, View.VISIBLE);

                    views.setViewVisibility(R.id.WS_box_zeiten, View.INVISIBLE);
                    views.setViewVisibility(R.id.WS_wert_pause, View.INVISIBLE);

                    // Klickhandler registrieren bzw. erneuern
                    views.setOnClickPendingIntent(R.id.WS_button_start, getPendingSelfIntent(context, START_CLICKED, (int)wStatus.mID));

                    // das aktuelle Datum anzeigen
                    views.setTextViewText(R.id.WS_wert_datum, mCal.getString_Datum(context));
                    break;
            }

            if (wStatus.mStatus != WidgetStatus.WIDGET_STATUS_NEU) {
                // Das Datum
                if (wStatus.mTag.tageBis(mCal) == 0) {
                    views.setTextViewText(R.id.WS_wert_datum, wStatus.mTag.getString_Datum(context));
                } else {
                    views.setTextViewText(
                            R.id.WS_wert_datum,
                            wStatus.mTag.getString_Datum_Bereich(
                                    context,
                                    0,
                                    wStatus.mTag.tageBis(mCal),
                                    Calendar.DAY_OF_MONTH));
                }

                // Die Zeitspanne zwichen Einstempeln und jetzt
                views.setTextViewText(R.id.WS_wert_von_bis, wStatus.mBeginn.getUhrzeitString() + " - " + mEnde.getUhrzeitString());

                // Die gesamte Pausenzeit
                if (wStatus.mPauseSumme.getAlsMinuten() > 0 || wStatus.mStatus == WidgetStatus.WIDGET_STATUS_PAUSE) {
                    views.setViewVisibility(R.id.WS_wert_pause, View.VISIBLE);
                    views.setTextViewText(R.id.WS_wert_pause, ASettings.res.getString(R.string.pause) + ": " + wStatus.mPauseSumme.getStundenString(true, wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));
                } else {
                    views.setViewVisibility(R.id.WS_wert_pause, View.INVISIBLE);
                }
            }

            // die Netto Arbeitszeit
            views.setTextViewText(R.id.WS_wert_netto, mNetto.getStundenString(true, wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));

            // der Arbeitsplatzname
            views.setTextViewText(R.id.WS_wert_job, wStatus.mJob.getName());
            views.setInt(R.id.WS_wert_job, "setBackgroundColor", wStatus.mJob.getFarbe_Widget_Titel_Background());
            views.setInt(R.id.WS_button_einstellungen, "setBackgroundColor", wStatus.mJob.getFarbe_Widget_Titel_Background());

            // der Schichtname
            /* if(wStatus.mSchichtDefinition > 0){
               views.setViewVisibility( R.id.WS_wert_schicht, View.VISIBLE);
               views.setTextViewText(
                       R.id.WS_wert_schicht,
                       wStatus.mJob.getDefaultSchichten().getVonId(wStatus.mSchichtDefinition).getName()
               );
            } else {*/
              //views.setViewVisibility( R.id.WS_wert_schicht, View.INVISIBLE);
            //}


            // der momentaner Wochhensaldo
            Arbeitswoche mWoche = new Arbeitswoche(wStatus.mTag.getTimeInMillis(), wStatus.mJob);
            views.setTextViewText(R.id.WS_titel_woche, ASettings.res.getString(R.string.woche_nummer, mWoche.getNummer()));
            Uhrzeit nettoWert = new Uhrzeit(mWoche.getIst() - mWoche.getSoll() + mNetto.getAlsMinuten());
            views.setTextViewText(R.id.WS_wert_woche, nettoWert.getStundenString(true, wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));
            if (nettoWert.getAlsMinuten() < 0)
                views.setTextColor(R.id.WS_wert_woche, ASettings.res.getColor(R.color.negativ));
            else if (nettoWert.getAlsMinuten() > 0)
                views.setTextColor(R.id.WS_wert_woche, ASettings.res.getColor(R.color.positiv));

            // der momentane Monatssaldo
            String sMonat;
            Datum mDatum = wStatus.mJob.getAbrechnungsmonat(wStatus.mTag);
            Arbeitsmonat mMonat = new Arbeitsmonat(
                    wStatus.mJob,
                    mDatum.get(Calendar.YEAR),
                    mDatum.get(Calendar.MONTH),
                    true, false);
            if (wStatus.mJob.getMonatsbeginn() > 1) {
                SimpleDateFormat dFormat = new SimpleDateFormat("MMM", Locale.getDefault());
                sMonat = dFormat.format(mDatum.getDate());
                sMonat += "/";
                mDatum.add(Calendar.MONTH, 1);
                sMonat += dFormat.format(mDatum.getDate());
            } else {
                SimpleDateFormat dFormat = new SimpleDateFormat("MMMM", Locale.getDefault());
                sMonat = dFormat.format(mDatum.getDate());
            }
            views.setTextViewText(R.id.WS_titel_monat, sMonat);

            nettoWert.set(mMonat.getSaldo_Aktuell(wStatus.mTag.get(Calendar.DAY_OF_MONTH)) + mNetto.getAlsMinuten());
            views.setTextViewText(R.id.WS_wert_monat, nettoWert.getStundenString(true, wStatus.mJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));
            if (nettoWert.getAlsMinuten() < 0)
                views.setTextColor(R.id.WS_wert_monat, ASettings.res.getColor(R.color.negativ));
            else if (nettoWert.getAlsMinuten() > 0)
                views.setTextColor(R.id.WS_wert_monat, ASettings.res.getColor(R.color.positiv));

            // sind die Aufzeichnungen Beendet oder haben noch nicht begonnen, dann das Widget sperren
            // die laufende Aufzeichnung läuft bis 24h nach Aufzeichnungsende weiter und wird dann beendet
            if (wStatus.mJob.isEndeAufzeichnung(mCal)) {
                // wenn Aufzeichnung noch läuft, dann das Sperrsymbol nicht anzeigen
                if (wStatus.mStatus == WidgetStatus.WIDGET_STATUS_NEU) {
                    views.setViewVisibility(R.id.WS_image_end, View.VISIBLE);
                    views.setViewVisibility(R.id.WS_button_start, View.GONE);
                }
            } else if (mCal.liegtVor(wStatus.mJob.getStartDatum())) {
                // wenn Aufzeichnung noch läuft, dann das Sperrsymbol nicht anzeigen
                if (wStatus.mStatus == WidgetStatus.WIDGET_STATUS_NEU) {
                    views.setViewVisibility(R.id.WS_image_end, View.VISIBLE);
                    views.setViewVisibility(R.id.WS_button_start, View.GONE);
                }
            } else {
                views.setViewVisibility(R.id.WS_image_end, View.GONE);
            }

            // Der arbeitsplatz ist nicht gelöscht
            views.setViewVisibility(R.id.WS_box_delete, View.GONE);
            views.setViewVisibility(R.id.WS_button_einstellungen, View.VISIBLE);
        } else {
            // Der arbeitsplatz ist gelöscht
            views.setViewVisibility(R.id.WS_box_delete, View.VISIBLE);
            views.setViewVisibility(R.id.WS_button_einstellungen, View.INVISIBLE);
        }
        // Mitteilen, dass der Widgetmanager alle Widgets neu zeichnen soll
        appWidgetManager.updateAppWidget(addWidgetID, views);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        String appAction = intent.getAction();
        Bundle extras = intent.getExtras();

        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        WidgetStatus mStatus;

        if (extras != null && appAction != null) {
            if (appAction.equals(UPDATE)) {
                ComponentName cName = new ComponentName(context.getPackageName(), Widget.class.getName());
                int[] appWidgetIds = appWidgetManager.getAppWidgetIds(cName);
                for (int appWidgetId : appWidgetIds) {
                    updateAppWidget(context, appWidgetManager, appWidgetId);
                }
            } else {
                mStatus = WidgetConfigureActivity.loadPref(
                        context,
                        extras.getInt(Widget.KEY_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID),
                        appAction
                );
                if (mStatus != null) {
                    switch (appAction) {
                        case START_CLICKED:
                            if (mStatus.mStatus == WidgetStatus.WIDGET_STATUS_NEU) {
                                mStatus.start();
                            } else {
                                mStatus.stopPause();
                            }

                            // den Status speichern
                            mStatus.save(ASettings.mPreferenzen);
                            updateAppWidget(context, appWidgetManager, (int) mStatus.mID);

                            break;
                        case PAUSE_CLICKED:
                            mStatus.startPause();
                            mStatus.save(ASettings.mPreferenzen);
                            updateAppWidget(context, appWidgetManager, (int) mStatus.mID);
                            break;
                        case STOP_CLICKED:
                            mStatus.stop();
                            ausstempeln(context, mStatus);
                            updateAppWidget(context, appWidgetManager, (int) mStatus.mID);
                            break;
                        case BACKGROUND_CLICKED:
                            // den entsprechenden Tag öffnen
                            Intent iMain = new Intent();
                            iMain.putExtra(ISettings.KEY_ANZEIGE_VIEW, ISettings.VIEW_TAG);
                            iMain.putExtra(ISettings.KEY_ANZEIGE_DATUM, new Date().getTime());
                            iMain.putExtra(ISettings.KEY_JOBID, mStatus.mJob.getId());
                            iMain.setClass(context, MainActivity.class);
                            iMain.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            iMain.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            context.startActivity(iMain);
                            break;
                        case CLOSE_SCHICHTAUSWAHL:
                            // Zeiten eintragen
                            SchichtDefault defSchicht = mStatus.mJob.getDefaultSchichten().getVonId(
                                    extras.getLong(KEY_DEFSCHICHT, 0)
                            );
                            schichtEintragen(
                                    context,
                                    mStatus,
                                    defSchicht,
                                    new Uhrzeit(extras.getInt(KEY_VON, 0)),
                                    new Uhrzeit(extras.getInt(KEY_BIS, 0)),
                                    new Uhrzeit(extras.getInt(KEY_PAUSE, 0)),
                                    extras.getBoolean(KEY_ADDSCHICHT, mStatus.isOptionSet(WidgetStatus.OPT_EXTRASCHICHT))
                            );
                            updateAppWidget(context, appWidgetManager, mStatus.mID);
                            break;
                        case ZEIT_CLICKED:
                            // die Startzeit soll angepasst werden
                            Intent setStartzeitIntent = new Intent(
                                    context, WidgetSetStartzeit.class
                            );
                            // die ID des betreffenden Widgets übergeben
                            setStartzeitIntent.putExtra(
                                    Widget.KEY_WIDGET_ID,
                                    mStatus.mID
                            );
                            // die aktuelle Startzeit übergeben
                            setStartzeitIntent.putExtra(KEY_VON, mStatus.mBeginn.getAlsMinuten());

                            // die ID des Arbeitsplatzes übergeben
                            setStartzeitIntent.putExtra(ISettings.KEY_JOBID, mStatus.mJob.getId());

                            setStartzeitIntent.setAction(OPEN_ZEITAUSWAHL);
                            setStartzeitIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            setStartzeitIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            context.startActivity(setStartzeitIntent);
                            break;
                        case CLOSE_ZEITAUSWAHL:
                            int newStarzeit = extras.getInt(KEY_VON, mStatus.mBeginn.getAlsMinuten());
                            if (newStarzeit > new Uhrzeit().getAlsMinuten()) {
                                // die neue Startzeit liegt nach der aktuellen Zeit
                                // also wurde schon am Vortag gestartet
                                mStatus.mTag.add(Calendar.DAY_OF_MONTH, -1);
                            }
                            mStatus.mBeginn.set(newStarzeit);
                            mStatus.save(ASettings.mPreferenzen);
                            Toast.makeText(
                                    context,
                                    ASettings.res.getString(R.string.widget_neue_startzeit, mStatus.mBeginn.getUhrzeitString()),
                                    Toast.LENGTH_LONG).show();

                            updateAppWidget(context, appWidgetManager, mStatus.mID);
                            break;
                    }
                }
            }
        }
    }

    protected static void ausstempeln(Context context, @NonNull WidgetStatus mStatus) {
        Calendar zeitpunktEnde = Calendar.getInstance();
        zeitpunktEnde.setTime(new Date());
        Datum mKalender = new Datum(zeitpunktEnde, mStatus.mJob.getWochenbeginn());
        ASettings.aktDatum.set(mKalender.getDate());
        Uhrzeit mEnde = new Uhrzeit(zeitpunktEnde.get(Calendar.HOUR_OF_DAY), zeitpunktEnde.get(Calendar.MINUTE));


        int mZeitspanne = mEnde.getAlsMinuten() - mStatus.mBeginn.getAlsMinuten() + (mStatus.mTag.tageBis(mKalender) * ISettings.Minuten_TAG);

        // wenn der Timer >= 1 Minute in Betrieb war
        if (mZeitspanne > 0) {
            // die gestempelten Zeiten werden ggf. gerundet
            Uhrzeit mVon = mStatus.runden(
                    mStatus.mBeginn.getAlsMinuten(),
                    mStatus.mRundenVon,
                    mStatus.mRundenVon_minuten
            );
            Uhrzeit mBis = mStatus.runden(
                    (mZeitspanne > ISettings.Minuten_TAG) ? mStatus.mBeginn.getAlsMinuten() : mEnde.getAlsMinuten(),
                    mStatus.mRundenBis,
                    mStatus.mRundenBis_minuten
            );
            Uhrzeit mPause = mStatus.runden(
                    mStatus.mPauseSumme.getAlsMinuten(),
                    mStatus.mRundenPause,
                    mStatus.mRundenPause_minuten
            );

            // die erkannte Schichtdefinition
            SchichtDefault defSchicht = null;

            // Schicht erkennen wenn gewünscht
            if (mStatus.isOptionSet(WidgetStatus.OPT_ERKENNE_SCHICHT)) {

                // die Lister der Treffer der Schichterkennung
                ArrayList<SchichtDefault> schichtDefinitionen = erkenneSchicht(mStatus.mJob, mVon, mBis);

                // ist nur ein Treffer in der Liste, diesen als erkannte Schichtdefinition setzen
                // ansonsten einen Auswahldialog öffnen
                if (schichtDefinitionen.size() == 1) {
                    // es gibt genau einen Treffer
                    defSchicht = schichtDefinitionen.get(0);
                    //schichtDefinitionVorhanden = true;
                } else {
                    // es gibt keinen oder mehrere Treffer
                    // es wird ein Dialog zur Auswahl der gewünschten Schichtdefinition bereitgestellt
                    Intent auswahlIntent = new Intent(
                            context, WidgetSchichtAuswahlActivity.class
                    );
                    // die ID des betreffenden Widgets übergeben
                    auswahlIntent.putExtra(
                            Widget.KEY_WIDGET_ID,
                            mStatus.mID
                    );
                    // die Art der Treffer übergeben -1= Schichterkennung aus 0= keiner; >0= mehrere
                    auswahlIntent.putExtra(KEY_DEFSCHICHT, schichtDefinitionen.size());

                    // die ID des Arbeitsplatzes übergeben
                    auswahlIntent.putExtra(ISettings.KEY_JOBID, mStatus.mJob.getId());

                    // die Option der erzwungenen Extraschicht übergeben
                    auswahlIntent.putExtra(KEY_ADDSCHICHT, mStatus.isOptionSet(WidgetStatus.OPT_EXTRASCHICHT));

                    String[] namen; //die Liste der Schichtnamen
                    long[] ids; // die Liste der IDs der Schichtdefinitionen
                    int i = 0;

                    if (schichtDefinitionen.isEmpty()) {
                        // es gibt keinen Treffer, es werden alle Schichten zur Auswahl gestellt
                        int menge = mStatus.mJob.getDefaultSchichten().getAktive().size();
                        namen = new String[menge];
                        ids = new long[menge];
                        for (SchichtDefault def : mStatus.mJob.getDefaultSchichten().getAktive()) {
                            namen[i] = def.getName();
                            ids[i] = def.getID();
                            i++;
                        }
                    } else {
                        // es gibt mehrere Treffer, es werden die Treffer zur Auswahl gestellt
                        namen = new String[schichtDefinitionen.size()];
                        ids = new long[schichtDefinitionen.size()];
                        for (SchichtDefault def : schichtDefinitionen) {
                            namen[i] = def.getName();
                            ids[i] = def.getID();
                            i++;
                        }
                    }
                    // die Liste der Schichtnamen übergeben
                    auswahlIntent.putExtra(
                            WidgetSchichtAuswahlActivity.LISTE_SCHICHT_NAMEN,
                            namen
                    );
                    // die Liste der Id's der Schichten übergeben
                    auswahlIntent.putExtra(
                            WidgetSchichtAuswahlActivity.LISTE_SCHICHT_IDS,
                            ids
                    );
                    // von, bis und pause in Minuten übergeben
                    auswahlIntent.putExtra(KEY_VON, mVon.getAlsMinuten());
                    auswahlIntent.putExtra(KEY_BIS, mBis.getAlsMinuten());
                    auswahlIntent.putExtra(KEY_PAUSE, mPause.getAlsMinuten());

                    auswahlIntent.setAction(OPEN_SCHICHTAUSWAHL);
                    auswahlIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    auswahlIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    context.startActivity(auswahlIntent);
                    return;
                }
            } else if (!mStatus.mJob.isTeilschicht() && mStatus.mJob.getAnzahlSchichten() > 1) {
                // die Schichterkennung ist aus und es gibt mehr als eine definierte Schicht
                // es wird ein Dialog zur Auswahl der gewünschten Schichtdefinition bereitgestellt
                Intent auswahlIntent = new Intent(
                        context, WidgetSchichtAuswahlActivity.class
                );
                // die ID des betreffenden Widgets übergeben
                auswahlIntent.putExtra(
                        Widget.KEY_WIDGET_ID,
                        mStatus.mID
                );
                // die Art der Treffer übergeben -1= keine Schichterkennung 0= keiner; >0= mehrere
                auswahlIntent.putExtra(KEY_DEFSCHICHT, -1);

                // die ID des Arbeitsplatzes übergeben
                auswahlIntent.putExtra(ISettings.KEY_JOBID, mStatus.mJob.getId());

                // die Option der erzwungenen Extraschicht übergeben
                auswahlIntent.putExtra(KEY_ADDSCHICHT, mStatus.isOptionSet(WidgetStatus.OPT_EXTRASCHICHT));

                int menge = mStatus.mJob.getDefaultSchichten().getAktive().size();
                String[] namen = new String[menge]; //die Liste der Schichtnamen
                long[] ids = new long[menge]; // die Liste der IDs der Schichtdefinitionen
                int i = 0;
                for (SchichtDefault def : mStatus.mJob.getDefaultSchichten().getAktive()) {
                    namen[i] = def.getName();
                    ids[i] = def.getID();
                    i++;
                }

                // die Liste der Schichtnamen übergeben
                auswahlIntent.putExtra(
                        WidgetSchichtAuswahlActivity.LISTE_SCHICHT_NAMEN,
                        namen
                );
                // die Liste der Id's der Schichten übergeben
                auswahlIntent.putExtra(
                        WidgetSchichtAuswahlActivity.LISTE_SCHICHT_IDS,
                        ids
                );
                // von, bis und pause in Minuten übergeben
                auswahlIntent.putExtra(KEY_VON, mVon.getAlsMinuten());
                auswahlIntent.putExtra(KEY_BIS, mBis.getAlsMinuten());
                auswahlIntent.putExtra(KEY_PAUSE, mPause.getAlsMinuten());

                auswahlIntent.setAction(OPEN_SCHICHTAUSWAHL);
                auswahlIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                auswahlIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                context.startActivity(auswahlIntent);
                return;
            }
            // die gestempelten Zeiten eintragen wenn keine Auswahl der Schichtdefinitonen
            // vorgenommen werden muss
            schichtEintragen(context, mStatus, defSchicht, mVon, mBis, mPause, mStatus.isOptionSet(WidgetStatus.OPT_EXTRASCHICHT));
        } else {
            // es wurde weniger als eine Minute gestempelt
            String mMeldung = ASettings.res.getString(R.string.widget_add_no_schicht);
            Toast toast = Toast.makeText(context, mMeldung, Toast.LENGTH_LONG);
            toast.show();

            // Widget zurück setzen
            mStatus.reset();
            mStatus.save(ASettings.mPreferenzen);
        }
    }

    /**
     *
     * @param stempelzeit Stempelzeit in Minuten
     * @param modus Rundungsmodus - aufrunden, abrunden, kaufmännisch runden
     * @param rundenMinuten Rundungsschritte in Minuten
     * @return die gerundete Stempelzeit in Minuten

    private static Uhrzeit runden(int stempelzeit, int modus, int rundenMinuten) {
        Uhrzeit ergebnis = new Uhrzeit(stempelzeit);

        if (modus != WidgetStatus.NICHTRUNDEN && rundenMinuten > 1) {
            // Anzahl Minuten von der gestempelten Zeit bis zur vorigen Schwelle
            int rStempelzeit = stempelzeit % rundenMinuten;
            if (rStempelzeit > 0) {
                if (modus == WidgetStatus.ABRUNDEN) {
                    ergebnis.sub(rStempelzeit);
                } else if (modus == WidgetStatus.AUFRUNDEN) {
                    ergebnis.add(rundenMinuten - rStempelzeit);
                } else if (modus == WidgetStatus.KAUFRUNDEN) {
                    // der Wert an dem auf- bzw. abgerundet wird
                    int rMinuten = Math.round((float) rundenMinuten / 2);
                    if (rStempelzeit >= rMinuten) {
                        ergebnis.add(rundenMinuten - rStempelzeit);
                    } else {
                        ergebnis.sub(rStempelzeit);
                    }
                }

                if (ergebnis.getAlsMinuten() < 0) {
                    ergebnis.set(0);
                }
            }
        }
        return ergebnis;
    }*/

    /**
     * versucht an Hand der gestempelten Zeiten eine passende definierte Schicht zu finden
     *
     * @param job der Arbeitsplatz zu dem das Widget gehört
     * @param von die Startzeit des Widgets
     * @param bis die Stopzeit des Widgets
     * @return die Liste erkannter Schichten
     */
    private static ArrayList<SchichtDefault> erkenneSchicht(Arbeitsplatz job, Uhrzeit von, Uhrzeit bis){
        ArrayList<SchichtDefault> schichtDefinitionen = new ArrayList<>();
        boolean erkannt = false;

        // die Liste der aktiven Schichtdefinitionen durchgehen
        // und alle Schichten mit passenden Startzeiten sammeln
        for (SchichtDefault defSchicht : job.getDefaultSchichten().getAktive()) {
            // erkannt wenn Startzeit +/- puffer bei def. Startzeit liegt und Endzeit nach def. Endzeit - puffer
            if(
                    von.getAlsMinuten() >= (defSchicht.getVon() - PUFFER)
                            && von.getAlsMinuten() <= (defSchicht.getVon() + PUFFER)
            ) {
                if(bis.getAlsMinuten() >= (defSchicht.getBis() - PUFFER)) {
                    schichtDefinitionen.add(defSchicht);
                    erkannt = true;
                }
            }

            // wenn keine passende Schicht an Hand der erweiterten Startzeit erkannt wurde
            if(!erkannt){
                // erkannt wenn Endzeit +/- puffer bei def. Endzeit liegt und Startzeitzeit vor def. Startzeit + puffer
                if(
                   bis.getAlsMinuten() >=  (defSchicht.getBis() - PUFFER)
                    && bis.getAlsMinuten() <= (defSchicht.getBis() + PUFFER)
                ){
                  if(von.getAlsMinuten() <= (defSchicht.getVon() + PUFFER)) {
                     schichtDefinitionen.add(defSchicht);
                  }
                }
            } else {
                // Erkennung zurück setzen
                erkannt = false;
            }
        }
        return schichtDefinitionen;
    }


   private static void schichtEintragen(
           Context context,
           WidgetStatus status, SchichtDefault defSchicht,
           Uhrzeit von, Uhrzeit bis, Uhrzeit pause, boolean addExtraSchicht
           ) {
       // den betreffenden Arbeitstag aus der Datenbank lesen oder einen neuen anlegen
       Arbeitstag mTag = new Arbeitstag(
               status.mTag.getCalendar(),
               status.mJob,
               status.mJob.getSollstundenTag(status.mTag),
               status.mJob.getSollstundenTagPauschal(
                       status.mTag.get(Calendar.YEAR), status.mTag.get(Calendar.MONTH)
               )
       );

       Arbeitsschicht aSchicht = null;

       if (!addExtraSchicht) {
           // wenn eine Defaultschicht vorhanden ist
           // dann die erste Wechselschicht überschreiben
           // oder die betreffende Teilschicht überschreiben
           //
           // wenn keine Defaultschicht vorhanden ist
           // die nächste leere Schicht zum eintragen finden
           // oder eine anhängen
           if (defSchicht != null) {
               // die korrekte Schicht zum überschreiben finden
               if (status.mJob.isTeilschicht()) {
                   for (Arbeitsschicht s : mTag.getSchichten()) {
                       if (s.getDefaultSchichtId() == defSchicht.getID()) {
                           aSchicht = s;
                           break;
                       }
                   }
               } else {
                   aSchicht = mTag.getSchicht(0);
               }
           } else {
               // die nächste freie Schicht finden
               for (Arbeitsschicht s : mTag.getSchichten()) {
                   if (s.getAbwesenheit().getKategorie() == Abwesenheit.KAT_KEINESCHICHT) {
                       aSchicht = s;
                       // wenn es eine Teilschicht ist, dann deren Schichtdefinition als defaultSchicht setzen
                       if(status.mJob.isTeilschicht()){
                           defSchicht = status.mJob.getDefaultSchichten().getVonId(aSchicht.getDefaultSchichtId());
                       }
                       break;
                   }
               }
           }
       }

       // wenn noch keine Schicht gefunden/angelegt wurde, eine am Ende der Liste einfügen
       if (aSchicht == null) {
           if (defSchicht != null) {
               mTag.addSchicht(-1, defSchicht);
           } else {
               mTag.addSchicht(-1, ASettings.res.getString(
                       R.string.schicht_nr, (mTag.getSchichtAnzahl() + 1)
               ));
           }
           aSchicht = mTag.getSchicht(mTag.getSchichtAnzahl() - 1);
       }

       // Stempelwerte eintragen
       if (defSchicht != null) {
           /*if(!status.mJob.isTeilschicht()) {
               aSchicht.getZusatzfelder(IZusatzfeld.TEXT_VOLL).setListenWerte(defSchicht.getZusatzfelder());
               aSchicht.setEinsatzort(status.mJob.getEinsatzortListe().getOrt(defSchicht.getEinsatzOrt()));
           }*/
           aSchicht.setAll(
                   status.mJob.getAbwesenheiten().get(Abwesenheit.ARBEITSZEIT),
                   status.isOptionSet(WidgetStatus.OPT_SET_VON_REAL) ? von.getAlsMinuten() : defSchicht.getVon(),
                   status.isOptionSet(WidgetStatus.OPT_SET_BIS_REAL) ? bis.getAlsMinuten() : defSchicht.getBis(),
                   status.isOptionSet(WidgetStatus.OPT_SET_PAUSE_REAL) ? pause.getAlsMinuten() : defSchicht.getPause(),
                   defSchicht,
                   status.mJob.isTeilschicht() ? null : defSchicht.getName()
           );
       } else {
           aSchicht.setAll(
                   status.mJob.getAbwesenheiten().get(Abwesenheit.ARBEITSZEIT),
                   von.getAlsMinuten(),
                   bis.getAlsMinuten(),
                   pause.getAlsMinuten(),
                   null,
                   ASettings.res.getString(R.string.stempelzeit)
           );
       }

       // den betreffenden Monat aktuallisieren
       Arbeitsmonat mMonat = new Arbeitsmonat(
               status.mJob,
               mTag.getKalender().get(Calendar.YEAR),
               mTag.getKalender().get(Calendar.MONTH),
               true,
               true);
       mMonat.updateSaldo(true);

       String mMeldung = ASettings.res.getString(R.string.widget_add_schicht);
       Toast toast = Toast.makeText(context, mMeldung, Toast.LENGTH_LONG);
       toast.show();

       if (status.isOptionSet(WidgetStatus.OPT_TAG_OEFFEN)) {
           Intent mMainIntent = new Intent();
           mMainIntent.setClass(context, MainActivity.class);
           mMainIntent.putExtra(ISettings.KEY_ANZEIGE_VIEW, ISettings.VIEW_TAG);
           mMainIntent.putExtra(ISettings.KEY_ANZEIGE_DATUM, mTag.getKalender().getTimeInMillis());
           mMainIntent.putExtra(ISettings.KEY_JOBID, status.mJob.getId());
           mMainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
           mMainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
           context.startActivity(mMainIntent);
       }

       // Widget zurück setzen
       status.reset();
       status.save(ASettings.mPreferenzen);
   }


    protected static PendingIntent getPendingSelfIntent(Context context, String action, int widgetID) {
        Intent intent = new Intent(context, Widget.class);
        intent.putExtra(Widget.KEY_WIDGET_ID, widgetID);
        intent.setAction(action);
        return PendingIntent.getBroadcast(
                context,
                widgetID,
                intent,
                (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? PendingIntent.FLAG_IMMUTABLE : 0);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        // wenn noch kein Update Alarm gesetzt wurde,
        // bzw. dieser nach Reboot oder Appupdate gelöscht wurde,
        // einen neuen setzen
        if (mAlarmManager == null) {
            onEnabled(context);
        }

        // Alle Widgets neu zeichnen
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        // Ein Widget wurde gelöscht,
        // dessen Einstellungen und Daten werden auch gelöscht
        for (int appWidgetId : appWidgetIds) {
            WidgetConfigureActivity.deletePref(context, appWidgetId);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // das erste Widget wurde angelegt,
        // einen Alarm setzen, der das Update der Widgets triggert
        /*Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.MILLISECOND, (int)(60000 - System.currentTimeMillis() % 60000));*/
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        mAlarmManager.setInexactRepeating(
                AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis() + (60000 - System.currentTimeMillis() % 60000),
                60000,
                getPendingSelfIntent(context, UPDATE, 0)
        );
    }

    @Override
    public void onDisabled(Context context) {
        // das letzte Widget wurde gelöscht,
        // also wird auch der Alarm gelöscht, der das Update der Widgets triggert
        if (mAlarmManager != null) {
            mAlarmManager.cancel(getPendingSelfIntent(context, UPDATE, 0));
            mAlarmManager = null;
        }
    }

    /*public static void updateAllWidgets(Context context) {
        // neu Zeichnen der Stempeluhren anstoßen
        AppWidgetManager wm = AppWidgetManager.getInstance(context);
        ComponentName cn = new ComponentName(context.getPackageName(), Stempeluhr.class.getName());
        int[] wi = wm.getAppWidgetIds(cn);
        for (int w : wi) {
            updateAppWidget(context, wm, w);
        }

        // Timer neu setzen
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.SECOND, 0);
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        mAlarmManager.setInexactRepeating(
                AlarmManager.RTC_WAKEUP,
                cal.getTimeInMillis(),
                60000,
                getPendingSelfIntent(context, UPDATE, 0)
        );
    }*/
}

