/**********************************************************************
 * Copyright (c) by Heiner Jostkleigrewe
 * This program 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.
 *
 *  This program 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 this program.  If not, 
 * see <http://www.gnu.org/licenses/>.
 * 
 * heiner@jverein.de
 * www.jverein.de
 **********************************************************************/
package de.jost_net.JVerein.gui.control;

import java.rmi.RemoteException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import de.jost_net.JVerein.Einstellungen;
import de.jost_net.JVerein.Einstellungen.Property;
import de.jost_net.JVerein.gui.dialogs.AbstractPartExportDialog.ExportArt;
import de.jost_net.JVerein.gui.dialogs.SaldoPartExportDialog;
import de.jost_net.JVerein.gui.parts.JVereinTablePart;
import de.jost_net.JVerein.io.ISaldoExport;
import de.jost_net.JVerein.server.PseudoDBObject;
import de.jost_net.JVerein.util.Datum;
import de.jost_net.JVerein.util.JVDateFormatTTMMJJJJ;
import de.willuhn.jameica.gui.AbstractView;
import de.willuhn.jameica.gui.GUI;
import de.willuhn.jameica.gui.input.DateInput;
import de.willuhn.jameica.gui.input.TextInput;
import de.willuhn.jameica.gui.parts.Button;
import de.willuhn.jameica.system.OperationCanceledException;
import de.willuhn.jameica.system.Settings;
import de.willuhn.logging.Logger;
import de.willuhn.util.ApplicationException;

public abstract class AbstractSaldoControl extends VorZurueckControl
{
  /**
   * Die Art des Eintrags: Header, Detail, Footer (siehe Konstanten)
   */
  public static final String ART = "art";

  /**
   * Summe der Einnahmen.
   */
  public static final String EINNAHMEN = "einnahmen";

  /**
   * Summe der Ausgaben.
   */
  public static final String AUSGABEN = "ausgaben";

  public static final String STEUERBETRAG = "steuerBetrag";

  /**
   * Summe der Umbuchungen.
   */
  public static final String UMBUCHUNGEN = "umbuchungen";

  /**
   * Die Buchungsklasse aus der DB
   */
  public static final String BUCHUNGSKLASSE = "buchungsklasse";

  public static final String BUCHUNGSKLASSE_NUMMER = "buchungsklasse_nummer";

  /**
   * Buchungsklasse Text der angezeigt werden soll
   */
  public static final String BUCHUNGSKLASSE_TEXT = "buchungsklasse_text";

  /**
   * Die Buchungsklasse_ID aus der DB
   */
  public static final String BUCHUNGSKLASSE_ID = "buchungsklasse_id";

  /**
   * Die Buchungsart aus der DB.
   */
  public static final String BUCHUNGSART = "buchungsart";

  /**
   * Buchungsart Text der angezeigt werden soll
   */
  public static final String BUCHUNGSART_TEXT = "buchungsart_text";

  public static final String BUCHUNGSART_NUMMER = "buchungsart_nummer";

  /**
   * Die Buchungsart_ID aus der DB.
   */
  public static final String BUCHUNGSART_ID = "buchungsart_id";

  /**
   * Anfangsbestand der Konten.
   */
  public static final String ANFANGSBESTAND = "anfangsbestand";

  /**
   * Endbestand der Konten.
   */
  public static final String ENDBESTAND = "endbestand";

  /**
   * Anzahl Einträge
   */
  public static final String ANZAHL = "anzahl";

  /**
   * Die Gruppe die im Saldo an erster Stelle stehen soll (Buchungsklasse,
   * Projekt...)
   */
  public static final String GRUPPE = "gruppe";

  /**
   * Die Projekt_ID aus der DBbeim Projektsaldo
   */
  public static final String PROJEKT_ID = "projekt_id";

  public static final String PROJEKT = "projekt";

  public static final String KONTO_ID = "konto_id";

  public static final String KONTO = "konto";

  private DateLabel datumvon;

  private DateLabel datumbis;

  private DateInput suchdatumvon;

  protected DateInput suchdatumbis;

  protected TextInput geschaeftsjahr;

  protected Settings settings = null;

  public static final int ART_HEADER = 1;

  public static final int ART_DETAIL = 2;

  public static final int ART_SALDOFOOTER = 3;

  public static final int ART_SALDOGEWINNVERLUST = 4;

  public static final int ART_GESAMTSALDOFOOTER = 5;

  public static final int ART_GESAMTGEWINNVERLUST = 6;

  public static final int ART_NICHTZUGEORDNETEBUCHUNGEN = 7;

  public static final int ART_LEERZEILE = 8;

  public AbstractSaldoControl(AbstractView view) throws RemoteException
  {
    super(view);
    settings = new Settings(this.getClass());
    settings.setStoreWhenRead(true);
  }

  /**
   * Liefert die Liste
   * 
   * @return die Liste der Einträge
   * @throws RemoteException
   */
  public abstract ArrayList<PseudoDBObject> getList() throws RemoteException;

  /**
   * Lädt die Liste neu
   * 
   * @throws ApplicationException
   * 
   * @throws RemoteException
   */
  public void reloadList() throws ApplicationException
  {
    try
    {
      // Daten in Einstellungen Speichern
      if (getDatumvon().getDate() != null)
      {
        settings.setAttribute("von",
            new JVDateFormatTTMMJJJJ().format(getDatumvon().getDate()));
        settings.setAttribute("bis",
            new JVDateFormatTTMMJJJJ().format(getDatumbis().getDate()));
      }

      ArrayList<PseudoDBObject> zeile = getList();
      JVereinTablePart part = (JVereinTablePart) getTablePart();
      part.removeAll();
      for (PseudoDBObject sz : zeile)
      {
        part.addItem(sz);
      }
    }
    catch (RemoteException re)
    {
      throw new ApplicationException("Fehler bei neu laden der Liste.");
    }
  }

