import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;

import java.util.Vector;


// Beispiel mit vollständiger GUI
// Oben Dateinamen mit einer Eingabezeile
// Mitte Ausgabe-Elemente: Liste und Editor
// Unten Schalter: ok=einlesen


public class Read_dBase2 extends JFrame {

  private JMenuBar menuBar1;
  private JMenu MainFile;
  private JMenuItem MnOpen;
  private JMenuItem MnClose;

  private JComboBox cbDateiname;
  private JList ItemListe;
  private JTextArea Editor;

  private Vector ItemVector;

  //Frame konstruieren
  public Read_dBase2() {

    setSize(1000, 700);
    setTitle("Einlesen einer dBase-Datei");

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setMenues();
    setGUI();
    ItemVector = new Vector();
  } // create


  void setMenues() {
    menuBar1 = new JMenuBar();

      // DATEI
    MainFile = new JMenu("Datei");
    MnOpen = new JMenuItem("Öffnen");
    MnClose = new JMenuItem("Schließen");

    MnOpen.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnOpen_actionPerformed(e);
      }
    });
    MnOpen.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
    MainFile.add(MnOpen);

    MainFile.addSeparator();
    MnClose.addActionListener(new ActionListener()  {

      public void actionPerformed(ActionEvent e) {
        MnClose_click();
      }
    });
    MainFile.add(MnClose);

    menuBar1.add(MainFile);

    this.setJMenuBar(menuBar1);

  }

  void setGUI() {
    this.getContentPane().setLayout( new GridBagLayout() );

    JLabel Label1;
    JButton BnOk;		// Schalter definieren
    JButton BnEsc;		// Schalter definieren

      // North
    Label1 = new JLabel();
    Label1.setText("Datei");
    Label1.setFont( new Font("Arial", Font.BOLD,16));
    String [] files = {"test_bsp1.dbf", "gw_messstellen.dbf"};
    cbDateiname = new JComboBox(files);
    cbDateiname.setEditable(true);
    cbDateiname.setSelectedIndex( 0 );

    cbDateiname.setFont( new Font("Arial", Font.BOLD,16));
    // Dateiname.setText("test_bsp1.dbf");  // N =10

    this.getContentPane().add(Label1,
        new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.NONE,
            new Insets(30,20,10,20), 0, 0));

    this.getContentPane().add(cbDateiname,
        new GridBagConstraints(1, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(30,20,10,20), 0, 0));


    ItemListe = new JList();
    JScrollPane Sc1 = new JScrollPane(ItemListe);
    Editor = new JTextArea();
    Editor.setFont( new Font("Arial", Font.BOLD,16));
    Editor.setText("-");
    JScrollPane Sc2 = new JScrollPane(Editor);

    JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,
           Sc1, Sc2 );

    split.setDividerLocation(150);
 		split.setDividerSize(4);

    this.getContentPane().add(split,
        new GridBagConstraints(0, 1, 2, 1, 1.0, 1.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.BOTH,
            new Insets(10,20,20,20), 0, 0));


    ItemListe.addMouseListener(new java.awt.event.MouseAdapter() {

      public void mouseClicked(MouseEvent e) {
        ItemListe_Clicked();
      }
    });

    ItemListe.addKeyListener(new java.awt.event.KeyAdapter() {
      public void keyReleased(KeyEvent e) {
        ItemListe_Clicked();
      }
    });


      // South
		BnOk = new JButton();  	// Schalter erzeugen
		BnOk.setText("Ok");  	// Text setzen
    //BnOk.setFont( new Font("Arial", Font.BOLD,28));
		BnEsc= new JButton();  	// Schalter erzeugen
		BnEsc.setText("Esc");  	// Text setzen
    //BnEsc.setFont( new Font("Arial", Font.BOLD,28));
     JPanel panelBn = new JPanel();
     panelBn.setLayout( new FlowLayout() );
     //panelBn.setBackground(Color.green);

    this.getContentPane().add(panelBn,
        new GridBagConstraints(0, 3, 2, 1, 100.0, 0.0
            ,GridBagConstraints.CENTER,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,0,20,0), 0, 0));


    panelBn.add(BnOk);
    panelBn.add(BnEsc);



    BnOk.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnOk_Click();
      }
    });
    BnEsc.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnEsc_Click();
      }
    });

  }


  void MnClose_click() {
    System.exit(0);
  }

    // öffnet eine Datei, DEFAULT-Fenster Frame4
    // eventuell auch die Extension abprüfen
  void MnOpen_actionPerformed(ActionEvent e) {
   JFileChooser jFileChooser1 = new JFileChooser();
   String sFileName;

   jFileChooser1.setMultiSelectionEnabled(false);
   // jFileChooser1.setCurrentDirectory(  new File(  (String) System.getProperties().get("user.dir")  )   );
   jFileChooser1.setCurrentDirectory( new File(CProperties.getuserDir() ) );

    if (JFileChooser.APPROVE_OPTION == jFileChooser1.showOpenDialog(this)) {
      // Rufen Sie openFile auf, um Text aus einer Datei in die TextArea zu laden
      sFileName = jFileChooser1.getSelectedFile().getPath();
      System.out.println(sFileName);
      cbDateiname.setSelectedItem(sFileName); // nur wenn Editierbar

//      cbDateiname.setText(sFileName);
    }
  }  // MnOpen


  void BnEsc_Click() {
    System.exit(0);
  }

  void ItemListe_Clicked() {
    Item it;
    int i;
    i = ItemListe.getSelectedIndex();
    if (i>=0) {
      it =(Item) ItemVector.elementAt(i);
      Editor.setText( it.getItem() );
    }                 
  }  // ItemListe_Clicked


  public static void main(String[] args) {
    Read_dBase2 frame = new Read_dBase2();
    frame.setVisible(true);
  }

  public boolean FileExists(String sFileName) {
      File f = null;
      try {
          // evnetuell kann auch f.pathSeparatorChar verwendet werden
          f = new File(sFileName);
          if (f.exists())
              return true;
          else
              return false;
      }
      catch (Exception e) {
          return false;
      }
  }  // FileExists


  void BnOk_Click() {
    String NL = "\n\r";
    FileInputStream Fin;
    DataInputStream Din;
    String sFilename;
    dBase_Header header;
    dBase_Feld felder[];
    int i, j, k;
    int i1,i2,i3,i4;
    String sStr, sItem;
    char ch;
    Item it;

    sFilename = (String) cbDateiname.getSelectedItem();

    if ( ! FileExists(sFilename) ) {
      Editor.setText("Datei ist nicht vorhanden");  // Editorinhalt wird gelöscht
      return;
    }
    ItemVector.clear();  // löschen aller Einträge

    Editor.setText("");  // Editorinhalt löschen
    try {
         Fin = new FileInputStream(sFilename);
       		// Druckausgabe
         Din = new DataInputStream(Fin);
         header = new dBase_Header();
         header.loadFromFile(Din);

         it = new Item("Header", header.toString() );
         ItemVector.add(it);

         // Lesen der Felder
         felder = new dBase_Feld[header.AnzFelder];
         sStr="";
         for (i=0; i<header.AnzFelder;i++) {
           felder[i] = new dBase_Feld();
           felder[i].loadFromFile(Din);
           sStr+="i : "+(i+1) + NL;
           sStr+="  Feldname:"+felder[i].FeldStr + NL;
           sStr+="  cTyp:"+felder[i].cTyp + NL;
           sStr+="  Fieldsize:"+felder[i].fieldsize + NL;
           sStr+="  Nachkomma:"+felder[i].nk + NL;
           sStr+="  Offset:"+felder[i].offset + NL+NL+NL;
         } // for
         it = new Item("Datenfelder", sStr );
         ItemVector.add(it);

         i = (int) Din.readByte();  // 0D

         // Lesen der Daten pro Feld
         // Ausgabe erstmal nur als String
         // es müssten noch Klassen definiert werden, in den
         // automatisch die Attribute gespeichert werden
         // es muss auch eine automatische Umwandlung implementiert werden
         for (i=0; i<header.anzRecords;i++) {
           //Editor.append( "\nDatensatz:"+(i+1) + NL);
           k = (int) Din.readByte();  // trennzeichen Blank  32 oder0x20
           sItem="";

           for (j=0; j<header.AnzFelder;j++) {
             //Editor.append( "  Offset:"+felder[i].offset + NL);
             switch (felder[j].cTyp) {
               case 'C': // Zeichenfolge
                    sStr="";
                    for (k=0;k<felder[j].fieldsize; k++) {
                      sStr+= (char) Din.readByte();  //
                    }
                    sItem+=felder[j]+" = "+sStr + NL;
                    break;
               case 'N':  // Numerisch mit oder ohne Nachkommastelle
                   sStr="";
                    for (k=0;k<felder[j].fieldsize; k++) {
                      sStr+= (char) Din.readByte();  //
                    }
                    sItem+=felder[j]+" = "+sStr + NL;
                    break;
               case 'D':  // datum
                    sStr="";
                    for (k=0;k<felder[j].fieldsize; k++) {
                      sStr+= (char) Din.readByte();  //
                    }
                    sItem+=felder[j]+" = "+sStr + NL;
                    break;
               case 'L':  // boolean
                    ch = (char) Din.readByte();  //
                    if ( (ch=='T') || (ch=='Y') || (ch=='J') )
                      sItem+=felder[j]+" = true" + NL;
                    else
                      sItem+=felder[j]+" = false" + NL;
                    break;
             }
           } // for
           it = new Item((i+1)+". Datensatz", sItem );
           ItemVector.add(it);
           
         }
    	   Din.close();

         ItemListe.setListData( ItemVector );
    }
    catch (IOException ee) {
        System.err.println("IOException: " + ee);
    }

  }  // BnOk_Click

}


