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

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;

import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.databinding.ItemZusatzfeldDefinitionBinding;
import askanimus.arbeitszeiterfassung2.datenbank.DatenbankHelper;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;

public class ZusatzWertAuswahlListe {
    private final ArrayList<zusatzWertAuswahlItem> mAuswahlListe;
    private static ZusatzfeldDefinition zusatzfeldDefinition;
    private int summeSelectedItems;
    private Arbeitsplatz mArbeitsplatz;

    // erstellt die Auswahlliste eines Zusatzwertes
    @SuppressLint("Range")
    public ZusatzWertAuswahlListe(IZusatzfeld zusatzfeld, Arbeitsplatz arbeitsplatz) {
        mArbeitsplatz = arbeitsplatz;
        mAuswahlListe = new ArrayList<>();
        zusatzfeldDefinition = mArbeitsplatz.getZusatzDefinition(zusatzfeld.getDefinitionID());
        if(zusatzfeldDefinition != null) {
            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getReadableDatabase();

            final String SQL_READ_ZUSAETZE =
                    "select * from "
                            + DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL
                            + " where "
                            + DatenbankHelper.DB_F_ZUSATZFELD
                            + " = ?";

            Cursor result = ASettings.mDatenbank.rawQuery(
                    SQL_READ_ZUSAETZE,
                    new String[]{Long.toString(zusatzfeldDefinition.getID())}
            );

            while (result.moveToNext()) {
                mAuswahlListe.add(new zusatzWertAuswahlItem(result));
            }
            result.close();
            // ASettings.mDatenbank.close();

            sort(ASettings.mPreferenzen.getInt(
                            ISettings.KEY_SORT_AUSWAHLLISTE,
                            ISettings.SORT_NO
                    )
            );

            summeSelectedItems = setAllSelected(zusatzfeld.getStringWert(false));
        }
    }


    // erstellt die Auswahlliste eines Zusatzwertes
    @SuppressLint("Range")
    public ZusatzWertAuswahlListe(ZusatzfeldDefinition zusatzfeld, Arbeitsplatz arbeitsplatz) {
        mArbeitsplatz = arbeitsplatz;
        mAuswahlListe = new ArrayList<>();
        zusatzfeldDefinition = zusatzfeld;
        if(zusatzfeldDefinition != null) {
            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getReadableDatabase();

            final String SQL_READ_ZUSAETZE =
                    "select * from "
                            + DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL
                            + " where "
                            + DatenbankHelper.DB_F_ZUSATZFELD
                            + " = ?";

            Cursor result = ASettings.mDatenbank.rawQuery(
                    SQL_READ_ZUSAETZE,
                    new String[]{Long.toString(zusatzfeldDefinition.getID())}
            );

            while (result.moveToNext()) {
                mAuswahlListe.add(new zusatzWertAuswahlItem(result));
            }
            result.close();
            // ASettings.mDatenbank.close();

            sort(ASettings.mPreferenzen.getInt(
                            ISettings.KEY_SORT_AUSWAHLLISTE,
                            ISettings.SORT_NO
                    )
            );

            summeSelectedItems = 0;
        }
    }

    // kopiert die ZusatzwertAuswahlListe
    public ZusatzWertAuswahlListe copy(IZusatzfeld zusatzfeld){
        ZusatzWertAuswahlListe ziel = new ZusatzWertAuswahlListe(zusatzfeld, mArbeitsplatz);
        zusatzWertAuswahlItem neu;
        for (zusatzWertAuswahlItem auswahlItem : mAuswahlListe) {
             neu = new zusatzWertAuswahlItem();
             neu.wert.set(auswahlItem.getWert());
            ziel.mAuswahlListe.add(neu);

        }
        return ziel;
    }

    public void sort(int sortBy){
        switch (sortBy) {
            case ISettings.SORT_AZ :
                sortNachName(false);
                break;
            case ISettings.SORT_ZA:
                sortNachName(true);
                break;
            default:
                sortNachBenutzung();
        }
    }
    private void sortNachName(boolean rev) {
        Comparator<zusatzWertAuswahlItem> comp = rev ? new NameComparator_ZA() : new NameComparator_AZ();
        try {
            mAuswahlListe.sort(comp);
        } catch (ConcurrentModificationException ce) {
            ce.fillInStackTrace();
        }
    }