  /**
   * Git ein Object, dass das Interface ISaldoExport implementiert zurück.
   * 
   * @param type
   *          der type der Auswertung
   * @return
   * @throws ApplicationException
   */
  protected abstract ISaldoExport getAuswertung() throws ApplicationException;

  /**
   * Erstellt die Auswertung
   * 
   * @param type
   *          Der Typ der Auswertung (AuswertungPDF, AuswertungCSV)
   * @throws ApplicationException
   */
  private void starteAuswertung() throws ApplicationException
  {
    try
    {
      ArrayList<PseudoDBObject> zeile = getList();

      if (!new SaldoPartExportDialog(getAuswertung(), zeile,
          GUI.getCurrentView().getClass().getSimpleName() + ".Saldotabelle.",
          ExportArt.PDF, getTableTitle(), getTableSubtitle(),
          getTableDateiname()).open())
      {
        throw new OperationCanceledException();
      }
    }
    catch (OperationCanceledException | ApplicationException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      Logger.error("Fehler beim Erstellen der Auswertung.", e);
      throw new ApplicationException("Fehler beim Erstellen der Auswertung.");
    }
  }

  public Button getStartAuswertungPDFButton()
  {
    return new Button("PDF", context -> starteAuswertung(), null, false,
        "file-pdf.png");
  }

  public DateLabel getDatumvon()
  {
    if (datumvon != null)
    {
      return datumvon;
    }
    Calendar cal = Calendar.getInstance();
    Date d = new Date();
    try
    {
      d = new JVDateFormatTTMMJJJJ()
          .parse(settings.getString("von", "01.01" + cal.get(Calendar.YEAR)));
    }
    catch (ParseException e)
    {
      //
    }
    datumvon = new DateLabel(d);
    datumvon.disable();
    return datumvon;
  }

  public DateLabel getDatumbis()
  {
    if (datumbis != null)
    {
      return datumbis;
    }
    Calendar cal = Calendar.getInstance();
    Date d = new Date();
    try
    {
      d = new JVDateFormatTTMMJJJJ()
          .parse(settings.getString("bis", "31.12." + cal.get(Calendar.YEAR)));
    }
    catch (ParseException e)
    {
      //
    }
    datumbis = new DateLabel(d);
    datumbis.disable();
    return datumbis;
  }

  public TextInput getGeschaeftsjahr()
  {
    if (geschaeftsjahr != null)
    {
      return geschaeftsjahr;
    }
    Calendar cal = Calendar.getInstance();
    cal.setTime(getDatumvon().getDate());
    geschaeftsjahr = new TextInput(
        Integer.valueOf((cal.get(Calendar.YEAR))).toString());
    geschaeftsjahr.disable();
    return geschaeftsjahr;
  }

  public DateInput getSuchDatumvon()
  {
    if (suchdatumvon != null)
    {
      return suchdatumvon;
    }
    Calendar cal = Calendar.getInstance();
    Date d = new Date();
    try
    {
      d = new JVDateFormatTTMMJJJJ()
          .parse(settings.getString("von", "01.01" + cal.get(Calendar.YEAR)));
    }
    catch (ParseException e)
    {
      //
    }
    suchdatumvon = new DateInput(d, new JVDateFormatTTMMJJJJ());
    return suchdatumvon;
  }

  public DateInput getSuchDatumbis()
  {
    if (suchdatumbis != null)
    {
      return suchdatumbis;
    }
    Calendar cal = Calendar.getInstance();
    Date d = new Date();
    try
    {
      d = new JVDateFormatTTMMJJJJ()
          .parse(settings.getString("bis", "31.12." + cal.get(Calendar.YEAR)));
    }
    catch (ParseException e)
    {
      //
    }
    suchdatumbis = new DateInput(d, new JVDateFormatTTMMJJJJ());
    return suchdatumbis;
  }

  /**
   * Holt das Geschäftsjahr des Datumbereichs
   * 
   * @return Das Geschäftsjahr, wenn Start und Ende mit der Auswahl
   *         übereinstimmen, sonst 0.
   */
  public Integer isGeschaeftsjahr()
  {
    try
    {
      Integer year;
      Calendar cal = Calendar.getInstance();
      Date von = getDatumvon().getDate();
      Date bis = getDatumbis().getDate();
      cal.setTime(von);
      year = cal.get(Calendar.YEAR);
      Date gjvon = Datum.toDate(
          (String) Einstellungen.getEinstellung(Property.BEGINNGESCHAEFTSJAHR)
              + year);
      if (!von.equals(gjvon))
      {
        return 0;
      }
      cal.add(Calendar.YEAR, 1);
      cal.add(Calendar.DAY_OF_MONTH, -1);
      if (bis.equals(cal.getTime()))
      {
        return year;
      }
    }
    catch (Exception e)
    {
      //
    }
    return 0;
  }

  /**
   * Textinput mit formatiertem Datum.
   */
  public class DateLabel extends TextInput
  {
    private Date d;

    DateLabel(Date date)
    {
      super("");
      setDate(date);
    }

    public void setDate(Date date)
    {
      d = date;
      JVDateFormatTTMMJJJJ df = new JVDateFormatTTMMJJJJ();
      String dstring = d == null ? "" : df.format(d);
      super.setValue(dstring);
    }

    public Date getDate()
    {
      return d;
    }
  }
}
