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

import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

import askanimus.arbeitszeiterfassung2.abwesenheiten.Abwesenheit;
import askanimus.arbeitszeiterfassung2.arbeitsmonat.Arbeitsmonat;
import askanimus.arbeitszeiterfassung2.arbeitstag.Arbeitstag;
import askanimus.arbeitszeiterfassung2.arbeitswoche.Arbeitswoche;
import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.setup.ASettings;

/**
 * @author askanimus@gmail.com on 19.08.15.
 */
public class ChartsFragment extends Fragment {
    private static final String ARG_DATUM = "datum";
    private static final String ARG_PERIODE = "periode";
    private static final String ARG_TYP = "typ";


    public static final int TYP_ABWESENHEITEN = 0;
    protected static final int TYP_EINSATZORTE = 1;
    protected static final int TYP_SCHICHTEN = 2;


    protected static final int PERIODE_FREI = 0;
    protected static final int PERIODE_TAG = 1;
    public static final int PERIODE_WOCHE = 2;
    public static final int PERIODE_MONAT = 3;
    protected static final int PERIODE_JAHR = 4;
    protected static final int PERIODE_ALL = 5;

    private Context mContext;

    /*
     * Neue Instanz anlegen
     */
    public static ChartsFragment newInstance(long dStart, int dPeriode, int dTyp){
        ChartsFragment fragment =  new ChartsFragment();
        Bundle bundle = new Bundle();

        bundle.putLong(ARG_DATUM, dStart);
        bundle.putInt(ARG_PERIODE, dPeriode);
        bundle.putInt(ARG_TYP, dTyp);
        fragment.setArguments(bundle);

        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        mContext = getContext();
        return inflater.inflate(R.layout.fragment_charts, container, false);
    }

    @Override
    public void onResume() {
        super.onResume();

        ASettings.init(mContext, this::resume);
    }

