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

import android.content.SharedPreferences;
import android.net.Uri;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.setup.ISettings;

/**
 * @author askanimus@gmail.com on 05.07.16.
 */
public class WidgetStatus {
    // wird nicht mehr verwendet
    @Deprecated
    protected static final String PREFS_NAME = "askanimus.arbeitszeiterfassung2.widget.Stempeluhr";
    public static final String KEY_JOB = "job_";
    protected static final String KEY_STATUS = "status_";
    protected static final String KEY_DATUM = "datum_";
    protected static final String KEY_ZEIT = "zeit_";
    protected static final String KEY_PAUSE_BEGINN_OLD = "pause_";
    protected static final String KEY_PAUSE_BEGINN = "_pause_";
    protected static final String KEY_PAUSE_LAENGE_OLD = "pauselaenge_";
    protected static final String KEY_PAUSE_LAENGE = "_pauselaenge_";
    protected static final String KEY_PAUSESUMME = "pausesumme_";
    protected static final String KEY_TIMER_MIN = "timermin_";
    protected static final String KEY_TIMER_TEXT = "timertext_";
    protected static final String KEY_TIMER_SOUND = "timersound_";
    protected static final String KEY_NEUSTART = "neustart_";
    // alte Rundungsoptionen für alle Werte gemeinsam bis Version 2.07.008
    protected static final String KEY_OPT_RUNDEN = "opt_runden_";
    protected static final String KEY_OPT_RUNDEN_MINUTEN = "opt_runden_minuten_";
    // neue Rundungsoptionen für jeden Wert separat ab Version 2.08.000
    protected static final String KEY_OPT_RUNDEN_VON = "opt_rundenVon_";
    protected static final String KEY_OPT_RUNDEN_VON_MINUTEN = "opt_rundenMinutenVon_";
    protected static final String KEY_OPT_RUNDEN_BIS = "opt_rundenBis_";
    protected static final String KEY_OPT_RUNDEN_BIS_MINUTEN = "opt_rundenMinutenBIS_";
    protected static final String KEY_OPT_RUNDEN_PAUSE = "opt_rundenPause_";
    protected static final String KEY_OPT_RUNDEN_PAUSE_MINUTEN = "opt_rundenMinutenPause_";
    
    protected static final String KEY_OPT_OPTIONEN = "opt_optionen_";
    //
    // Zustände des Stempeluhrwidgets
    //
    public static final int WIDGET_STATUS_NEU = 0;
    public static final int WIDGET_STATUS_RUN = 1;
    public static final int WIDGET_STATUS_PAUSE = 3;
    public static final int WIDGET_STATUS_STOP = 4;

    //
    // Rundungseinstellungen
    //
    protected final static int NICHTRUNDEN = 0;
    protected final static int AUFRUNDEN = 1;
    protected final static int ABRUNDEN = 2;
    protected final static int KAUFRUNDEN = 3;

    //
    // Widgetoptionen
    //
    final static int OPT_TAG_OEFFEN = 1;
    final static int OPT_ERKENNE_SCHICHT = 2;
    final static int OPT_SET_VON_REAL = 4;
    final static int OPT_SET_BIS_REAL = 8;
    final static int OPT_SET_PAUSE_REAL = 16;
    final static int OPT_EXTRASCHICHT = 32;
    // final static int OPT_FIXSCHICHT = 64;

    //
    // Widget Werte
    //
    protected int mID;
    protected Arbeitsplatz mJob;

    protected Datum mTag;
    protected Uhrzeit mBeginn;
    protected boolean mNeustart;
    protected ArrayList <Uhrzeit> mPauseBeginn;
    protected ArrayList <Uhrzeit> mPauseLaenge;
    protected Uhrzeit mPauseSumme;
    //protected Abwesenheit mAbwesenheit;
    //protected long mSchichtDefinition;
    protected int mStatus;

    //
    // die Optionen
    //
    //int mRunden = NICHTRUNDEN;
    //int mRunden_minuten = 1;
    
    protected int mRundenVon = NICHTRUNDEN;
    protected int mRundenVon_minuten = 1;
    public int mRundenBis = NICHTRUNDEN;
    protected int mRundenBis_minuten = 1;
    protected int mRundenPause = NICHTRUNDEN;
    public int mRundenPause_minuten = 1;

    int mOptionen = 28; //  0011100;

    ArrayList<TimerEintrag> mTimerListe;
    String mZusatz ="";