class dBase_Header {
     private String NL = "\n\r";

     public int Version;  // byte
     public int jahr;  // byte
     public int monat;  // byte
     public int tag;  // byte
     public int anzRecords;   // Anzahl der Datensaetze
     public int headersize;   // WORD Headergroesse in Byte
     public int recordsize;   // Word Laenge eines einzelnen Datensatzes */
     private byte  dummy[] = new byte[20];
     public int AnzFelder;

     public void loadFromFile(DataInputStream Din) {
         byte b, b1, b2, b3, b4;
         int i1,i2;
         try {
           b = Din.readByte();  // Vorzeichenbehaftet
           Version = (int) b;
           jahr = (int) Din.readByte();  // Vorzeichenbehaftet;
           monat = (int) Din.readByte();  // Vorzeichenbehaftet;
           tag = (int) Din.readByte();  // Vorzeichenbehaftet;

           // Problem little Endian
           b1 = Din.readByte();  // Vorzeichenbehaftet
           b2 = Din.readByte();  // Vorzeichenbehaftet
           b3 = Din.readByte();  // Vorzeichenbehaftet
           b4 = Din.readByte();  // Vorzeichenbehaftet
           //anzRecords = (int)Din.readInt();  //
           anzRecords = (b4 << 24 ) | (b3 << 16 ) | (b2 << 8 ) | b1;

           //b4 = Din.readByte();  // Vorzeichenbehaftet
           i1 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i1<0)  i1+=256;
           i2 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i2<0)  i2+=256;
           headersize = (i2 << 8 ) | i1;