    private void resume(){
        View mView = getView();

        Bundle mArgs = getArguments();
        Datum datumStart;
        int diagrammPeriode;
        int diagrammTyp;
        if (mArgs != null){
            datumStart = new Datum(mArgs.getLong(ARG_DATUM), ASettings.aktJob.getWochenbeginn());
            diagrammPeriode = mArgs.getInt(ARG_PERIODE);
            //diagrammTyp = mArgs.getInt(ARG_TYP);
        } else {
            datumStart = new Datum(ASettings.aktDatum);
            diagrammPeriode = PERIODE_MONAT;
            //diagrammTyp = TYP_ABWESENHEITEN;
        }

        if(mView != null) {
            CombinedChart chart_combined = mView.findViewById(R.id.C_combined);
            PieChart chart_pie = mView.findViewById(R.id.C_pie);
            TextView wPeriode = mView.findViewById(R.id.C_wert_links);
            TextView wDatum = mView.findViewById(R.id.C_wert_rechts);

            switch (diagrammPeriode) {
                case PERIODE_TAG:
                    wPeriode.setText(getText(R.string.tag));
                    wDatum.setText(datumStart.getString_Datum(mContext));
                    break;
                case PERIODE_WOCHE:
                    Arbeitswoche mWoche = new Arbeitswoche(datumStart.getTimeInMillis(), ASettings.aktJob);
                    // die Wochennumer anzeigen
                    wPeriode.setText(getString(R.string.woche_nummer, mWoche.getNummer()));
                    // das Datum der Woche anzeigen
                    wDatum.setText(
                            mWoche.getDatumErsterTag().getString_Datum_Bereich(
                                    mContext,
                                    0,
                                    mWoche.getTagzahl() - 1,
                                    Calendar.DAY_OF_MONTH
                            )
                    );

                    // Kreisdiagramm
                    // die Daten
                    chart_pie.setData(Abwesenheiten(mWoche));
                    // der Titel
                    chart_pie.getDescription().setText(getString(R.string.summe_tage));
                    chart_pie.getDescription().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_pie.getDescription().setTextSize(12f);
                    // die Legende
                    chart_pie.getLegend().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    // die Bezeichner im Diagramm
                    chart_pie.setDrawEntryLabels(false);
                    chart_pie.setEntryLabelColor(Color.DKGRAY);
                    // das Kreisinnere
                    chart_pie.setHoleColor(Color.TRANSPARENT);
                    chart_pie.setCenterTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_pie.setCenterText(getString(
                            R.string.pie_inner_tage,
                            mWoche.getTagzahl(),
                            ASettings.zahlenformat.format(
                                    mWoche.getSummeArbeitsTage(true)
                            )));
                    // die Animation
                    chart_pie.animateY(1000, Easing.EaseInOutCirc);

                    //Kombiniertes Bar- und Linediagramm
                    chart_combined.setData(
                            Soll_Ist_Saldo(
                                    mWoche.getTagListe(),
                                    0)
                    );
                    chart_combined.getDescription().setEnabled(false);
                    chart_combined.getLegend().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getXAxis().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getXAxis().setLabelCount(mWoche.getTagzahl());
                    chart_combined.getAxisLeft().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getAxisRight().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.animateXY(
                            1000,
                            1000,
                            Easing.EaseInOutExpo,
                            Easing.EaseInOutBounce
                    );
                    break;
                case PERIODE_MONAT:
                    Arbeitsmonat mMonat = new Arbeitsmonat(
                            ASettings.aktJob,
                            datumStart.get(Calendar.YEAR),
                            datumStart.get(Calendar.MONTH),
                            true, false);

                wPeriode.setText(datumStart.getString_Monat_Jahr(ASettings.aktJob.getMonatsbeginn(),false));

                    // Datumsbereich des Monats anzeigen
                    wDatum.setText(
                            datumStart.getString_Datum_Bereich(
                                    mContext,
                                    ASettings.aktJob.getMonatsbeginn(),
                                    -1,
                                    Calendar.DAY_OF_MONTH
                            )
                    );

                    // Kreisdiagramm
                    // die Daten
                    chart_pie.setData(Abwesenheiten(mMonat));
                    // der Titel
                    chart_pie.getDescription().setText(getString(R.string.summe_tage));
                    chart_pie.getDescription().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_pie.getDescription().setTextSize(12f);
                    // die Legende
                    chart_pie.getLegend().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    // die Bezeichner im Diagramm
                    chart_pie.setDrawEntryLabels(false);
                    chart_pie.setEntryLabelColor(Color.DKGRAY);
                    // das Kreisinnere
                    chart_pie.setHoleColor(Color.TRANSPARENT);
                    chart_pie.setCenterTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_pie.setCenterText(getString(
                            R.string.pie_inner_tage,
                            mMonat.getTagListe().size(),
                            ASettings.zahlenformat.format(
                                    mMonat.getSollArbeitsTage(true)
                            )));
                    // die Animation
                    chart_pie.animateY(1000, Easing.EaseInOutCirc);
                    //Kombiniertes Bar- und Linediagramm
                    chart_combined.setData(
                            Soll_Ist_Saldo(
                                    mMonat.getTagListe(),
                                    mMonat.getSaldoVormonat())
                    );
                    chart_combined.getDescription().setEnabled(false);
                    chart_combined.getLegend().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getXAxis().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getXAxis().setLabelCount(mMonat.getTagZahl());
                    chart_combined.getAxisLeft().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.getAxisRight().setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
                    chart_combined.animateXY(
                            1000,
                            1000,
                            Easing.EaseInOutExpo,
                            Easing.EaseInOutBounce
                    );
                    break;
                case PERIODE_JAHR:
                    wPeriode.setText(getText(R.string.jahr));
                    break;
                case PERIODE_ALL:
                    wPeriode.setText(getText(R.string.zeitraum));
                    break;
                default:
            }
        }

    }

    //
    // Kreisdiagramme
    //
    private PieData Abwesenheiten(Arbeitsmonat monat){
        List<PieEntry> abwesenheiten = new ArrayList<>();
        List<Integer> farben = new ArrayList<>();

        Abwesenheit abwesenheit;
        float t;
        Random rnd = new Random();
        for(int a = 0; a< ASettings.aktJob.getAbwesenheiten().sizeAktive(); a++) {
            abwesenheit = ASettings.aktJob.getAbwesenheiten().getAktive(a);
            t = monat.getSummeAlternativTage(abwesenheit.getID());
            if (t > 0) {
                abwesenheiten.add(new PieEntry(t, abwesenheit.getName()));
                farben.add(
                        Color.argb(
                                255,
                                rnd.nextInt(128) + 128,
                                rnd.nextInt(128) + 128,
                                rnd.nextInt(128) + 128)
                );
            }
        }

        PieDataSet pieDataset = new PieDataSet(abwesenheiten, "");
        pieDataset.setColors(farben);
        pieDataset.setSelectionShift(10f);
        pieDataset.setSliceSpace(2f);
        pieDataset.setValueTextSize(12f);
        pieDataset.setValueTextColor(Color.DKGRAY);

        return new PieData(pieDataset);
    }