    private void sortNachBenutzung() {
        Comparator<zusatzWertAuswahlItem> comp = new BenutzungComparator();
        try {
            mAuswahlListe.sort(comp);
        } catch (ConcurrentModificationException ce){
            ce.fillInStackTrace();
        }
    }

    public void speichern() {
        for (zusatzWertAuswahlItem auswahlItem : mAuswahlListe) {
            auswahlItem.save();
        }
    }

    void addWert(zusatzWertAuswahlItem wert) {
        if (wert.wert.getDatenTyp() == IZusatzfeld.TYP_AUSWAHL_TEXT && wert.wert.getString(false).contains(", ")) {
            // eingegebenen Text aufteilen (Kommas als Seperaror)
            // Teiltexte als eigene Auswahlfelder eintragen wenn sie noch nicht vorhanden sind
            String[] werte = wert.wert.getString(false).split(", ");
            for (String s : werte) {
                boolean gefunden = false;
                for (zusatzWertAuswahlItem item : mAuswahlListe) {
                    if (item.wert.getString(false).equals(s)) {
                        gefunden = true;
                        break;
                    }
                }
                if (!gefunden) {
                    zusatzWertAuswahlItem wertNeu = new zusatzWertAuswahlItem();
                    wertNeu.wert.setWert(s);
                    wertNeu.save();
                    mAuswahlListe.add(wertNeu);
                    changeSummeItemSelected(wertNeu.setSelect(true));
                }
            }
            wert.loeschen();
            setAllSelected(wert.wert.getString(false));
        } else {
            boolean gefunden = false;
            for (zusatzWertAuswahlItem item : mAuswahlListe) {
                if (item.wert.getString(false).equals(wert.wert.getString(false))) {
                    gefunden = true;
                    changeSummeItemSelected(item.setSelect(true));
                    wert.loeschen();
                    break;
                }
            }
            if (!gefunden) {
                mAuswahlListe.add(wert);
                changeSummeItemSelected(wert.setSelect(true));
            }
        }
    }

    public int size(){
       return mAuswahlListe.size();
    }

    /**
     * Markiert alle Werte, die im Zielfeld enthalten sind als augewählt
     * @param wertliste die Werte als Zeichenkette, wie sie im Zielfeld stehen (durch Komma getrennt)
     * @return die Anzahl der ausgewälten Werte
     */
    private int setAllSelected(String wertliste){
        int anzahl = 0;

        String[] werte = wertliste.split(", ");
        for (String s : werte) {
            for (zusatzWertAuswahlItem item : mAuswahlListe) {
                if (s.equals(item.getWert().getStringWert(false))) {
                    item.isSelect = true;
                    anzahl++;
                    break;
                }
            }
        }
        return anzahl;
    }

    /**
     * vergrössert oder verkleinert die Anzahl der selectierten Werte
     * @param wert Betrag um den die Anzahl vergrössert oder vcerkleinert werden soll
     * @return neue Anzahl selektierter Einträge (0...n)
     */
    protected int changeSummeItemSelected(int wert){
        summeSelectedItems += wert;
        if(summeSelectedItems < 0) summeSelectedItems = 0;
        return summeSelectedItems;
    }

    /**
     * Gibt die Summe der ausgewälten Werte zurück
     * @return
     */
    public int getSummeSelectedItems(){
        return summeSelectedItems;
    }

    /**
     * Gibt den ausgewälten Wert zurück
     * @param index Position innerhalb der Werteliste
     * @return null oder der gesuchte Wert
     */
    public zusatzWertAuswahlItem getEintrag(int index){
        if(index < mAuswahlListe.size())
            return mAuswahlListe.get(index);
        else
            return null;
    }

    /**
     * Gibt das komplette Zusatzfeld des gesuchten Wertes zurück
     * @param index Position innerhalb der Werteliste
     * @return null oder das Zusatzfeld des gesuchten Wertes
     */
    public IZusatzfeld getEintragWert(int index){
        if(index < mAuswahlListe.size())
            return mAuswahlListe.get(index).wert;
        else
            return null;
    }

    /**
     * Gibt das komplette Zusatzfeld des gesuchten Wertes zurück
     * @param id die ID des gesuchten Zusatzfeldes
     * @return null oder das Zusatzfeld des gesuchten Wertes
     */
    public IZusatzfeld getEintragWert(long id){
        for (zusatzWertAuswahlItem auswahlItem: mAuswahlListe) {
            if(auswahlItem.id == id)
                return auswahlItem.wert;
        }
        return null;
    }

