package kuchenBasar;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.sql.*;
import java.util.*;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.AbstractTableModel;

import util.*;
import util.WinUtil.*;

/**
 * Erzeugt und verwaltet eine JTable aus einer KuchenBasar Tabelle (Kuchen, Gäste, Bestellungen)
 * 
 * bietet folgende Funktionen: - Liste aller Elememte - Navigieren mit Maus bzw. Tastatur - Auswahl
 * eines Elementes zum Detail über Doppelklick oder Enter, und Weiterreichen zum Bearbeiten an das
 * DB-Modul (Insert/Update) - Löschen der ausgewählten Elements - Extrafunktionen: + Alle Elemente
 * löschen (Zap) + Import von neuen Elementen über CSV + Export der gesamten Elementeliste als CSV
 * 
 * 
 * @author Bernd Schubert
 * 
 */
public class KuchenBasarTable extends JDialog implements ActionListener, WindowListener,
    ListSelectionListener, KeyListener, MouseListener, DocumentListener
{
  /**
   * 
   */
  private static final long serialVersionUID   = 20150305L;
  private JMenuBar          menuBar;
  private JMenu             menuDatei, menuBearbeiten, menuExtra, menuHilfe;
  private JMenuItem         miSchliessen, miNeu, miAendern, miLoeschen,
                            miAnzeigen, miZap, miImport, miExport, miInfo, miKurz;

  private JPanel            untereZeile;
  private JTable            tabelle;
  private JScrollPane       jspTabelle;

  private StatusBar         statusBar;
  private JTextField        filter;

  private String[]          aktNameEZ          =
                                               { "Kuchen", "Gast", "Bestellung" };
  private String[]          aktNameMZ          =
                                               { "Kuchen", "Gäste", "Bestellungen" };
  private File              fcFile;
  private String            hilfePfad;
  private boolean           admin              = true;
  private int               aktKey;
  private int               aktDB;
  private final int         BASAR_KUCHEN       = 0;
  private final int         BASAR_GAESTE       = 1;
  private final int         BASAR_BESTELLUNGEN = 2;

  private MainFrame         owner;
  private boolean           programmStart      = true;

  private enum DBOperation
  {
    DB_SHOW, DB_INSERT, DB_UPDATE, DB_DELETE, DB_EXPORT, DB_IMPORT
  }

  /**
   * 
   * @param aktDB
   * @param aktKey
   * @param dbPfad
   */
  public KuchenBasarTable( int aktDB, int aktKey, String pfad, boolean admin )
  {
    this.admin = admin;
    this.aktDB = aktDB;
    this.aktKey = aktKey;
    this.fcFile = new File( pfad );
    this.hilfePfad = pfad;

    initializeComponent();
  }

  private void initializeComponent()
  {
    this.setTitle( aktNameMZ[aktDB] );
    this.setBounds( 10, 10, 800, 480 );
    this.setLayout( new BorderLayout() );

    this.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
    this.addWindowListener( this );

    menuBar = new JMenuBar();

    menuDatei = WinUtil.createMenu( menuBar, "Datei", "file", KeyEvent.VK_D );
    miSchliessen = WinUtil.createMenuItem( menuDatei, "Schließen", "exit", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_E, "Programm beenden" );
    menuBearbeiten = WinUtil.createMenu( menuBar, "Bearbeiten", "change", KeyEvent.VK_B );
    miNeu = WinUtil.createMenuItem( menuBearbeiten, "Neu", "insert", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_I, "Zeile hinzufügen" );
    miAendern = WinUtil.createMenuItem( menuBearbeiten, "Ändern", "update", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_A, "Zeile ändern" );
    miLoeschen = WinUtil.createMenuItem( menuBearbeiten, "Löschen", "delete", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_D, "Zeile löschen" );
    menuExtra = WinUtil.createMenu( menuBar, "Extra", "change", KeyEvent.VK_E );
    miAnzeigen = WinUtil.createMenuItem( menuExtra, "(neu) Anzeigen", "refresh", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_R, "neu zeigen" );
    miZap = WinUtil.createMenuItem( menuExtra, "(alle) Löschen", "zap", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_Z, "alle löschen" );
    miImport = WinUtil.createMenuItem( menuExtra, "Import", "import", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_I, "neue Sätze importieren" );
    miExport = WinUtil.createMenuItem( menuExtra, "Export", "export", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_E, "alle Sätze exportieren" );
    menuHilfe = WinUtil.createMenu( menuBar, "Hilfe", "help", KeyEvent.VK_H );
    miInfo = WinUtil.createMenuItem( menuHilfe, "Info", "info", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_I, "Info" );
    miKurz = WinUtil.createMenuItem( menuHilfe, "Kurzbeschreibung", "kurz", MenuItemType.ITEM_PLAIN,
        this, null, KeyEvent.VK_K, "Kurzbeschreibung" );

    this.setJMenuBar( menuBar );

    tabelle = new JTable();
    tabelle.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
    tabelle.getSelectionModel().addListSelectionListener( this );
    tabelle.addKeyListener( this );
    tabelle.addMouseListener( this );

    jspTabelle = new JScrollPane( tabelle );
    this.add( jspTabelle, BorderLayout.CENTER );

    untereZeile = new JPanel();
    untereZeile.setLayout( new GridLayout( 0, 2 ) );

    statusBar = new StatusBar();
    statusBar.setPreferredSize( new Dimension( 0, 30 ) );
    untereZeile.add( statusBar );

    filter = new JTextField();
    filter.setPreferredSize( new Dimension( 0, 30 ) );
    filter.getDocument().addDocumentListener( this );
    untereZeile.add( filter );

    this.add( untereZeile, BorderLayout.PAGE_END );
  }

  /**
   * 
   * @param owner
   *          Besonderheit: Schaltet den Owner auf Unsichtbar
   */
  public void showDialog( Component owner )
  {
    this.owner = (MainFrame)owner;
    showDialog();
  }

  /**
   * 
   * @param owner
   *          Besonderheit: Knipst sich selbst beim Owner auf "einmalig"
   */
  public void showDialog()
  {
    initDialog();
    this.setVisible( true );

    if ( owner != null )
    {
      //owner.setVisible( false );
      owner.isAktiv[aktDB] = true;
      owner.miKuchenBasar[aktDB].setEnabled( false );
    }
  }

  private void initDialog()
  {
    this.setLocationRelativeTo( owner );
    this.setLocation( 10 + 100 * ( aktDB + 1 ), 10 + 100 * ( aktDB + 1 ) );
    menuExtra.setEnabled( admin );
    statusBar.setMessage( "Datensätze werden gerade gelesen ..." );

    showDataThread( false );
  }

  private void showDataThread( boolean warten )
  {
    Thread t = new Thread( new ShowData( aktKey ) );
    if ( warten )
      t.run();
    else
      t.start();
  }

  // Die Unterscheidung in t.run() und t.start() muß sein
  // Es trat beim Test eine Fehlermeldung auf
  // - nur in der Eclipse-Umgebung (nicht als JAR-Programm)
  // - nur sporadisch und nicht replizierbar
  // - nur bei zu schnellem Eintippen von Zeichen in den Filter 
  //   (jedesmal Neu Lesen und Erzeugen der JTable!)
  // - ohne Absturz (das Programm arbeitete korrekt weiter...)
  // - nur mit der Exceptionmeldung ArrayIndexOutOfBounds 
  // - und nicht in meinen SourceCodes sondern leider anonym in Vektoren und
  //   Repaints der JTable
  // Mögliche Ursachen:
  // - die Threads mit den neu aufgebauten Table-Modellen könnten miteinander
  //   oder mit dem Garbage-Collector in Konflikt geraten sein
  // - HEAP Probleme?
  // - die ChangeSelection Methode der aktuellen JTable könnte konfus geworden sein
  //   von den JTable-Versionen in den ebenfalls gerade noch aktiven Threads, weil
  //   die Probleme nur mit den Aufrufen (0, 0, false, true) auftraten,
  //   nach Änderung in ( 0, 0, false, false) habe ich keine Abstürze mehr beobachtet

  private void neuAufbau()
  {
    statusBar.setMessage( "Datensätze werden neu gelesen ..." );

    showDataThread( true );
  }

  /**
   * Aufruf der Änderungs-Form und Zurückgebenlassen des aktuell geänderten oder neuen Satzes
   */
  private void detailFormat()
  {
    int ergebnis = -1;

    switch ( aktDB )
    {
      case BASAR_KUCHEN:
        if ( aktKey > -1 && !KuchenDB.isKuchenVorhanden( aktKey ) )
          meldung( "Kuchen ist nicht (mehr) vorhanden" );
        else
        {
          KuchenForm dlg = new KuchenForm( aktKey );
          ergebnis = dlg.showDialog( this );
        }
        break;
      case BASAR_GAESTE:
        if ( aktKey > -1 && !GaesteDB.isGastVorhanden( aktKey ) )
          meldung( "Gast ist nicht (mehr) vorhanden" );
        else
        {
          GaesteForm dlg = new GaesteForm( aktKey );
          ergebnis = dlg.showDialog( this );
        }
        break;
      case BASAR_BESTELLUNGEN:
        if ( aktKey > -1 && !BestellungenDB.isBestellungVorhanden( aktKey ) )
          meldung( "Bestellung ist nicht (mehr) vorhanden" );
        else
        {
          BestellungenForm dlg = new BestellungenForm( aktKey );
          ergebnis = dlg.showDialog( this );
        }
        break;

      default:
        break;
    }

    //Für das Positionieren ist es hinderlich, wenn 
    //der DetailFormat -1 (Abbruch) liefert
    //oder die Zeile schon gelöscht wurde (!isVorhanden)
    if ( ergebnis > -1 )
      aktKey = ergebnis;

    neuAufbau();
  }

  private void auswahl( DBOperation operation )
  {
    int ausw = -1;

    if ( operation == DBOperation.DB_INSERT )
      aktKey = -1;

    else
    {
      ausw = tabelle.getSelectedRow();

      if ( ausw < 0 )
        return;

      aktKey = (int)tabelle.getValueAt( ausw, 0 );
    }

    switch ( operation )
    {
      case DB_SHOW:
        //System.out.print("Key=" + ausw + " ");
        //for ( int i = 0; i < tabelle.getColumnCount(); i++ )
        //  System.out.print("El["+i+"]="+tabelle.getValueAt( ausw, i ) + ", ");
        break;

      case DB_DELETE:
        loeschen();
        break;

      case DB_INSERT:
      case DB_UPDATE:
        detailFormat();
        break;

      default:
        break;
    }
  }

  private void loeschen()
  {
    boolean ergebnis = false;
    int referenzen = 1;

    if ( frage( "Soll " + aktNameEZ[aktDB] + " gelöscht werden" ) )
    {
      //BOT und EOT übernimmt das Zugriffsmodul
      switch ( aktDB )
      {
        case BASAR_KUCHEN:
          if ( !KuchenDB.isKuchenVorhanden( aktKey ) )
          {
            meldung( "Kuchen ist nicht (mehr) vorhanden" );
            return;
          }
          referenzen = BestellungenDB.getBestellungenAnzahlZuKuchen( aktKey );
          if ( referenzen > 0 )
          {
            meldung( "Kuchen ist noch in " + referenzen + " Bestellungen vorhanden!" );
            return;
          }
          ergebnis = KuchenDB.deleteKuchen( aktKey );
          break;
        case BASAR_GAESTE:
          if ( !GaesteDB.isGastVorhanden( aktKey ) )
          {
            meldung( "Gast ist nicht (mehr) vorhanden" );
            return;
          }
          referenzen = BestellungenDB.getBestellungenAnzahlZuGast( aktKey );
          if ( referenzen > 0 )
          {
            meldung( "Gast hat noch " + referenzen + " Bestellungen!" );
            return;
          }
          ergebnis = GaesteDB.deleteGast( aktKey );
          break;
        case BASAR_BESTELLUNGEN:
          if ( !BestellungenDB.isBestellungVorhanden( aktKey ) )
            meldung( "Bestellung ist nicht (mehr) vorhanden" );
          else
            ergebnis = BestellungenDB.deleteBestellung( aktKey );
          break;

        default:
          break;
      }

      if ( ergebnis )
      {
        aktKey = 0;
        neuAufbau();
      }
    }
  }

  private void zap()
  {
    boolean ergebnis = false;
    if ( frage( "Wirklich alle " + aktNameMZ[aktDB] + " löschen?" ) )
    {
      switch ( aktDB )
      {
        case BASAR_KUCHEN:
          if ( frage( "Es müssen dann auch alle Bestellungen gelöscht werden?" ) )
          {
            ergebnis = BestellungenDB.zapBestellungen() && KuchenDB.zapKuchen();
          }
          break;
        case BASAR_GAESTE:
          if ( frage( "Es müssen dann auch alle Bestellungen gelöscht werden?" ) )
          {
            ergebnis = BestellungenDB.zapBestellungen() && GaesteDB.zapGaeste();
          }
          break;
        case BASAR_BESTELLUNGEN:
          ergebnis = BestellungenDB.zapBestellungen();
          break;

        default:
          break;
      }
      if ( ergebnis )
      {
        aktKey = 0;
        neuAufbau();
      }
    }
  }

  private void importieren()
  {
    openFileDialog( DBOperation.DB_IMPORT );

    aktKey = 0;
    neuAufbau();
  }

  private void exportieren()
  {
    openFileDialog( DBOperation.DB_EXPORT );

    aktKey = 0;
    neuAufbau();
  }

  private void openFileDialog( DBOperation operation )
  {
    String dateiname;
    JFileChooser fc = new JFileChooser();
    fc.setCurrentDirectory( fcFile );

    fc.setFileFilter( new FileNameExtensionFilter( "CSV-Dateien (*.csv)", "csv" ) );
    fc.addChoosableFileFilter( new FileNameExtensionFilter( "Textdateien (*.txt)", "txt" ) );

    fc.setMultiSelectionEnabled( false );
    fc.setAcceptAllFileFilterUsed( false );

    if ( fc.showOpenDialog( this ) != JFileChooser.APPROVE_OPTION )
      return;

    fcFile = fc.getSelectedFile();
    dateiname = fcFile.toString();

    if ( dateiname.indexOf( "." ) < 0 )
      dateiname += ".csv";

    if ( operation == DBOperation.DB_IMPORT )
      lesen( dateiname );
    else if ( operation == DBOperation.DB_EXPORT )
      schreiben( dateiname );
  }

  private void lesen( String dateiname )
  {
    FileReader rd = null;
    BufferedReader br = null;
    String zeile;

    try
    {
      rd = new FileReader( dateiname );
      br = new BufferedReader( rd );

      while ( ( zeile = br.readLine() ) != null )
      {
        //BOT und EOT übernimmt das Zugriffsmodul
        //Auf die Auswertung des Inserts (ID) kann hier verzichtet werden
        switch ( aktDB )
        {
          case BASAR_KUCHEN:
            Kuchen kuchen = new Kuchen( zeile );
            if ( !kuchen.getFehler() )
              KuchenDB.insertKuchen( kuchen );
            break;
          case BASAR_GAESTE:
            Gast gast = new Gast( zeile );
            if ( !gast.getFehler() )
              GaesteDB.insertGast( gast );
            break;
          case BASAR_BESTELLUNGEN:
            Bestellung bestellung = new Bestellung( zeile );
            if ( !bestellung.getFehler() )
              //Die Bestellungen müssen hier an den Kuchenvorräten vorbei importiert werden
              //(ohne die incl. Vorratsveränderung des Inserts)
              BestellungenDB.importBestellung( bestellung );
            break;

          default:
            break;
        }
      }
    }
    catch ( IOException e )
    {
      meldung( "IO-Fehler beim Öffnen/Schreiben " + dateiname + " " + e.getMessage() );
    }
    catch ( Exception e )
    {
      meldung( "allgemeiner Fehler beim Lesen " + dateiname + " " + e.getMessage() );
    }
    finally
    {
      try
      {
        br.close();
      }
      catch ( IOException e )
      {
        meldung( "IO-Fehler beim Close " + dateiname + " " + e.getMessage() );
      }
    }
  }

  private void schreiben( String dateiname )
  {
    ArrayList<Kuchen> kuchenliste = null;
    ArrayList<Gast> gaesteliste = null;
    ArrayList<Bestellung> bestellungenliste = null;

    switch ( aktDB )
    {
      case BASAR_KUCHEN:
        kuchenliste = KuchenDB.getKuchenTabelle();
        break;
      case BASAR_GAESTE:
        gaesteliste = GaesteDB.getGaesteTabelle();
        break;
      case BASAR_BESTELLUNGEN:
        bestellungenliste = BestellungenDB.getBestellungenTabelle();
        break;

      default:
        break;
    }

    FileWriter wr = null;
    BufferedWriter bw = null;

    try
    {
      wr = new FileWriter( dateiname );
      bw = new BufferedWriter( wr );

      switch ( aktDB )
      {
        case BASAR_KUCHEN:
          for ( Kuchen kuchen : kuchenliste )
          {
            bw.write( kuchen.getGesamt() );
            bw.newLine();
          }
          break;
        case BASAR_GAESTE:
          for ( Gast gast : gaesteliste )
          {
            bw.write( gast.getGesamt() );
            bw.newLine();
          }
          break;
        case BASAR_BESTELLUNGEN:
          for ( Bestellung bestellung : bestellungenliste )
          {
            bw.write( bestellung.getGesamt() );
            bw.newLine();
          }
          break;

        default:
          break;
      }

    }
    catch ( IOException e )
    {
      meldung( "IO-Fehler beim Öffnen/Schreiben " + dateiname + " " + e.getMessage() );
    }
    catch ( Exception e )
    {
      meldung( "allgemeiner Fehler beim Schreiben " + dateiname + " " + e.getMessage() );
    }
    finally
    {
      try
      {
        bw.close();
      }
      catch ( IOException e )
      {
        meldung( "IO-Fehler beim Close " + dateiname + " " + e.getMessage() );
      }
    }
  }

  private void info()
  {
    meldung( "Hier können die " + aktNameMZ[aktDB] + " verwaltet werden" );
  }

  private void kurz()
  {
    statusBar.setMessage( "Kurzbeschreibung" );
    Hilfe dlg = new Hilfe( this, hilfePfad );
    dlg.showDialog( this );
  }

  private boolean frage( String frage )
  {
    Object[] options =
    { "Ja", "Nein" };

    int retValue = JOptionPane.showOptionDialog(
        this,
        frage,
        aktNameEZ[aktDB],
        JOptionPane.YES_NO_OPTION,
        JOptionPane.QUESTION_MESSAGE,
        null,
        options,
        options[1]
        );

    if ( retValue == JOptionPane.NO_OPTION || retValue == JOptionPane.CLOSED_OPTION )
      return false;

    return true;
  }

  private void meldung( String satz )
  {
    JOptionPane.showMessageDialog(
        this,
        satz,
        aktNameMZ[aktDB] + "-Tabelle",
        JOptionPane.ERROR_MESSAGE
        );
  }

  private class ShowData implements Runnable
  {
    private int key      = 0;
    private int position = 0;

    public ShowData( int key )
    {
      this.key = key;
    }

    @Override
    public void run()
    {
      tabelle.setModel( new KuchenBasarTableModel( filter.getText() ) );

      aktiviere();

      if ( tabelle.getRowCount() > 0 )
      {
        Font font = tabelle.getTableHeader().getFont().deriveFont( Font.BOLD, 14.0f );
        tabelle.getTableHeader().setFont( font );

        //tabelle.getColumn( "ID" ).setMaxWidth( 0 );
        //tabelle.getColumn( "ID" ).setMinWidth( 0 );

        setTableColumnInvisible( 0 );
      }

      switch ( aktDB )
      {
        case BASAR_KUCHEN:
          statusBar.setMessage( "Ausgewählt: " + tabelle.getRowCount() + "/" + KuchenDB.getKuchenAnzahl() );
          break;
        case BASAR_GAESTE:
          statusBar.setMessage( "Ausgewählt: " + tabelle.getRowCount() + "/" + GaesteDB.getGaesteAnzahl() );
          break;
        case BASAR_BESTELLUNGEN:
          statusBar.setMessage( "Ausgewählt: " + tabelle.getRowCount() + "/"
              + BestellungenDB.getBestellungenAnzahl() );
          break;

        default:
          statusBar.setMessage( "fertig" );
          break;
      }
    }

    private void setTableColumnInvisible( int i )
    {
      tabelle.getColumnModel().getColumn( i ).setWidth( 0 );
      tabelle.getColumnModel().getColumn( i ).setMaxWidth( 0 );
      tabelle.getColumnModel().getColumn( i ).setMinWidth( 0 );
      tabelle.getColumnModel().getColumn( i ).setPreferredWidth( 0 );
      tabelle.getColumnModel().getColumn( i ).setResizable( false );
    }

    private void aktiviere()
    {
      if ( tabelle.getRowCount() > 0 )
      {
        position = suche( key );

        if ( position < 0 )
          position = 0;

        tabelle.changeSelection( position, position, false, false );
      }
    }

    public int suche( int key )
    {
      int retVal = -1;

      for ( int i = 0; i < tabelle.getRowCount(); i++ )
      {
        if ( (int)tabelle.getValueAt( i, 0 ) == key )
          retVal = i;
      }

      return retVal;
    }

  }

  private class KuchenBasarTableModel extends AbstractTableModel
  {
    /**
     * 
     */
    private static final long     serialVersionUID = 20150305L;
    private int                   anzahlZeilen;
    private int                   anzahlSpalten;
    private ArrayList<String>     columnNames;
    private ArrayList<ObjectFeld> data;
    private ResultSet             rSet;

    private KuchenBasarTableModel( String filter )
    {
      rSet = null;
      switch ( aktDB )
      {
        case BASAR_KUCHEN:
          rSet = KuchenDB.getKuchenSet();
          break;
        case BASAR_GAESTE:
          rSet = GaesteDB.getGaesteSet();
          break;
        case BASAR_BESTELLUNGEN:
          rSet = BestellungenDB.getBestellungenSet();
          break;
        default:
          break;
      }

      if ( rSet == null )
        return;

      ResultSetMetaData rsMetaData = getMetaData( rSet );

      anzahlSpalten = getColumnCount( rsMetaData );
      setHeader( rsMetaData );

      //Einlesen des ResultSets in die ArrayList und dabei Bestimmen der anzahlZeilen
      //Der Filter kann bewirken, daß ArrayList manche Zeilen des ResultSets nicht enthält

      anzahlZeilen = getData( rSet, filter );
    }

    private int getData( ResultSet rSet, String filter )
    {
      int zeilen;
      String auswerten;
      Object test;
      ObjectFeld feld;
      data = new ArrayList<ObjectFeld>();

      zeilen = 0;

      try
      {
        while ( rSet.next() )
        {
          auswerten = "";

          for ( int spalte = 1; spalte < anzahlSpalten; spalte++ )
          {
            test = rSet.getObject( spalte + 1 );

            if ( test != null )
              auswerten += test.toString();
          }

          if ( auswerten.indexOf( filter ) > -1 || filter.length() == 0 )
          {
            feld = new ObjectFeld( anzahlSpalten );

            for ( int spalte = 0; spalte < anzahlSpalten; spalte++ )
            {
              test = rSet.getObject( spalte + 1 );

              if ( test != null )
                feld.setElement( spalte, rSet.getObject( spalte + 1 ) );
              else
                feld.setElement( spalte, "" );
            }

            zeilen++;
            data.add( feld );
          }
        }

        rSet.close();
      }

      catch ( Exception ex )
      {
        JOptionPane.showMessageDialog( null, "getData: " + ex.getMessage(), "Fehler",
            JOptionPane.ERROR_MESSAGE );
      }

      return zeilen;
    }

    private void setHeader( ResultSetMetaData rsMetaData )
    {
      columnNames = new ArrayList<String>();

      for ( int i = 1; i <= anzahlSpalten; i++ )
        columnNames.add( getColumnLabel( rsMetaData, i ) );
    }

    private String getColumnLabel( ResultSetMetaData rsMetaData, int i )
    {
      String colLabel = "";

      try
      {
        colLabel = rsMetaData.getColumnLabel( i );
      }
      catch ( Exception ex )
      {
        JOptionPane.showMessageDialog( null, "getColumnLabel: " + ex.getMessage(), "Fehler",
            JOptionPane.ERROR_MESSAGE );
      }
      return colLabel;
    }

    private int getColumnCount( ResultSetMetaData rsMetaData )
    {
      int retValue = 0;

      try
      {
        retValue = rsMetaData.getColumnCount();
      }
      catch ( Exception ex )
      {
        JOptionPane.showMessageDialog( null, "getColumnCount: " + ex.getMessage(), "Fehler",
            JOptionPane.ERROR_MESSAGE );
      }
      return retValue;
    }

    private ResultSetMetaData getMetaData( ResultSet rSet )
    {
      ResultSetMetaData rsMD = null;

      try
      {
        rsMD = rSet.getMetaData();
      }
      catch ( Exception ex )
      {
        JOptionPane.showMessageDialog( null, "getMetaData: " + ex.getMessage(), "Fehler",
            JOptionPane.ERROR_MESSAGE );
      }
      return rsMD;
    }

    @Override
    public String getColumnName( int colIndex )
    {
      return columnNames.get( colIndex );
    }

    @Override
    public int getRowCount()
    {
      return anzahlZeilen;
    }

    @Override
    public int getColumnCount()
    {
      return anzahlSpalten;
    }

    @Override
    public Object getValueAt( int rowIndex, int columnIndex )
    {
      return data.get( rowIndex ).getElement( columnIndex );
    }
  }

  @Override
  public void actionPerformed( ActionEvent e )
  {
    JMenuItem mi;
    if ( e.getSource() instanceof JMenuItem )
    {
      mi = (JMenuItem)e.getSource();
      if ( mi.equals( miAnzeigen ) )
      {
        aktKey = 0;
        neuAufbau();
      }
      else if ( mi.equals( miNeu ) )
        auswahl( DBOperation.DB_INSERT );
      else if ( mi.equals( miAendern ) )
        auswahl( DBOperation.DB_UPDATE );
      else if ( mi.equals( miLoeschen ) )
        auswahl( DBOperation.DB_DELETE );
      else if ( mi.equals( miZap ) )
        zap();
      else if ( mi.equals( miImport ) )
        importieren();
      else if ( mi.equals( miExport ) )
        exportieren();
      else if ( mi.equals( miInfo ) )
        info();
      else if ( mi.equals( miKurz ) )
        kurz();
      else if ( mi.equals( miSchliessen ) )
        this.windowClosing( new WindowEvent( this, WindowEvent.WINDOW_CLOSING ) );
    }
  }

  @Override
  public void windowOpened( WindowEvent e )
  {
  }

  @Override
  public void windowClosing( WindowEvent e )
  {
    if ( frage( aktNameMZ[aktDB] + " schließen?" ) )
    {
      //Wiederanmelden des Schalters und Menupunktes beim Owner
      //owner.setVisible( true );
      owner.isAktiv[aktDB] = false;
      owner.miKuchenBasar[aktDB].setEnabled( true );
      this.dispose();
    }
  }

  @Override
  public void windowClosed( WindowEvent e )
  {
  }

  @Override
  public void windowIconified( WindowEvent e )
  {
  }

  @Override
  public void windowDeiconified( WindowEvent e )
  {
  }

  @Override
  public void windowActivated( WindowEvent e )
  {
    if ( !programmStart && tabelle.getRowCount() > 0 )
    {
      neuAufbau();
    }
    programmStart = false;
  }

  @Override
  public void windowDeactivated( WindowEvent e )
  {
  }

  @Override
  public void valueChanged( ListSelectionEvent e )
  {
  }

  @Override
  public void keyTyped( KeyEvent e )
  {
  }

  @Override
  public void keyPressed( KeyEvent e )
  {
    if ( e.getKeyCode() == KeyEvent.VK_ENTER )
    {
      auswahl( DBOperation.DB_UPDATE );
      e.consume();
    }
  }

  @Override
  public void keyReleased( KeyEvent e )
  {
    int kc = e.getKeyCode();
    if ( kc == 36 ) //Pos1
      tabelle.changeSelection( 0, 0, false, false );
    else if ( kc == 35 ) //End
      tabelle.changeSelection( tabelle.getRowCount() - 1, tabelle.getRowCount() - 1, false, false );
    else if ( kc == 155 ) //Ins
      auswahl( DBOperation.DB_INSERT );
    else if ( kc == 127 ) //Del
      auswahl( DBOperation.DB_DELETE );
  }

  @Override
  public void mouseClicked( MouseEvent e )
  {
    if ( e.getClickCount() == 2 )
      auswahl( DBOperation.DB_UPDATE );
  }

  @Override
  public void mouseEntered( MouseEvent e )
  {
  }

  @Override
  public void mouseExited( MouseEvent e )
  {
  }

  @Override
  public void mousePressed( MouseEvent e )
  {
  }

  @Override
  public void mouseReleased( MouseEvent e )
  {
  }

  @Override
  public void insertUpdate( DocumentEvent e )
  {
    aktKey = 0;
    neuAufbau();
  }

  @Override
  public void removeUpdate( DocumentEvent e )
  {
    aktKey = 0;
    neuAufbau();
  }

  @Override
  public void changedUpdate( DocumentEvent e )
  {
  }
}