package kuchenBasar;

import java.sql.*;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import util.DatenPlausi;

/**
 * Datenbankzugriffsmodul Bestellungen
 * 
 * @author Bernd Schubert
 * 
 */
public class BestellungenDB
{
  private BestellungenDB()
  {
  }

  /**
   * 
   * @return Aktuelle ID (z.B. gerade beim Insert erzeugt)
   */
  private static int getMaxID()
  {
    String sql = " SELECT MAX(ID) ";
          sql += " FROM bestellungen ";

    int retValue = -1;

    try
    {
      Object obj = DBConnection.executeScalar( sql );

      if ( obj != null )
        retValue = (int)obj;
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim MAX-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param ID
   * @return ist (noch) vorhanden?
   */
  public static boolean isBestellungVorhanden( int ID )
  {
    String sql = " SELECT COUNT(*) ";
          sql += " FROM bestellungen";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    boolean retValue = false;

    try
    {
      prepStatement.setInt( 1, ID );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = ( result.getInt( 1 ) > 0 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Exist-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param kuchen
   * @return wieviele Bestellungen sind zu diesem Kuchen vorhanden?
   */
  public static int getBestellungenAnzahlZuKuchen( int kuchen )
  {
    String sql = " SELECT COUNT(*) ";
          sql += " FROM bestellungen";
          sql += " WHERE kuchen = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, kuchen );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = result.getInt( 1 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Anzahl-Zugriff-Kuchen auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param gast
   * @return wieviele Bestellungen sind zu diesem Kuchen vorhanden?
   */
  public static int getBestellungenAnzahlZuGast( int gast )
  {
    String sql = " SELECT COUNT(*) ";
          sql += " FROM bestellungen";
          sql += " WHERE gast = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, gast );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = result.getInt( 1 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Anzahl-Zugriff-Gast auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @return Anzahl der vorhandenen Bestellungen Der technische Satz ID wird nicht mitgezählt
   */
  public static int getBestellungenAnzahl()
  {
    String sql = " SELECT COUNT(*) ";
          sql += " FROM bestellungen ";
          sql += " WHERE ID > 0 ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    int retValue = -1;

    try
    {
      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = result.getInt( 1 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Count-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param ID
   * @return Bestellung-Objekt zur ID
   */
  public static Bestellung getBestellung( int ID )
  {
    String sql = " SELECT ID, gast, kuchen, bestelldatum, menge, ";
          sql += " gesamtpreis, bezahlt, abgeholt, letzterzugriff ";
          sql += " FROM bestellungen ";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    Bestellung retValue = new Bestellung();

    try
    {
      prepStatement.setInt( 1, ID );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue.setID( result.getInt( 1 ) );
        retValue.setGast( result.getInt( 2 ) );
        retValue.setKuchen( result.getInt( 3 ) );
        retValue.setBestelldatum( DatenPlausi.ef2df( result.getString( 4 ) ) );
        retValue.setMenge( result.getInt( 5 ) );
        retValue.setGesamtpreis( result.getDouble( 6 ) );
        retValue.setBezahlt( result.getBoolean( 7 ) );
        retValue.setAbgeholt( result.getBoolean( 8 ) );
        retValue.setLetzterzugriff( result.getString( 9 ) );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim ID-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param ID
   * @return Menge aus der Bestellung zur ID
   */
  private static int getMenge( int ID )
  {
    String sql = " SELECT menge ";
          sql += " FROM bestellungen ";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, ID );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = result.getInt( 1 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Menge/ID-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param ID
   * @return Kuchen aus der Bestellung zur ID
   */
  private static int getKuchen( int ID )
  {
    String sql = " SELECT kuchen ";
          sql += " FROM bestellungen ";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, ID );

      result = prepStatement.executeQuery();

      if ( result != null )
      {
        result.next();
        retValue = result.getInt( 1 );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Kuchen/ID-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @return Liste aller Bestellungen-Objekte
   */
  public static ArrayList<Bestellung> getBestellungenTabelle()
  {
    String sql = " SELECT ID, gast, kuchen, bestelldatum, menge, ";
          sql += " gesamtpreis, bezahlt, abgeholt, letzterzugriff ";
          sql += " FROM bestellungen ";
    //    sql += " WHERE ID > 0 ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet result = null;
    ArrayList<Bestellung> retValue = new ArrayList<Bestellung>();

    try
    {
      result = prepStatement.executeQuery();

      while ( result.next() )
      {
        Bestellung bestellung = new Bestellung();
        bestellung.setID( result.getInt( 1 ) );
        bestellung.setGast( result.getInt( 2 ) );
        bestellung.setKuchen( result.getInt( 3 ) );
        bestellung.setBestelldatum( DatenPlausi.ef2df( result.getString( 4 ) ) );
        bestellung.setMenge( result.getInt( 5 ) );
        bestellung.setGesamtpreis( result.getDouble( 6 ) );
        bestellung.setBezahlt( result.getBoolean( 7 ) );
        bestellung.setAbgeholt( result.getBoolean( 8 ) );
        bestellung.setLetzterzugriff( result.getString( 9 ) );
        retValue.add( bestellung );
      }
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Tabelle-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @return Liste aller Bestellungen als ResultSet für die JTable Diese kann die ResultSet-Felder
   *         selber und besser (da anonym) auswerten
   */
  public static ResultSet getBestellungenSet()
  {
    //Die Formatierung(Bestelldatum) wird direkt an SQLite weitergereicht, 
    //damit JTable nur noch einen String als Object bekommen kann
    String sql = " SELECT ID ID, ";
          sql += " strftime('%d.%m.%Y', bestelldatum) AS Bestellung, ";
          sql += " kurzgast AS Gast, kurzkuchen AS Kuchen, ";
          sql += " menge AS Menge, gesamtpreis AS Preis, letzterzugriff AS Aktuell  ";
          sql += " FROM bestellungenview ";
          sql += " WHERE ID > 0 ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    ResultSet retValue = null;

    try
    {
      retValue = prepStatement.executeQuery();
    }

    catch ( Exception ex )
    {
      JOptionPane.showMessageDialog(
          null,
          "Fehler beim RSet-Zugriff auf die View BestellungenView: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param bestellung
   * @return ID der erzeugten und eingefügten neuen Bestellung
   * 
   *         Die importierten Bestellungen verändern den Kuchen-Vorrat nicht!!!
   */
  public static int importBestellung( Bestellung bestellung )
  {
    String sql = " INSERT INTO bestellungen ";
          sql += " (gast, kuchen, bestelldatum, menge, ";
          sql += " gesamtpreis, bezahlt, abgeholt, letzterzugriff) ";
          sql += " VALUES ( ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP )";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, bestellung.getGast() );
      prepStatement.setInt( 2, bestellung.getKuchen() );
      prepStatement.setString( 3, DatenPlausi.df2ef( bestellung.getBestelldatum() ) );
      prepStatement.setInt( 4, bestellung.getMenge() );
      prepStatement.setDouble( 5, bestellung.getGesamtpreis() );
      prepStatement.setBoolean( 6, bestellung.isBezahlt() );
      prepStatement.setBoolean( 7, bestellung.isAbgeholt() );

      DBConnection.beginTransaction();

      prepStatement.executeUpdate();

      //Wichtig! In der laufenden Transaktion nach dem gerade eingefügten
      //Satz fahnden
      retValue = getMaxID();

      DBConnection.commitTransaction();
    }

    catch ( Exception ex )
    {
      DBConnection.rollbackTransaction();

      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Import-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param bestellung
   * @return ID der erzeugten und eingefügten neuen Bestellung
   * 
   *         Gleichzeitig muß die Anzahl(Vorrat) beim Kuchen reduziert werden 
   *         (in der gleichen Transaktion)
   */
  public static int insertBestellung( Bestellung bestellung )
  {
    String sql = " INSERT INTO bestellungen ";
          sql += " (gast, kuchen, bestelldatum, menge, ";
          sql += " gesamtpreis, bezahlt, abgeholt, letzterzugriff) ";
          sql += " VALUES ( ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP )";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    int retValue = -1;

    try
    {
      prepStatement.setInt( 1, bestellung.getGast() );
      prepStatement.setInt( 2, bestellung.getKuchen() );
      prepStatement.setString( 3, DatenPlausi.df2ef( bestellung.getBestelldatum() ) );
      prepStatement.setInt( 4, bestellung.getMenge() );
      prepStatement.setDouble( 5, bestellung.getGesamtpreis() );
      prepStatement.setBoolean( 6, bestellung.isBezahlt() );
      prepStatement.setBoolean( 7, bestellung.isAbgeholt() );

      DBConnection.beginTransaction();

      prepStatement.executeUpdate();

      //Das Commit / EOT erfolgt nach dem letzten Aufruf
    }

    catch ( Exception ex )
    {
      DBConnection.rollbackTransaction();

      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Insert-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    int tempKuchen = bestellung.getKuchen();
    int vorrat = KuchenDB.getAnzahl( tempKuchen );

    vorrat -= bestellung.getMenge();

    //KuchenDB.setAnzahl hat KEINE eigene Transaktionssteuerung
    //Es hat aber einen eigenen try/catch und eine Fehlermeldung
    //Hier kann bei Ergebnis "False" sofort beendet werden

    if ( !KuchenDB.setAnzahl( tempKuchen, vorrat ) )
    {
      DBConnection.rollbackTransaction();

      return retValue;
    }

    //Wichtig! In der laufenden Transaktion jetzt noch 
    //nach dem gerade eingefügten Satz fahnden

    retValue = getMaxID();

    DBConnection.commitTransaction();

    return retValue;
  }

  /**
   * 
   * @param ID
   * @param bestellung
   * @return erfolgreich
   * 
   *         Gleichzeitig müssen die Anzahlen(Vorräte) beim alten Kuchen und beim neuen Kuchen
   *         verändert werden (in der gleichen Transaktion)
   */
  public static boolean komplexesUpdateBestellung( int ID, Bestellung bestellung )
  {
    String sql = " UPDATE bestellungen ";
          sql += " SET gast = ?, kuchen = ?, bestelldatum = ?, ";
          sql += " menge = ?, gesamtpreis = ?, bezahlt = ?, abgeholt = ?, ";
          sql += " letzterzugriff = CURRENT_TIMESTAMP ";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    boolean retValue = false;

    try
    {
      prepStatement.setInt( 1, bestellung.getGast() );
      prepStatement.setInt( 2, bestellung.getKuchen() );
      prepStatement.setString( 3, DatenPlausi.df2ef( bestellung.getBestelldatum() ) );
      prepStatement.setInt( 4, bestellung.getMenge() );
      prepStatement.setDouble( 5, bestellung.getGesamtpreis() );
      prepStatement.setBoolean( 6, bestellung.isBezahlt() );
      prepStatement.setBoolean( 7, bestellung.isAbgeholt() );
      prepStatement.setInt( 8, ID );

      DBConnection.beginTransaction();

      //Werte aus der bisherigen Bestellung
      int altKuchen = getKuchen( ID );
      int altMenge = getMenge( ID );
      int altVorrat = KuchenDB.getAnzahl( altKuchen );

      //Zurückgeben der alten Kuchen
      altVorrat += altMenge;

      //KuchenDB.setAnzahl hat KEINE eigene Transaktionssteuerung
      //Es hat aber einen eigenen try/catch und eine Fehlermeldung
      //Hier kann bei Ergebnis "False" sofort beendet werden

      if ( !KuchenDB.setAnzahl( altKuchen, altVorrat ) )
      {
        DBConnection.rollbackTransaction();

        return retValue;
      }

      //Werte für die neue Bestellung
      int neuKuchen = bestellung.getKuchen();
      int neuMenge = bestellung.getMenge();
      int neuVorrat = KuchenDB.getAnzahl( neuKuchen );

      //Reservieren der neuen Kuchen
      neuVorrat -= neuMenge;

      if ( !KuchenDB.setAnzahl( neuKuchen, neuVorrat ) )
      {
        DBConnection.rollbackTransaction();

        return retValue;
      }

      //jetzt kommt zum Schluß das eigentliche Update der Bestellung
      prepStatement.executeUpdate();

      DBConnection.commitTransaction();

      retValue = true;
    }

    catch ( Exception ex )
    {
      DBConnection.rollbackTransaction();

      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Update-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * 
   * @param ID
   * @return erfolgreich
   */
  public static boolean deleteBestellung( int ID )
  {
    String sql = " DELETE FROM bestellungen ";
          sql += " WHERE ID = ? ";

    PreparedStatement prepStatement = DBConnection.prepareStatement( sql );
    boolean retValue = false;

    try
    {
      prepStatement.setInt( 1, ID );

      DBConnection.beginTransaction();

      int tempKuchen = getKuchen( ID );
      int menge = getMenge( ID );
      int vorrat = KuchenDB.getAnzahl( tempKuchen );

      //Zurückgeben der Kuchen aus der zu löschenden Bestellung
      vorrat += menge;

      //KuchenDB.setAnzahl hat KEINE eigene Transaktionssteuerung
      //Es hat aber einen eigenen try/catch und eine Fehlermeldung
      //Hier kann bei Ergebnis "False" sofort beendet werden

      if ( !KuchenDB.setAnzahl( tempKuchen, vorrat ) )
      {
        DBConnection.rollbackTransaction();

        return retValue;
      }

      prepStatement.executeUpdate();

      DBConnection.commitTransaction();

      retValue = true;
    }

    catch ( Exception ex )
    {
      DBConnection.rollbackTransaction();

      JOptionPane.showMessageDialog(
          null,
          "Fehler beim Delete-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }

  /**
   * Leeren der Bestellungen-Tabelle
   * 
   * @return erfolgreich
   */
  public static boolean zapBestellungen()
  {
    //Entwurfsentscheidung: wir lassen den technischen 0-Satz mal leben...
    String sql = " DELETE FROM bestellungen ";
          sql += " WHERE ID > 0 ";

    boolean retValue = false;

    try
    {
      DBConnection.beginTransaction();

      DBConnection.executeNoneQuery( sql );

      DBConnection.commitTransaction();

      retValue = true;
    }

    catch ( Exception ex )
    {
      DBConnection.rollbackTransaction();

      JOptionPane.showMessageDialog(
          null,
          "Fehler beim ZAP-Zugriff auf die Tabelle Bestellungen: " + ex.getMessage(),
          "db-Fehler",
          JOptionPane.ERROR_MESSAGE
          );
    }

    return retValue;
  }
}
