/*
 * Copyright (c) 2014 - 2025 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.feiertage;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Scanner;

import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.Ics.IIcs;
import askanimus.arbeitszeiterfassung2.datenbank.DatenbankHelper;

public class FeiertageListe  implements IIcs {

    private final static String SQL_READ_FEIERTAGE =
            "select * from "
                    + DatenbankHelper.DB_T_FEIERTAGE
                    + " ORDER BY "
                    + DatenbankHelper.DB_F_JAHR
                    + ", " + DatenbankHelper.DB_F_MONAT
                    + ", " + DatenbankHelper.DB_F_TAG;

    private final ArrayList<FeiertageJahr> feiertagJahre;

    @SuppressLint("Range")
    public FeiertageListe(SQLiteDatabase datenbank) {
        feiertagJahre = new ArrayList<>();
        Cursor resultFeiertage = datenbank.rawQuery(SQL_READ_FEIERTAGE, null);

        if (resultFeiertage.getCount() > 0) {
            FeiertageJahr aktJahrFeiertage = null;
            while (resultFeiertage.moveToNext()) {
                Feiertag feiertagNeu = new Feiertag(resultFeiertage);

                // wenn es der erste Feiertag ist oder der erste eines neuen Jahres
                // dann das erste bzw. ein neues Jahr anlegen
                if (aktJahrFeiertage == null || feiertagNeu.getJahr() > aktJahrFeiertage.getJahr()) {
                    aktJahrFeiertage = new FeiertageJahr(feiertagNeu.getJahr());
                    feiertagJahre.add(aktJahrFeiertage);
                }
                aktJahrFeiertage.addFeiertag(feiertagNeu);
            }
        }
        resultFeiertage.close();
    }

    public boolean add(Feiertag fNeu) {
        int jahrAdd = fNeu.getJahr();

        // es wird der neue Termin eingeordnet
        for (int i = 0; i < feiertagJahre.size(); i++) {
            int jahr = feiertagJahre.get(i).getJahr();
            // den neuen Feiertag in diese Jahr eintragen
            if (jahr == jahrAdd) {
                return (feiertagJahre.get(i).insertFeiertag(fNeu));
            }

            // der Feiertag gehört ins vorangegangene Jahr welches noch nicht in der Liste steht
            if (jahr > jahrAdd) {
                FeiertageJahr jahrNeu = new FeiertageJahr(jahrAdd);
                jahrNeu.addFeiertag(fNeu);
                feiertagJahre.add(i, jahrNeu);
                return true;
            }
        }

        // der Feiertag gehört in ein Folgejahr welches noch nicht in der Liste steht
        FeiertageJahr jahrNeu = new FeiertageJahr(jahrAdd);
        jahrNeu.addFeiertag(fNeu);
        feiertagJahre.add(jahrNeu);

        return true;
    }

    public boolean loescheFeiertag(int posJahr, int posTag){
        if(feiertagJahre.get(posJahr).getFeiertag(posTag).loesche()) {
            feiertagJahre.get(posJahr).getFeiertage().remove(posTag);
            if (feiertagJahre.get(posJahr).getFeiertage().isEmpty()) {
                feiertagJahre.remove(posJahr);
            }
            return true;
        }
        return false;
    }

    public boolean loescheJahr(int posJahr){
        if(getFeiertageJahr(posJahr).loesche()){
           feiertagJahre.remove(posJahr);
           return true;
        }
        return false;
    }

    /**
     * Feiertageliste importieren
     *
     * @param feiertagListe: Liste von Feiertagen
     *                       die in die zentrale feiertagsliste importiert werden sollen
     */
    public int FeiertageListeImport(ArrayList<Feiertag> feiertagListe) {
        ArrayList<Feiertag> feiertageWiederholt = new ArrayList<>();
        int anzahl = 0;
        for (Feiertag feiertagNeu : feiertagListe) {
            if(add(feiertagNeu)){
                feiertagNeu.save();
                anzahl++;
                if(feiertagNeu.getWiederholung_Typ() == IIcs.WIEDERHOLUNG_JAHR){
                    feiertageWiederholt.add(feiertagNeu);
                }
            }
        }

        // alle jährlich sich wiederholende Feiertage in alle importierten Jahre einfügen
        for (Feiertag feiertagW : feiertageWiederholt) {
            for (FeiertageJahr jahr : feiertagJahre ) {
                if(jahr.getJahr() > feiertagW.getJahr()){
                    Feiertag feiertagInsert = new Feiertag(feiertagW);
                    feiertagInsert.setStartJahr(jahr.getJahr());
                    if(jahr.insertFeiertag(feiertagInsert)){
                        feiertagInsert.save();
                    }
                }
            }
        }

        return anzahl;
    }

    public ArrayList<Feiertag> FeiertageIcsImport(Context ctx, Uri uri) {
        InputStream is;
        try {
            is = ctx.getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            return null;
        }
        Scanner scanner;
        scanner = new Scanner(is);

        ArrayList<Feiertag> feiertage = new ArrayList<>();

        //Zeile für Zeile lesen
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            if (line.startsWith(TAG_BEGINN + BEREICH_TERMIN)) {
                Feiertag feiertag = new Feiertag();
                while (scanner.hasNextLine()) {
                    line = scanner.nextLine();
                    if (line.startsWith(TAG_TERMIN_VON)) {
                        // Datum des Feiertages
                        feiertag.setStart(line);
                    } else if (line.startsWith(TAG_TERMIN_NAME)) {
                        // Name des Feiertages
                        feiertag.setName(line);
                    } else if(line.startsWith(TAG_WIEDERHOLUNG)) {
                        // jährliche Wiederholung fixer Feiertage
                        if(line.contains(WIEDERHOLUNG_FREQ+WIEDERHOLUNG_FREQ_JAHR)){
                            feiertag.setWiederholung(IIcs.WIEDERHOLUNG_JAHR,0,1);
                        }
                    } else if (line.startsWith(TAG_ENDE)) {
                        // Termineintrag ist zu Ende
                        if (feiertag.getDatumStart() != null) {
                            // Ist ein gültiger Termin gesetzt, dann in die Terminliste eintragen
                            feiertage.add(feiertag);
                        }
                        break;
                    }
                }
            }
        }
        scanner.close();
        try {
            is.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //FeiertageListeImport(feiertage);

        return feiertage;
    }

    public FeiertageJahr getFeiertageJahr(int posJahr) {
        return feiertagJahre.get(posJahr);
    }

    public Feiertag getFeiertag(int posJahr, int posTag) {
        return getFeiertageJahr(posJahr).getFeiertag(posTag);
    }

    public Feiertag getFeiertag(Datum tag) {
        if (tag.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY && tag.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
            for (FeiertageJahr fj : feiertagJahre) {
                if (fj.getJahr() == tag.getJahr()) {
                    for (Feiertag ft : fj.getFeiertage()) {
                        if (ft.getDatumStart().istGleich(tag)) {
                            return ft;
                        }
                    }
                    return null;
                }
            }
        }
        return null;
    }


    int getJahr(int posJahr) {
        return getFeiertageJahr(posJahr).getJahr();
    }

    int getPosJahr(int jahr){
        int pos = -1;
        for (FeiertageJahr fj : feiertagJahre) {
            pos++;
            if(jahr == fj.getJahr()){
                break;
            }
        }
        return pos;
    }

    int getAnzahlJahre() {
        return feiertagJahre.size();
    }

    int getAnzahlFeiertageJahr(int posJahr) {
        return feiertagJahre.get(posJahr).size();
    }
}
