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

import java.util.ArrayList;
import java.util.Calendar;

import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.arbeitstag.Arbeitstag;
import askanimus.arbeitszeiterfassung2.Datum;

/**
 * @author askanimus@gmail.com on 28.01.15.
 */
public class Arbeitswoche {
    private final Arbeitsplatz mArbeitsplatz;
    private final Datum dErsterTag;
    private int mSoll = 0;
    private int mIst = 0;
    private int mPause = 0;
    private int mBrutto = 0;
    private float mVerdienst;

    //private final int[] pRuhetag = new int[]{0,0,0,0,0,0,0};

    //private Datum mBeginn;
    private final ArrayList<Arbeitstag> mTage;

    public Arbeitswoche(long datum, Arbeitsplatz job) throws NullPointerException {
        Datum mEnde;
        Datum mAktuell;
        mArbeitsplatz = job;
        int sollStundenTag;
        int sollStundenTagPauschal;
        float[] verdienstWerte;
        float verdienstMinuten = 0;
        float verdienstKorrektur = 0;
        boolean isSiebenTageWoche = mArbeitsplatz.getModell() == Arbeitsplatz.Soll_Woche_rollend;

        mAktuell = new Datum(datum, job.getWochenbeginn());
        mAktuell.setDatumAufWochenbeginn();

        mEnde = new Datum(mAktuell.getTimeInMillis(), job.getWochenbeginn());
        mEnde.add(Calendar.DAY_OF_MONTH, 6);

        if (mAktuell.liegtVor(mArbeitsplatz.getStartDatum())) {
            mAktuell.set(mArbeitsplatz.getStartDatum().getDate());
        }

        if (mEnde.liegtNach(ASettings.letzterAnzeigeTag)) {
            mEnde.set(ASettings.letzterAnzeigeTag.getCalendar());
        }

        dErsterTag = new Datum(mAktuell);
        // entsprechende Arbeitstage einlesen
        mTage = new ArrayList<>();

        // im 7 Tage Modell werden erstmal die Brutto Sollstunden der (Teil-)Woche ermittelt
        if(isSiebenTageWoche){
            float arbeitstage = dErsterTag.tageBis(mEnde) + 1;
            arbeitstage /= 7;
            arbeitstage *= 5;
            mSoll = Math.round(arbeitstage * mArbeitsplatz.getSollstundenTagPauschal(
                    mAktuell.get(Calendar.YEAR), mAktuell.get(Calendar.MONTH)
            ));
        }

        do {
            // die, durch manuell vergebene Monatssollstunden angepassten,
            // Sollstunden des Tages ermitteln
            sollStundenTag = mArbeitsplatz.getSollstundenTag(mAktuell);
            sollStundenTagPauschal = mArbeitsplatz.getSollstundenTagPauschal(
                    mAktuell.get(Calendar.YEAR), mAktuell.get(Calendar.MONTH)
            );

            Arbeitstag mTag = new Arbeitstag(
                    mAktuell.getCalendar(),
                    mArbeitsplatz,
                    sollStundenTag,
                    sollStundenTagPauschal
            );

            mTage.add(mTag);

            mIst += mTag.getTagNetto();
            mPause += mTag.getTagPause();
            mBrutto += mTag.getTagBrutto();

            // im 7 Tage Modell werden von Brutto Sollstunden die Sollstunden(-tage) reduzierenden
            // Abwesneheiten abgezogen
            if(isSiebenTageWoche){
                mSoll -= Math.round(mTag.getAbzugTag() * sollStundenTagPauschal);
                mSoll -= mTag.getAbzugMinuten();
            } else {
                mSoll += mTag.getTagSollNetto();
            }

            if (ASettings.isVerdienst) {
               verdienstWerte = mTag.getTagVerdienstWerte();
               verdienstMinuten += verdienstWerte[0];
               verdienstKorrektur += verdienstWerte[1];
               //mVerdienst += mTag.getTagVerdienst();
            }

            // einen Tag weiter
            mAktuell.add(Calendar.DAY_OF_MONTH, 1);
        } while (!mAktuell.liegtNach(mEnde));

        mSoll = Math.max(0, mSoll);

        // Verdienst berechnen

        // Anzahl Minuten auf Sollminuten reduzieren
        // also Überminuten von der Verdienstberechnung ausnehmen
        if(mSoll > 0) {
            verdienstMinuten = Math.min(verdienstMinuten, mSoll);
        }

        // Minuten in Stunden umrechnen
        float stunden = verdienstMinuten / 60;

        // verdienst berechnen
        mVerdienst = stunden * mArbeitsplatz.getStundenlohn();
        mVerdienst += verdienstKorrektur;

        // auf zwei Kommastellen runden
        mVerdienst = Math.round(mVerdienst * 100.0f) / 100.0f;
    }