    public WidgetStatus(Arbeitsplatz job, int id, String zusatz) {
        mJob = job;
        mID = id;
        mZusatz = zusatz;

        mTag = new Datum(new Date(), mJob.getWochenbeginn());
        mBeginn = new Uhrzeit(0);
        mPauseBeginn = new ArrayList<>();//new Uhrzeit(0);
        mPauseLaenge = new ArrayList<>();
        mPauseSumme = new Uhrzeit(0);
        //mAbwesenheit = mJob.getAbwesenheiten().get(Abwesenheit.ARBEITSZEIT);
        // mSchichtDefinition = 0;
        mStatus = WIDGET_STATUS_NEU;
        mTimerListe = new ArrayList<>();
    }

    /**
     * gibt den Wert der gewünschten Option zurück
     * @param option die gesuchte Option
     * @return true oder false
     */
    Boolean isOptionSet(int option){
        return (mOptionen & option) != 0;
    }

    public int getStatus(){
        return mStatus;
    }

    /**
     * setzen einer Option
     * @param option die zu setztende Option
     * @param wert true oder false
     */
    void setOption(int option, Boolean wert){
        if(wert)
            mOptionen = mOptionen | option;
        else
            mOptionen = mOptionen & ~option;

    }


    public void start() {
        mBeginn.set();
        mTag.set(new Date());
        //mAbwesenheit = Abwesenheit.ARBEITSZEIT;
        mStatus = WIDGET_STATUS_RUN;
        mNeustart = true;
    }

    public void stop(){
        if (mStatus == WIDGET_STATUS_PAUSE){
            stopPause();
        }
        mStatus = WidgetStatus.WIDGET_STATUS_STOP;
    }

    public void reset(){
        mBeginn.set(0);
        mPauseSumme.set(0);
        mPauseBeginn = new ArrayList<>();
        mPauseLaenge = new ArrayList<>();

        mStatus = WIDGET_STATUS_NEU;
    }

    TimerEintrag getNextTimer(int aktMinten){
        if (mTimerListe.isEmpty()) {
            return  null;
        } else {
            int m = aktMinten - mBeginn.getAlsMinuten();
            for (TimerEintrag te : mTimerListe) {
                if (te.minuten > m) {
                    return te;
                }
            }
            return  null;
        }
    }

    /*
     * Pausenmanagement
     */
    public void startPause(){
        mPauseBeginn.add(new Uhrzeit());
        mPauseLaenge.add(new Uhrzeit(0));
        mStatus = WIDGET_STATUS_PAUSE;
    }

    public void stopPause(){
        Uhrzeit t = new Uhrzeit();
        Uhrzeit laenge = getAktPauseLaenge();
        if(laenge != null){
            int p = t.getAlsMinuten() - getAktPauseBeginn();
            if (p < 0){
                p += ISettings.Minuten_TAG;
            }
            laenge.set(p);
        }
        mStatus = WIDGET_STATUS_RUN;
        updatePauseSumme();
    }

    public void updatePause(int minuten){
        Uhrzeit l = getAktPauseLaenge();
        if(l != null){
            int laenge = minuten - getAktPauseBeginn();
            if (laenge < 0){
                laenge += ISettings.Minuten_TAG;
            }
            l.set(laenge);

            updatePauseSumme();
        }
    }

    protected void updatePauseSumme(){
        mPauseSumme.set(0);
        for (Uhrzeit p : mPauseLaenge) {
            mPauseSumme.add(p.getAlsMinuten());
        }
    }

    int getAktPauseBeginn(){
        int s = mPauseBeginn.size();
        if(s > 0) {
            return mPauseBeginn.get(s - 1).getAlsMinuten();
        }
        return 0;
    }

    Uhrzeit getAktPauseLaenge(){
        int s = mPauseLaenge.size();
        if(s > 0) {
            return mPauseLaenge.get(s - 1);
        }
        return null;
    }