           i1 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i1<0)  i1+=256;
           i2 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i2<0)  i2+=256;
           recordsize = (i2 << 8 ) | i1;
           for (int i=0; i<dummy.length; i++) {
             b = Din.readByte();  // Vorzeichenbehaftet
           }

           // Jeder Feldeintrag ist 32 Byte lang
           // 33 Byte sind vorweg eingetragen
           AnzFelder = (int)( (headersize-33) / 32 );

         }
         catch (IOException ee) {
            System.err.println("IOException: " + ee);
         }
     }

  public String toString() {
    String sStr="";
    sStr="dBase Version: "+Version + NL;
    sStr+="Jahr: "+jahr + NL;
    sStr+="Monat: "+monat + NL;
    sStr+="Tag: "+tag + NL;
    sStr+="AnzRecords: "+anzRecords + NL;
    sStr+="HeaderSize: "+headersize + NL;
    sStr+="RecordsSize: "+recordsize + NL;
    sStr+="AnzFelder: "+AnzFelder + NL;
    return sStr;
  }

} // dBase_Header


class dBase_Feld {
    public String FeldStr;      // Feldname   aber nur Grossbuchstaben  11 Zeichen
    public char cTyp;           //Feldtyp  C=String; N=Zahl; D=Datum; L=Boolean
    private byte  dummy1[] = new byte[4];