    public void copy(int wochennummer){
        Datum zielTag = new Datum(dErsterTag);
        int anzahlWochen = wochennummer - getNummer();
        zielTag.add(Calendar.DAY_OF_YEAR, anzahlWochen * 7);

        for (Arbeitstag quellTag : mTage) {
            quellTag.copy(zielTag);
            zielTag.add(Calendar.DAY_OF_YEAR, 1);
        }
    }

    public int getNummer(){
        return dErsterTag.get(Calendar.WEEK_OF_YEAR);
    }

    public int getIst() {
        return mIst;
    }

    public int getSoll() {
        return mSoll;
    }

    public int getTagzahl() {
        return mTage.size();
    }

    // gibt die Summe der Arbeitstage der Woche aus
    // entweder alle Arbeitstage laut Kalender (false)
    // oder unter Berücksichtigung der eingetragenen Abwesenheitstage (Urlaub etc.) (true)
    public float getSummeArbeitsTage(Boolean netto) {
        float mArbeitstage = 0;
        float mAbzugTage = 0;
        if (netto)
            mAbzugTage = getSummeAbwesenheitsTage();

        if(mTage != null ) {
            if(mArbeitsplatz.getModell() != Arbeitsplatz.Soll_Woche_rollend) {
                for (int i = 0; i < mTage.size(); i++) {
                    mArbeitstage += mArbeitsplatz.getArbeitstag(
                            mTage.get(i).getWochentag());
                }
                mArbeitstage -= mAbzugTage;
            } else {
                mArbeitstage = mTage.size() - mAbzugTage;
                mArbeitstage = Math.min(mArbeitstage, 5f - mAbzugTage);
            }
        }

        return mArbeitstage;
    }


    // gibt die Summe von Tagen nach Art der Abwesenheit (bezahlt(Feiertage)
    // oder Sollstundereduzierend (Urlaub, Krank. usw.)
    private float getSummeAbwesenheitsTage() {
        float tage = 0;

        if(mTage != null ) {
            for (int i = 0; i < mTage.size(); i++) {
                //if (Arbeitstage[i] != null)
                tage += mTage.get(i).getAbzugTag();
            }
        }
        return tage;
    }


    public float getSummeAlternativTage(long abwesenheit) {
        float u = 0;

        if(mTage != null ) {
            for (int i = 0; i < mTage.size(); i++) {
                //if (Arbeitstage[i] != null)
                u += mTage.get(i).getAlternativTag(abwesenheit);
            }
        }

        return u;
    }

    public int getPause() {
        return mPause;
    }

    public int getBrutto() {
        return mBrutto;
    }

    public float getVerdienst(){
        return mVerdienst;
    }

    public Arbeitstag getTag(int nummer){
        if(nummer < mTage.size())
            return mTage.get(nummer);
        else
            return null;
    }

    public ArrayList<Arbeitstag> getTagListe(){
        return mTage;
    }

    public Datum getDatumErsterTag(){
        return dErsterTag;
    }

    public Datum getDatumLetzterTag(){
        Datum d = new Datum(dErsterTag);
        d.add(Calendar.DAY_OF_MONTH, mTage.size()-1);
        return d;
    }

    public Arbeitsplatz getArbeitsplatz(){
        return mArbeitsplatz;
    }
}