    /**
     * @param stempelzeit   Stempelzeit in Minuten
     * @param modus         Rundungsmodus - aufrunden, abrunden, kaufmännisch runden
     * @param rundenMinuten Rundungsschritte in Minuten
     * @return die gerundete Stempelzeit in Minuten
     */
    public Uhrzeit runden(int stempelzeit, int modus, int rundenMinuten) {
        Uhrzeit ergebnis = new Uhrzeit(stempelzeit);

        if (modus != NICHTRUNDEN && rundenMinuten > 1) {
            // Anzahl Minuten von der gestempelten Zeit bis zur vorigen Schwelle
            int rStempelzeit = stempelzeit % rundenMinuten;
            if (rStempelzeit > 0) {
                if (modus == ABRUNDEN) {
                    ergebnis.sub(rStempelzeit);
                } else if (modus == AUFRUNDEN) {
                    ergebnis.add(rundenMinuten - rStempelzeit);
                } else if (modus == 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;
    }


    public void load(SharedPreferences prefs) {
        String id = mZusatz + mID;
        mStatus = prefs.getInt(KEY_STATUS + id, WidgetStatus.WIDGET_STATUS_NEU);
        mTag = new Datum(prefs.getLong(KEY_DATUM + id, new Date().getTime()), mJob.getWochenbeginn());
        mBeginn.set(prefs.getInt(KEY_ZEIT + id,
                (mTag.get(Calendar.HOUR_OF_DAY) * 60) + mTag.get(Calendar.MINUTE)));
        int i = 0;
        Uhrzeit z;
        if (prefs.contains(KEY_PAUSE_BEGINN_OLD + id)) {
            // Nach Update der App alte Pauseneinstellungen lesen und löschen
            z = new Uhrzeit(prefs.getInt(KEY_PAUSE_BEGINN_OLD + id, 0));
            mPauseBeginn.add(z);
            z = new Uhrzeit(prefs.getInt(KEY_PAUSE_LAENGE_OLD + id, 0));
            mPauseLaenge.add(z);

            prefs.edit().remove(KEY_PAUSE_BEGINN_OLD + id).apply();
            prefs.edit().remove(KEY_PAUSE_LAENGE_OLD + id).apply();
        } else {
            while (prefs.contains(i + KEY_PAUSE_BEGINN + id)) {
                z = new Uhrzeit(prefs.getInt(i + KEY_PAUSE_BEGINN + id, 0));
                mPauseBeginn.add(z);
                z = new Uhrzeit(prefs.getInt(i + KEY_PAUSE_LAENGE + id, 0));
                mPauseLaenge.add(z);
                i++;
            }
        }
        mPauseSumme.set(prefs.getInt(KEY_PAUSESUMME + id, 0));

        i = 0;
        while (prefs.contains(i + KEY_TIMER_MIN + id)) {
            TimerEintrag e = new TimerEintrag();
            e.minuten = prefs.getInt(i + KEY_TIMER_MIN + id, 0);
            e.meldung = prefs.getString(i + KEY_TIMER_TEXT + id, "");
            String s = prefs.getString(i + KEY_TIMER_SOUND + id, "");
            if (!s.isEmpty()){
                e.alarmton = Uri.parse(s);
            } else {
                e.alarmton = null;
            }
            mTimerListe.add(e);
            i++;
        }

        mOptionen = prefs.getInt(KEY_OPT_OPTIONEN + id, mOptionen);
        // ab Versin 2.08.000 werden alle Stempelzeiten individuell gerundet
        int runden = prefs.getInt(KEY_OPT_RUNDEN + id, NICHTRUNDEN);
        int runden_minuten = prefs.getInt(KEY_OPT_RUNDEN_MINUTEN + id, 1);
        mRundenVon = prefs.getInt(KEY_OPT_RUNDEN_VON + id, runden);
        mRundenVon_minuten = prefs.getInt(KEY_OPT_RUNDEN_VON_MINUTEN + id, runden_minuten);
        mRundenBis = prefs.getInt(KEY_OPT_RUNDEN_BIS + id, runden);
        mRundenBis_minuten = prefs.getInt(KEY_OPT_RUNDEN_BIS_MINUTEN + id, runden_minuten);
        mRundenPause = prefs.getInt(KEY_OPT_RUNDEN_PAUSE + id, runden);
        mRundenPause_minuten = prefs.getInt(KEY_OPT_RUNDEN_PAUSE_MINUTEN + id, runden_minuten);
        
        mNeustart = prefs.getBoolean(KEY_NEUSTART + id, false);
    }
    
    protected void save(SharedPreferences prefs) {
        SharedPreferences.Editor mEditor = prefs.edit();
        String id = mZusatz + mID;

        mEditor.putLong(KEY_JOB + id, mJob.getId());
        mEditor.putInt(KEY_STATUS + id, mStatus);
        mEditor.putLong(KEY_DATUM + id, mTag.getTimeInMillis());
        mEditor.putInt(KEY_ZEIT + id, mBeginn.getAlsMinuten());
        int i = 0;
        while (i < mPauseBeginn.size()) {
            mEditor.putInt(i + KEY_PAUSE_BEGINN + id, mPauseBeginn.get(i).getAlsMinuten());
            mEditor.putInt(i + KEY_PAUSE_LAENGE + id, mPauseLaenge.get(i).getAlsMinuten());
            i++;
        }
        while (prefs.contains(i + KEY_PAUSE_BEGINN + id)) {
            mEditor.remove(i + KEY_PAUSE_BEGINN + id);
            mEditor.remove(i + KEY_PAUSE_LAENGE + id);
            i++;
        }
        mEditor.putInt(KEY_PAUSESUMME + id, mPauseSumme.getAlsMinuten());

        i = 0;
        for (TimerEintrag eintrag : mTimerListe) {
            mEditor.putInt(i + KEY_TIMER_MIN + id, eintrag.minuten);
            mEditor.putString(i + KEY_TIMER_TEXT + id, eintrag.meldung);
            if(eintrag.alarmton != null) {
                mEditor.putString(i + KEY_TIMER_SOUND + id, eintrag.alarmton.toString());
            }
            i++;
        }
        while (prefs.contains(i + KEY_TIMER_MIN + id)) {
            mEditor.remove(i + KEY_TIMER_MIN + id);
            mEditor.remove(i + KEY_TIMER_TEXT + id);
            mEditor.remove(i + KEY_TIMER_SOUND + id);
            i++;
        }

        mEditor.putInt(KEY_OPT_OPTIONEN + id, mOptionen);
        //mEditor.putInt(KEY_OPT_RUNDEN + id, mRunden);
        //mEditor.putInt(KEY_OPT_RUNDEN_MINUTEN + id, mRunden_minuten);
        mEditor.putInt(KEY_OPT_RUNDEN_VON + id, mRundenVon);
        mEditor.putInt(KEY_OPT_RUNDEN_VON_MINUTEN + id, mRundenVon_minuten);
        mEditor.putInt(KEY_OPT_RUNDEN_BIS + id, mRundenBis);
        mEditor.putInt(KEY_OPT_RUNDEN_BIS_MINUTEN + id, mRundenBis_minuten);
        mEditor.putInt(KEY_OPT_RUNDEN_PAUSE + id, mRundenPause);
        mEditor.putInt(KEY_OPT_RUNDEN_PAUSE_MINUTEN + id, mRundenPause_minuten);
        mEditor.putBoolean(KEY_NEUSTART + id, mNeustart);
        //mEditor.putLong(KEY_FIXSCHICHT + id, mSchichtDefinition);

        mEditor.apply();
    }


    /*protected void delete(SharedPreferences prefs, int id) {
        SharedPreferences.Editor mPrefs = prefs.edit();
        mPrefs.remove(KEY_JOB + id);
        mPrefs.remove(KEY_STATUS + id);
        mPrefs.remove(KEY_DATUM + id);
        mPrefs.remove(KEY_ZEIT + id);
        mPrefs.remove(KEY_PAUSE_BEGINN + id);
        mPrefs.remove(KEY_PAUSESUMME + id);
        mPrefs.remove(KEY_OPT_OPTIONEN + id);
        mPrefs.remove(KEY_OPT_RUNDEN + id);
        mPrefs.remove(KEY_OPT_RUNDEN_MINUTEN + id);
        mPrefs.remove(KEY_OPT_RUNDEN_VON + id);
        mPrefs.remove(KEY_OPT_RUNDEN_VON_MINUTEN + id);
        mPrefs.remove(KEY_OPT_RUNDEN_BIS + id);
        mPrefs.remove(KEY_OPT_RUNDEN_BIS_MINUTEN + id);
        mPrefs.remove(KEY_OPT_RUNDEN_PAUSE + id);
        mPrefs.remove(KEY_OPT_RUNDEN_PAUSE_MINUTEN + id);
        // mPrefs.remove(KEY_FIXSCHICHT + id);

        int i = 0;
        while (prefs.contains(i + KEY_PAUSE_BEGINN + id)) {
            mPrefs.remove(i + KEY_PAUSE_BEGINN + id);
            mPrefs.remove(i + KEY_PAUSE_LAENGE + id);
            i++;
        }

        i = 0;
        while (prefs.contains(i + KEY_TIMER_MIN + id)) {
            mPrefs.remove(i + KEY_TIMER_MIN + id);
            mPrefs.remove(i + KEY_TIMER_TEXT + id);
            mPrefs.remove(i + KEY_TIMER_SOUND + id);
            i++;
        }
        mPrefs.apply();
    }*/

    /*
     * Innere Klasse für eine Liste von Timern, die als Pausenerinnerung o.ä dienen
     */
    static class TimerEintrag {
        int minuten;        // Anzahl Minuten vom Start der Zeiterfassung des Widgets beginnend
        String meldung;     // Text der beim Erreichen angezeigt werden soll
        Uri alarmton;       // der Sound der asugegeben werden soll
    }
}