    public int  fieldsize;           // Feldlaenge byte
    public int  nk;             // Nachkommastellen byte
    private byte  dummy2[] = new byte[14];
    public  int offset;  // speichert den Offset jedes Feldes
                     // eventuell zum zurückschreiben

     public void loadFromFile(DataInputStream Din) {
         byte b, b1, b2;
         char ch;
         int i, i1,i2;
         try {
           FeldStr="";
           // offset = Din.
           for (i=0; i<11;i++) {
             ch = (char) Din.readByte();  // kein Unicode, Char
             if (ch>0) FeldStr+=ch;  // mit Zeichen Null am Ende
           }
           cTyp = (char) Din.readByte();

           for (i=0; i<dummy1.length; i++) {
             b = Din.readByte();  // Vorzeichenbehaftet
           }

           i1 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i1<0)  i1+=256;
           fieldsize = i1;


           i1 = (int) Din.readByte();  // Vorzeichenbehaftet
           if (i1<0)  i1+=256;
           nk = i1;

           for (i=0; i<dummy2.length; i++) {
             b = Din.readByte();  // Vorzeichenbehaftet
           }

         }
         catch (IOException ee) {
            System.err.println("IOException: " + ee);
         }
     }

     public String toString() {
         return FeldStr;
     }

}



class Item {
 private String _sName;
 private String _sItem;

  public Item( String sName, String sItem) {
    _sName = sName;
    _sItem = sItem;
  }

  public String getName() {
    return _sName;
  }

  public String getItem() {
    return _sItem;
  }

  public String toString() {
    return _sName;
  }

}


// dient zum Auslesen des Programmverzeichnis
class CProperties {

    // liefert  /  oder \
    public static String getfileSeparator() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("file.separator");  
        return sErg;
    }  // getfileSeparator

    // liefert  :
    public static String getpathSeparator() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("path.separator");
        return sErg;
    }  // getpathSeparator

    
    // liefert  \n  bzw. \r\n
    public static String getlineSeparator() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("line.separator");
        return sErg;
    }  // getlineSeparator


  	        
    // c:\einstellungen  oder /home
    public static String getuserHome() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("user.home");
        return sErg;
    }  // getuserHome
                

    
    public static String getuserName() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("user.name");
        return sErg;
    }  // getpathSeparator
                

     // aktuelle Verzeichnis  System.getProperties("user.dir");
    public static String getuserDir() {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get("user.dir");
        return sErg;
    }  // getuserDir


    // liefert  alles
    public static String getpathParam(String sParam) {
        java.util.Properties pHash = System.getProperties();
        String sErg = (String) pHash.get(sParam);
        return sErg;
    }  // getpathParam




}  // CCProperties