    private PieData Abwesenheiten(Arbeitswoche woche){
        List<PieEntry> abwesenheiten = new ArrayList<>();
        List<Integer> farben = new ArrayList<>();

        Abwesenheit abwesenheit;
        float t;
        Random rnd = new Random();
        for(int a = 0; a< ASettings.aktJob.getAbwesenheiten().sizeAktive(); a++) {
            abwesenheit = ASettings.aktJob.getAbwesenheiten().getAktive(a);
            t = woche.getSummeAlternativTage(abwesenheit.getID());
            if(t > 0){
                abwesenheiten.add(new PieEntry(t, abwesenheit.getName()));
                if(ASettings.isThemaDunkel)
                    farben.add(Color.argb(
                            255,
                            rnd.nextInt(128)+128,
                            rnd.nextInt(128) + 128,
                            rnd.nextInt(128)+128
                    ));
                else
                    farben.add(Color.argb(
                            255,
                            rnd.nextInt(128),
                            rnd.nextInt(128),
                            rnd.nextInt(128)
                    ));
            }
        }

        PieDataSet pieDataset = new PieDataSet(abwesenheiten, "");
        pieDataset.setColors(farben);
        pieDataset.setSelectionShift(10f);
        pieDataset.setSliceSpace(2f);
        pieDataset.setValueTextSize(12f);
        pieDataset.setValueTextColor(Color.DKGRAY);

        return new PieData(pieDataset);
    }

    //
    // Kombinierte Balken- und Liniendiagramme
    //
    private CombinedData Soll_Ist_Saldo(List<Arbeitstag> tagList, int saldoVor){
        List<BarEntry> stunden = new ArrayList<>();
        List<Entry> saldi = new ArrayList<>();

        int tag = 0;
        Uhrzeit ist = new Uhrzeit(0);
        Uhrzeit diff = new Uhrzeit(0);
        Uhrzeit saldo = new Uhrzeit(saldoVor);
        // den Saldo des Vormontas als Startwert eintragen
        saldi.add(new Entry(tag, saldo.getAlsDezimalZeit()));
        stunden.add(new BarEntry(tag, new float[]{0f, 0f, 0f}));
        for (Arbeitstag aTag : tagList) {
            //tag = aTag.getTagimMonat();
            tag += 1;
            ist.set(aTag.getTagNetto());
            diff.set(aTag.getTagNetto());
            diff.sub(aTag.getTagSollNetto());
            saldo.add(diff.getAlsMinuten());
            if (diff.getAlsMinuten() > 0) {
                ist.sub(diff.getAlsMinuten());
                stunden.add(new BarEntry(
                        tag,
                        new float[]{0f, ist.getAlsDezimalZeit(), diff.getAlsDezimalZeit()}
                ));
            } else if (diff.getAlsMinuten() < 0) {
                stunden.add(new BarEntry(
                        tag,
                        new float[]{diff.getAlsDezimalZeit(), ist.getAlsDezimalZeit(), 0f}
                ));
            } else {
                stunden.add(new BarEntry(
                        tag,
                        new float[]{0f, ist.getAlsDezimalZeit(), 0f}
                ));
            }
            saldi.add(new Entry(tag, saldo.getAlsDezimalZeit()));
        }

        // Basis und Einstellungen Balkendiagramm
        BarDataSet bardataSet = new BarDataSet(stunden, "");
        bardataSet.setStackLabels(new String[]{getString(R.string.fehlstunden), getString(R.string.arbeitszeit), getString(R.string.ueberstunden)});
        bardataSet.setColors(
                new int[]{R.color.bpRed, R.color.bpDarker_blue, R.color.box_gruen},
                mContext
        );
        BarData barData = new BarData(bardataSet);
        barData.setDrawValues(false);

        // Basis und Einstellungen Liniendiagramm
        LineDataSet linedataset = new LineDataSet(saldi, getString(R.string.saldo));
        linedataset.setColors(Color.YELLOW);
        linedataset.setLineWidth(3f);
        linedataset.setDrawCircles(false);
        linedataset.setMode(LineDataSet.Mode.LINEAR);
        LineData lineData = new LineData(linedataset);
        lineData.setDrawValues(false);

        // Basis des kombinierten Diagramms
        CombinedData CombinedData = new CombinedData();
        CombinedData.setData(barData);
        CombinedData.setData(lineData);

        return (CombinedData);
    }

}