    public ArrayList<zusatzWertAuswahlItem> getListe(){
        return mAuswahlListe;
    }

    public void loescheEintrag(int position){
        mAuswahlListe.get(position).loeschen();
        mAuswahlListe.remove(position);
    }

    /*
     * Sortierer für die Liste
     */
    private static class NameComparator_AZ implements Comparator<zusatzWertAuswahlItem> {

        @Override
        public int compare(zusatzWertAuswahlItem wert1, zusatzWertAuswahlItem wert2) {
            return wert1.wert.getString(false).toLowerCase()
                    .compareTo(wert2.wert.getString(false).toLowerCase());
        }
    }
    private static class NameComparator_ZA implements Comparator<zusatzWertAuswahlItem> {
        @Override
        public int compare(zusatzWertAuswahlItem wert1, zusatzWertAuswahlItem wert2) {
            return wert2.wert.getString(false).toLowerCase()
                    .compareTo(wert1.wert.getString(false).toLowerCase());
        }
    }

    private static class BenutzungComparator implements Comparator<zusatzWertAuswahlItem> {
        @Override
        public int compare(zusatzWertAuswahlItem wert1, zusatzWertAuswahlItem wert2) {
            return wert2.verwendetMenge - wert1.verwendetMenge;
        }
    }

    /*
     + Innere Klasse eines Listenitems
     */
    public static class zusatzWertAuswahlItem {
        private int verwendetMenge = 0;
        private long id = -1;
        private final IZusatzfeld wert;
        private boolean isNotSave = false;
        private boolean isSelect = false;
        zusatzWertAuswahlItem(){
            wert = zusatzfeldDefinition.makeNewZusatzfeld();
            isNotSave = true;
        }
        @SuppressLint("Range")
        zusatzWertAuswahlItem(Cursor result) {
            verwendetMenge = result.getInt(result.getColumnIndex(DatenbankHelper.DB_F_ANZAHL_VERWENDET));
            id = result.getLong(result.getColumnIndex(DatenbankHelper.DB_F_ID));
            wert = zusatzfeldDefinition.makeNewZusatzfeld(result);
        }

        public void setWert(@NonNull IZusatzfeld wert){
            if(!this.wert.getStringWert(false).equals(wert.getStringWert(false))) {
                this.wert.set(wert);
                isNotSave = true;
                save();
            }
        }

       IZusatzfeld getWert(){
            return wert;
        }

        public int getVerwendet(){
            return verwendetMenge;
        }

        protected void addVerwendet(){
            verwendetMenge++;
            isNotSave = true;
            save();
            //return verwendetMenge;
        }

        protected void subVerwendet(){
            if(verwendetMenge > 0) {
                verwendetMenge--;
                isNotSave = true;
                save();
            }
            //return verwendetMenge;
        }

        protected int setSelect(boolean selection){
            if(selection != isSelect) {
                isSelect = !isSelect;
                if(isSelect){
                    addVerwendet();
                    return 1;
                }
                subVerwendet();
                return -1;
            }
            return 0;
        }

        public boolean isSelect(){
            return isSelect;
        }

        private void loeschen(){
            // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
            ASettings.mDatenbank.delete(
                    DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL,
                    DatenbankHelper.DB_F_ID + "=?",
                    new String[]{Long.toString(id)});
            // ASettings.mDatenbank.close();
        }

        private void save(){
          if(isNotSave){
              ContentValues werteSave = new ContentValues();
              String stringWert = wert.getStringforDatenbank();

              if(!stringWert.isEmpty()) {
                  // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
                  werteSave.put(DatenbankHelper.DB_F_ZUSATZFELD, wert.getDefinitionID());
                  werteSave.put(DatenbankHelper.DB_F_ANZAHL_VERWENDET, verwendetMenge);
                  werteSave.put(DatenbankHelper.DB_F_WERT, stringWert);

                  if(id < 0){
                      id = ASettings.mDatenbank.insert(
                              DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL,
                              null,
                              werteSave
                      );
                  } else {
                      ASettings.mDatenbank.update(
                           DatenbankHelper.DB_T_ZUSATZWERT_AUSWAHL ,
                            werteSave,
                            DatenbankHelper.DB_F_ID + "=?", new String[]{Long.toString(id)});
                  }
                  // mDatenbank.close();
              }
              isNotSave = false;
          }
        }

    }
}
