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

// Packages fuer Opendialog
import javax.swing.JFileChooser;

import java.io.*;

import java.awt.FontMetrics.*;


import javax.swing.plaf.metal.*;  // look and Feel

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

import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

// ca. 1000 Zeilen (ohne Basis, Excel)

public class HexEditor extends JFrame implements ActionListener, IInsertFile {
  private final int FONTSIZE = 14;
  
  private JMenuBar menuBar1;  // MenueContainer
  private JMenu mainFile;     
  private JMenuItem mnOpen;   
  private JMenuItem mnClose;  

  private JMenu mainEdit;     
  private JMenuItem mnDeleteTab; 

  private JMenu mainExport;
  private JMenuItem mnExport2Biff; 

  private JMenu mainView;
  private JMenuItem mnSearchDialog; 
  
  private JMenu mainLook_Feel;
  private JMenuItem mnLook_Feel_Windows;
  private JMenuItem mnLook_Feel_Motif;
  private JMenuItem mnLook_Feel_Metal;
  private JMenuItem mnLook_Feel_Nimbus;
   
  
  
  private JTabbedPane jTabbedPane1;

  private JComboBox comboFont;
  
    public HexEditor() {
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    setGUI();
    setMenus();
  }

  private void setGUI() {
    setSize(800, 430);
    setTitle("Hexeditor");

    //JTextArea e = new JTextArea();
    
    this.getContentPane().setLayout( new BorderLayout() );
    jTabbedPane1 = new JTabbedPane();
    jTabbedPane1.setFont( new Font("Arial", Font.BOLD,18));

   
    //jpanelGrf.setBackground(Color.red);
    this.getContentPane().add( jTabbedPane1, BorderLayout.CENTER);

    JPanel jpanelTop= new JPanel();
    jpanelTop.setLayout( new GridBagLayout() );
    JLabel label1 = new JLabel("Fontgroessee: ");

    comboFont = new JComboBox();
    for (int i=8; i<36; i+=2) {      
      comboFont.addItem( Integer.toString(i) );
    }
    label1.setFont( new Font("Arial", Font.BOLD,FONTSIZE));
    comboFont.setFont( new Font("Arial", Font.BOLD,FONTSIZE));

    jpanelTop.add(label1,
       new GridBagConstraints(
           0, 0, 1, 1, 0.0, 0.0
      ,GridBagConstraints.WEST,
      GridBagConstraints.NONE,
         new Insets(0,0,20,20), 0, 0));

    jpanelTop.add(comboFont,
       new GridBagConstraints(
           1, 0, 1, 1, 100.0, 0.0
      ,GridBagConstraints.WEST,
      GridBagConstraints.HORIZONTAL,
         new Insets(0,0,20,20), 0, 0));

    comboFont.setSelectedIndex( 3 );
    comboFont.addActionListener(
     new java.awt.event.ActionListener() {
       @Override
      public void actionPerformed(ActionEvent e) {
        comboFont_click();
      }
    });

    this.getContentPane().add( jpanelTop, BorderLayout.NORTH);
  } // setGUI

    // setzt die Menues
  private void setMenus() {
    menuBar1 = new JMenuBar();

      // DATEI
    mainFile = new JMenu("Datei");
    mnOpen = new JMenuItem("Oeffnen");
    mnClose = new JMenuItem("Schliessen");


     mnOpen.addActionListener( this );
     mnClose.addActionListener( this );
    
      // Event definieren
      // Short Key definieren  STRG+O
    mnOpen.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
    mainFile.add(mnOpen);
    mainFile.addSeparator();

    mainFile.add(mnClose);

      // Hauptmenue FILE in den MenueBar einfuegen
    menuBar1.add(mainFile);

    mainEdit = new  JMenu("Bearbeiten");
    mnDeleteTab = new JMenuItem("Loeschen des aktuellen Registers");

    
    mainEdit.add(mnDeleteTab);
    menuBar1.add(mainEdit);
    mnDeleteTab.addActionListener( this );
    

    mainExport = new JMenu("Export");
    mnExport2Biff = new JMenuItem("Export 2 Excel (BIFF)") ;
    mainExport.add(mnExport2Biff);
    menuBar1.add(mainExport);
    mnExport2Biff.addActionListener( this );
    
    
  
    mainView = new JMenu("Ansicht");
    mnSearchDialog = new JMenuItem("Auswahldialog") ;
    mainView.add(mnSearchDialog);
    menuBar1.add(mainView);
    mnSearchDialog.addActionListener( this );
    
    
    mainLook_Feel = new JMenu("Look & Feel");
    mnLook_Feel_Windows = new JMenuItem("Windows");
    mainLook_Feel.add(mnLook_Feel_Windows);


    mnLook_Feel_Motif = new JMenuItem("Motif");
    mainLook_Feel.add(mnLook_Feel_Motif);
    mnLook_Feel_Metal = new JMenuItem("Metal");
    mainLook_Feel.add(mnLook_Feel_Metal);
    mnLook_Feel_Nimbus = new JMenuItem("Nimbus");
    mainLook_Feel.add(mnLook_Feel_Nimbus);
    menuBar1.add(mainLook_Feel);
    
    mnLook_Feel_Windows.addActionListener( this );
    mnLook_Feel_Motif.addActionListener( this );
    mnLook_Feel_Metal.addActionListener( this );
    mnLook_Feel_Nimbus.addActionListener( this );
    
    this.setJMenuBar(menuBar1);
    
    for (int i=0; i<menuBar1.getMenuCount(); i++) {
      JMenu main = menuBar1.getMenu(i);
      main.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );      
      JMenuItem mn;
      for (int j=0; j<main.getItemCount(); j++) {
        mn = main.getItem(j);
        // Abfrage auf Separator, sonst Absturz
        if ( mn instanceof JMenuItem )
          mn.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
      }
    }
    
  } // setMenus


    public void actionPerformed(ActionEvent e) {
         JMenuItem mn = (JMenuItem) e.getSource();
         if (mn.equals(mnOpen)) {
             MnOpen_Click();
             return;
         }
         if (mn.equals(mnClose)) {
            this.dispose();
             return;
         }
         if (mn.equals(mnDeleteTab)) {
           DeleteTab();
             return;
         }
         
         if (mn.equals(mnExport2Biff)) {
                Export2BIFF();
                return;         
         }
         if (mn.equals(mnSearchDialog)) {
                SearchDialog();
                return;        
         }
         
         if (mn.equals(mnLook_Feel_Windows) ){
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                SwingUtilities.updateComponentTreeUI(this.getContentPane() );  // alles neuzeichnen
                return;
            }
            catch (Exception elook) {
            }
         }
         
         if (mn.equals(mnLook_Feel_Motif)) {
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
                SwingUtilities.updateComponentTreeUI(this.getContentPane() );  // alles neuzeichnen
                return;
            }
            catch (Exception elook) {
            }
         }
         if (mn.equals(mnLook_Feel_Metal)) {
            try {
                UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
                SwingUtilities.updateComponentTreeUI(this.getContentPane() );  // alles neuzeichnen
                return;
            }
            catch (Exception elook) {
            }
         }
         if (mn.equals(mnLook_Feel_Nimbus)) {
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                SwingUtilities.updateComponentTreeUI(this.getContentPane() );  // alles neuzeichnen
                return;
            }
            catch (Exception elook) {
            }
         }
         

     }

   private void comboFont_click() {
     int i = comboFont.getSelectedIndex();
     if (i>=0) {
      System.out.println(8+i+i);      
      int n = jTabbedPane1.getTabCount();
      for (int j=0; j<n; j++) {
          HexPanel hexpanel = (HexPanel) jTabbedPane1.getComponentAt(j);  // getTabComponentAt(j);
          hexpanel.setFontSize(8+i+i);
      }
      //jTabbedPane1.getSelectedIndex();
          // jTabbedPane1.removeTabAt(i);
     // hexpanel.setFontSize(8+i+i);
     // hexpanel.updateUI();
     }
   }
   
   private void SearchDialog() {
       SelectView frame = new SelectView(this);
       frame.setVisible(true);  // JDialog waere modal
   }
   
   private void Export2BIFF() {
      int i = jTabbedPane1.getSelectedIndex();  // -1  bedeutet  kein Register ausgewaehlt
      if (i>=0) {
            JFileChooser jFileChooser1 = new JFileChooser();
            String sFilename;
            // setzen der Optionen
            jFileChooser1.setMultiSelectionEnabled(false);
            jFileChooser1.setCurrentDirectory(  new File(  (String) System.getProperties().get("user.dir")  )   );

            // Aufruf des Dialogfensters
            if (JFileChooser.APPROVE_OPTION == jFileChooser1.showSaveDialog(this)) {
                // holen des Dateinamens
              sFilename = jFileChooser1.getSelectedFile().getPath();
              HexPanel hexpanel = (HexPanel) jTabbedPane1.getComponentAt(i); 
              hexpanel.Export2BIFF(sFilename);
            }
      }

   }

   
  private void DeleteTab() {
      int i = jTabbedPane1.getSelectedIndex();  // -1  bedeutet  kein Register ausgewaehlt
      if (i>=0) {
          jTabbedPane1.removeTabAt(i);
      }
  }
   

  void MnOpen_Click() {
   JFileChooser jFileChooser1 = new JFileChooser();
   String sFilename;
     // setzen der Optionen
   jFileChooser1.setMultiSelectionEnabled(false);
   jFileChooser1.setCurrentDirectory(  new File(  (String) System.getProperties().get("user.dir")  )   );

      // Aufruf des Dialogfensters
    if (JFileChooser.APPROVE_OPTION == jFileChooser1.showOpenDialog(this)) {
        // holen des Dateinamens
      sFilename = jFileChooser1.getSelectedFile().getPath();
      insertFile(sFilename);
    }
  }  // MnOpen
  
  
   public void insertFile(String sFilename) {
      HexPanel hexpanel = new HexPanel(sFilename);      
      hexpanel.updateUI();
      jTabbedPane1.add( Basis.getFileNameExt(sFilename) ,  hexpanel);      
      hexpanel.loadFile(sFilename);             
      jTabbedPane1.setSelectedIndex(  jTabbedPane1.getTabCount()-1   );
   }


    public static void main(String[] args) {
        HexEditor frame = new HexEditor();
        frame.setVisible(true);
    System.out.println("ssss");
    }
}



class HexFile {
  private String _sFilename="";
  private long  _filesize = 0;

  public HexFile(String sFilename) {
      this._sFilename =sFilename;
  }

  public void loadFile(String sFilename) {
    this._sFilename =sFilename;
    File file = new File(sFilename);
    _filesize = file.length();
    System.out.println(_filesize);
  }

  public byte[] loadRow(int offset, int count) {
    byte [] feld = new byte[count];    
    try {       
       RandomAccessFile fin =  new RandomAccessFile(_sFilename, "r");
       if (offset>0) fin.seek(offset);
       
       int anz = fin.read(feld, 0, count);
       fin.close();
       if (anz!=feld.length) {  // letzter Rest oder EOF
         if (anz==-1) {            
            return null;
         }
         else {
             // wenn man am Ende zu wenig Bytes gelesen hat, muss ein neues Feld her
           byte [] feld2 = new byte[anz];
           for (int i=0; i<anz; i++) {
             feld2[i] = feld[i];
           }
           return feld2;
        }
       }
       else {
         return feld;
       }
    }
    catch (IOException ee) {
           System.err.println("IOException: " + ee);          
    }
    return null;
   }
  
    public String getFilename() {
        return _sFilename;
    }
    public long getFilesize() {
        return _filesize;
    }

} // HexFile


class HexPanel extends JPanel implements AdjustmentListener {
    Font f1 = new Font( "Courier New", Font.PLAIN, 14 ); // Courier New
    Font fMitte = new Font( "Verdana", Font.PLAIN, 14 ); // Courier New
    
    private Scrollbar _scrollbar;
    private int _fontsize=12;
    private HexFile _hexfile;
    private int _colCount=16;
    private int _offset=0;
    private int _linkerRand=0;
    private int _rechterRand=100;
    private int _rowHeight=10;
    private int _wFF=10;
    private boolean _bFirst=true;
    private int _blockRowCount=25;  // geschaetzt
    private String _sFilename;
    
   
  public HexPanel(String sFilename) {
    _sFilename = sFilename;
    setLayout( new BorderLayout() );
    _scrollbar = new Scrollbar(Scrollbar.VERTICAL);
    add( _scrollbar, BorderLayout.EAST);
    this._hexfile = new HexFile(sFilename);
    
    _scrollbar.setBlockIncrement(_colCount*25);
    _scrollbar.setUnitIncrement(1);                    
    _scrollbar.setMinimum(0);
    _scrollbar.setMaximum(100);  // geschaetzt
    _scrollbar.addAdjustmentListener(this);

    // initDatas();
  }
  
   public void loadFile(String sFilename) {
       _hexfile.loadFile(sFilename);
       long filesize = _hexfile.getFilesize();
       int lastrow = (int) Math.ceil((double)filesize / _colCount)-1;
        _scrollbar.setBlockIncrement(_colCount);
        _scrollbar.setUnitIncrement(1);
        _scrollbar.setMinimum(0);
        _scrollbar.setMaximum(lastrow);
        _scrollbar.setValue(0);
        _offset=0;
        System.out.println("lastrow: "+lastrow);
        initDatas();
   } // loadFile
   

   public void setFontSize(int size) {
     this._fontsize = size;
     f1 = new Font("Courier New", Font.PLAIN, size);  
     fMitte = new Font( "Verdana", Font.PLAIN, size ); // Courier New
     _bFirst = true;       
     initDatas();
     updateUI();
   }

   private void initDatas() {
     Graphics g = this.getGraphics();
     g.setFont(f1);
  
     FontMetrics fontMetrics = g.getFontMetrics(f1);
     _rowHeight = fontMetrics.getHeight();
     _linkerRand = fontMetrics.stringWidth("00000:_");
     _wFF = fontMetrics.stringWidth("FF ");
     _rechterRand = 10+_linkerRand+(_wFF<<4);
   }
     

  
   
 @Override
    public void adjustmentValueChanged(AdjustmentEvent e) {
        // throw new UnsupportedOperationException("Not supported yet.");
        System.out.println("Offset: "+_scrollbar.getValue() );
        _offset= _scrollbar.getValue()*_colCount;
        updateUI();
    }   

 @Override
 public void paint (Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    g.setFont(f1);
   
    g.setColor(Color.white);
    g.fillRect(0,0, getWidth(), getHeight() ); 
    if (_hexfile.getFilename().equals("")) {
      g.setColor(Color.blue);
      g.drawString( "Keine Datei ausgewählt", 10,_rowHeight<<1);
      return;
    }

    g.setColor( new Color(20,20,255) );
    int y=_rowHeight; // y ist immer unten
    int offset=_offset;
    int ii=0;
    if (_bFirst) _blockRowCount = 0;
    while ( (y)<getHeight() ) {
      byte[] feld = _hexfile.loadRow(offset, _colCount);
      if (feld==null)  break;
      
      String s = Integer.toHexString(offset).toUpperCase();
      while (s.length()<5) {
        s="0"+s;
      }
      g.setColor(Color.black);
      g.setFont(f1);
      g.drawString( s, 10,y);
      g.setColor(Color.blue);
      String sMitte="";
      String sRechts="";
      
      for (int i=0; i<feld.length; i++) {
          int value = (int) feld[i];  // Problem signed byte
          if (value<0) {
              value+=256;
          }
        s = Integer.toHexString( value ).toUpperCase();
        if (s.length()==1) s+="0";
        g.setFont(fMitte);
        g.drawString(s, 10+_linkerRand + _wFF*i,y); // zeichnen mittels TAB !
        sMitte+=s+" ";
        if ( value<32) // Sonderzeichen 
            sRechts+=".";
        else
            sRechts+=(char) value;
      }      
      // g.drawString( sMitte, 10+_linkerRand,y);
      
      g.setFont(f1);
      g.setColor(Color.black);
      g.drawString( sRechts, _rechterRand,y);
      
      
      y+=_rowHeight;
      offset+=_colCount;   
      ii++;      
      if (_bFirst) _blockRowCount++;
    }
    if (_bFirst)
    {
        _bFirst = false;    
        _scrollbar.setBlockIncrement( _blockRowCount);  // Anzahl der Zeilen pro Fenster
        System.out.println("_blockRowCount:"+_blockRowCount);
    }
  }  // paint

 
 
   public void Export2BIFF(String sFilename) {
      int COLCOUNT = 16;
      int offset=0;       
      
      long laenge = this._hexfile.getFilesize();
      int c = (int) laenge / COLCOUNT;  // maximal 60000 Zeilen
      if (c>60000) {
          // ceil rundet auf, immer Vielfache von 16
          int count = (int) Math.ceil( (double) laenge/60000.0   );  // z. B. 19
          // aufrunden auf Vielfache von 16
          COLCOUNT = (int) Math.ceil( count/16.0   )*16;  // z. B. 19 auf 32
      }     
      
      Export2BIFF excel = new Export2BIFF(sFilename);
      excel.openFile();
      
      excel.Write(0,0,sFilename); // col row Value
      excel.Write(0,1,"Adresse"); // col row Value
      for (int i=0; i<COLCOUNT; i++) {
          excel.Write(1+i, 1, i ); // col row Value
      }
      excel.Write(COLCOUNT+1, 1, "Text" ); // col row Value
      int row=1;
      while ( true ) {
        byte[] feld = _hexfile.loadRow(offset, COLCOUNT);
        if (feld==null)  break;
        row++;

        String sAdr = Integer.toHexString(offset).toUpperCase();
        while (sAdr.length()<5) { // oder mit Format
            sAdr="0"+sAdr;
        }
        excel.Write(0, row,sAdr); // col row Value
        
        String sMitte="";
        String sRechts="";

        for (int i=0; i<feld.length; i++) {
            int value = (int) feld[i];  // Problem signed byte
            if (value<0) {
                value+=256;
            }
            sMitte = Integer.toHexString( value ).toUpperCase();
            if (sMitte.length()==1) sMitte+="0";
            excel.Write(1+i,row,sMitte); // col row Value
            if ( value<32) // Sonderzeichen entfernen
                sRechts+=".";
            else
                sRechts+=(char) value;
        }      
        excel.Write(1+COLCOUNT,row, sRechts ); // col row Value
        offset+=COLCOUNT;   
      }
      
      excel.closeFile();
      StartExcel(sFilename);     
   }

    private void StartExcel(String sFilename) {
        String sExcel ="C:\\Program Files (x86)\\Microsoft Office\\Office14\\EXCEL.EXE";
        try {
        Runtime.getRuntime().exec(sExcel+" "+sFilename);
        }
        catch (IOException e1) {
        System.out.println("Error beim Starten von Excel");
        }
    }
   
}


interface IInsertFile {
        void insertFile(String sFilename);   
}



class SelectView  extends JFrame implements ActionListener {
    final int FONTSIZE = 14;
    
    
 
  private JMenuBar menuBar1;  // MenueContainer
  private JMenu mainFile;       
  private JMenuItem mnClose;  

  private JMenu mainRun;     
  private JMenuItem mnSearch;     
  private JMenuItem mnSearchThread;     
  private JLabel _statusbar;
    
    IInsertFile _parent; 
    
    JTextField _startverz = new JTextField();
    JComboBox _masken = new JComboBox();
    
    DefaultListModel _fileListModel = new DefaultListModel();
     JList _filelist = new JList( _fileListModel );
     
     JTextArea _editorTop = new JTextArea();
     
     CardLayout _cardLayout = new CardLayout(10,10);
     JPanel _panelCardLayout = new JPanel();
     
     JTextArea _previewEditor = new JTextArea();
     JLabel  _previewPictFile = new JLabel ();
     
     String _selectFile="";
     String [] _sMaskenArray;
    
    public SelectView (IInsertFile parent) {
        _parent = parent;  
        setSize(650,500);
        setLocation(150,150);
        setTitle("Suchen und Auswahl von Dateien");
        setGUI();
        setMenus();
    }
    
    private void setGUI() {
       setLayout( new GridBagLayout() );
       
       _filelist.setSelectionMode( ListSelectionModel.SINGLE_SELECTION);

       
        _masken.addItem("*.*");
        _masken.addItem("*.jpg;*.jpeg;*.bmp;*.png;*.gif;*.tif;*.emf;*.wmf");
        _masken.addItem("*.jpg;*.jpeg");
        _masken.addItem("*.bmp");
        _masken.addItem("*.png");
        _masken.addItem("*.tif");
        _masken.addItem("*.gif");
        _masken.addItem("*.exe");
        _masken.addItem("*.txt;.dat");
        _masken.addItem("*.cs");
        _masken.addItem("*.java");
        _masken.addItem("*.html;*.xhtml;*.css;*.php");
        _masken.addItem("*.dbf;*.mdb");
        _masken.setSelectedIndex(0);
        _masken.setEditable(true);
       
       JLabel lstartverz = new JLabel("Startverzeichnis");
       JLabel lmaske = new JLabel("Dateimaske");
       add( lstartverz,
               new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0
               ,GridBagConstraints.WEST, GridBagConstraints.NONE,
             new Insets(10,0,20,20), 0, 0));
       add( _startverz,
               new GridBagConstraints( 1, 0, 1, 1, 100.0, 0.0
               ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
             new Insets(10,0,20,20), 0, 0));
        
       add( lmaske,
               new GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0
               ,GridBagConstraints.WEST, GridBagConstraints.NONE,
             new Insets(0,0,20,20), 0, 0));
       add( _masken,
               new GridBagConstraints( 1, 1, 1, 1, 100.0, 0.0
               ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
             new Insets(0,0,20,20), 0, 0));

       
    lstartverz.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    lmaske.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    _startverz.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    _masken.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    _filelist.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    _editorTop.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
    _previewEditor.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
     
        
       _startverz.setText ( (String) System.getProperties().get("user.dir")  );
           
     _panelCardLayout.setLayout(_cardLayout);

  // Splitter  links=Baum   rechts=tabelle
    JSplitPane vertsplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,false,     
            new JScrollPane( new JScrollPane(_editorTop)), _panelCardLayout );
    vertsplit.setDividerLocation(200);
    JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,false,     
    new JScrollPane(_filelist), vertsplit );
    
    _panelCardLayout.add("editor", new JScrollPane(_previewEditor));
    _panelCardLayout.add("bild", new  JScrollPane(_previewPictFile) );
    split.setDividerLocation(150);
       
       add( split,
               new GridBagConstraints( 0, 2, 2, 1, 100.0, 100.0
               ,GridBagConstraints.WEST, GridBagConstraints.BOTH,
             new Insets(0,0,20,20), 0, 0));
     
       
     _statusbar = new JLabel();       
     add( _statusbar,
               new GridBagConstraints( 0, 3, 2, 1, 100.0, 0.0
               ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
             new Insets(0,0,20,20), 0, 0));
      _statusbar.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );      
      _statusbar.setForeground(Color.RED);
       
   _filelist.addListSelectionListener(
           new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {           
                    FileListClick(e);                    
                }
           }
    );
   
    _filelist.addMouseListener(new java.awt.event.MouseAdapter() {
          public void mouseClicked(MouseEvent e) {
          FileListMouseClick(e);
        }
       });   
       
    }  // setGUI
    
    
  private void setMenus() {
    menuBar1 = new JMenuBar();

      // DATEI
    mainFile = new JMenu("Datei");
    mnClose = new JMenuItem("Schließen");
    mnClose.addActionListener( this );
    mainFile.add(mnClose);

      // Hauptmenue FILE in den MenueBar einfÃ¼gen
    menuBar1.add(mainFile);

    mainRun = new  JMenu("Starten");
    mnSearch = new JMenuItem("Suchen der Dateien");
    mnSearch.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0));
    
    mnSearchThread = new JMenuItem("Suchen der Dateien (Thread)");
    mnSearchThread.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_F5, KeyEvent.CTRL_MASK));

    mainRun.add(mnSearch);
    mainRun.add(mnSearchThread);
    menuBar1.add(mainRun);
    mnSearch.addActionListener( this );
    mnSearchThread.addActionListener( this );
    
    
    this.setJMenuBar(menuBar1);
    
    for (int i=0; i<menuBar1.getMenuCount(); i++) {
      JMenu main = menuBar1.getMenu(i);
      main.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );      
      JMenuItem mn;
      for (int j=0; j<main.getItemCount(); j++) {
        mn = main.getItem(j);
        // Abfrage auf Separator, sonst Absturz
        if ( mn instanceof JMenuItem )
          mn.setFont( new Font("Arial", Font.BOLD,FONTSIZE)  );
      }
    }
    
  } // setMenus
  
  // http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
  
  
    public void actionPerformed(ActionEvent e) {
         JMenuItem mn = (JMenuItem) e.getSource();
         if (mn.equals(mnClose)) {
            this.dispose();
            return;
         }
         if (mn.equals(mnSearch)) {
             SearchFiles(false);
         }
         if (mn.equals(mnSearchThread)) {
             SearchFiles(true);
         }
    }    
    
    private void SearchFiles(boolean bWithThread) {
        String sStartPath = this._startverz.getText().trim();
        if ( sStartPath.equals("") ) {
            Basis.Error("Startverzeichnis", "Der Eintrag im Startverzeichnis ist leer");
        }
        if ( ! Basis.DirExists(sStartPath)  ) {
            Basis.Error("Startverzeichnis", "Der Eintrag im Startverzeichnis ist leer");
        }
        String sMasken = (String) _masken.getSelectedItem();
        _sMaskenArray = sMasken.split(";");                
        if ( sMasken.equals("") ) {
            Basis.Error("Dateimasken", "Der Eintrag im Masken ist leer");
        }
              
        //_fileListModel = new DefaultListModel();
        _fileListModel.clear();
        _filelist.setModel(_fileListModel);
        _selectFile="";
        if (bWithThread) 
            searchForFilesThread(sStartPath);
        else
            searchForFiles(sStartPath);
        
        _statusbar.setText("Anzahl der Einträge: "+_fileListModel.getSize());
        _statusbar.updateUI();
        
    }
    
    
    private void searchForFiles(String sPath) {
        File dir = new File( sPath );
        _statusbar.setText(sPath);
        _statusbar.updateUI();
        File[] items =  dir.listFiles(); // ohne Maske FilenameFiler  FileFilter);
        for (int i=0; i<items.length; i++) {
               if ( items[i].isFile() ) { 
                   String sExt = Basis.getFileExt( items[i].getName() ).toUpperCase();
                   if (_sMaskenArray.length==1  && _sMaskenArray[0].equals("*.*")) {
                       //_fileListModel.add(  _fileListModel.getSize(), new myFile(items[i].getAbsolutePath()) );
                       _fileListModel.add(  _fileListModel.getSize(), new myFile(items[i]) );
                       //_filelist.setModel(_fileListModel);
                       //System.out.println(items[i].getAbsolutePath());
                   }
                   else {
                    for (String sMaske : _sMaskenArray) {  
                        String sMaskeExt = Basis.getFileExt( sMaske ).toUpperCase();
                        if (sMaskeExt.equals(sExt))  {
                            _fileListModel.add(  _fileListModel.getSize(), new myFile(items[i]) );
                            break;
                        }
                    }
                   }
               }
            }
        for (int i=0; i<items.length; i++) {
               if ( items[i].isDirectory() ) {          
                  searchForFiles(  items[i].getPath()  );
               }
            }
    }  // searchForFiles
    
    
    private void searchForFilesThread(String sPath) {
        ThreadSearch thread = new ThreadSearch(sPath);
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(SelectView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    class ThreadSearch extends Thread {
        String _sPath="";
        public ThreadSearch(String sPath) {
            _sPath=sPath;
        }
        
        @Override
        public void run() {
            searchForFilesThread(_sPath);
        }
        
        private void searchForFilesThread(String sPath) {
            File dir = new File( sPath );
            _statusbar.setText(sPath);
            _statusbar.updateUI();
            File[] items =  dir.listFiles(); // ohne Maske FilenameFiler  FileFilter);
            for (int i=0; i<items.length; i++) {
                if ( items[i].isFile() ) { 
                    String sExt = Basis.getFileExt( items[i].getName() ).toUpperCase();
                    if (_sMaskenArray.length==1  && _sMaskenArray[0].equals("*.*")) {
                        _fileListModel.add(  _fileListModel.getSize(), new myFile(items[i]) );
                    }
                    else {
                        for (String sMaske : _sMaskenArray) {  
                            String sMaskeExt = Basis.getFileExt( sMaske ).toUpperCase();
                            if (sMaskeExt.equals(sExt))  {
                                _fileListModel.add(  _fileListModel.getSize(), new myFile(items[i]) );
                                //_filelist.updateUI();
                                //_filelist = new JList( _fileListModel  );
                                break;
                            }
                        }
                    }
                }
                }
            for (int i=0; i<items.length; i++) {
                if ( items[i].isDirectory() ) {          
                    searchForFiles(  items[i].getPath()  );
                }
            } // for
        }
       
   }
   
   private void FileListClick(ListSelectionEvent e) {
       if ( _filelist.getSelectedIndex()>=0) {
        myFile item = (myFile) _filelist.getSelectedValue();  //           e.getFirstIndex();
        if ( _selectFile != item.getAbsolutePath() ) {
            System.out.println("item: "+item);  // _selectFile
            String sItem="Verzeichnis:" +System.getProperty("line.separator");
            sItem+= item.getPath()+System.getProperty("line.separator");
            sItem+="Dateiname:";
            sItem+= item.getName()+System.getProperty("line.separator")+System.getProperty("line.separator");        

            sItem+= "Größe: "+item.length()+" Bytes"+System.getProperty("line.separator");
            _editorTop.setText(sItem);
            
            // Eintragen in die beiden Preview
            String sExt = Basis.getFileExt( item.getName() ).toUpperCase();
            if ( sExt.equals(".TXT") || sExt.equals(".DAT") || sExt.equals(".INI") || sExt.equals(".HTML")
                 || sExt.equals(".XHTML") ||  sExt.equals(".XML") || sExt.equals(".CSS")  || sExt.equals(".CSV") 
                 || sExt.equals(".PHP")  || sExt.equals(".JAVA") || sExt.equals(".CS")  ) {
                _cardLayout.show(_panelCardLayout,"editor");
                String sValue="";
                FileInputStream fin;
                InputStreamReader iin;
                LineNumberReader din;                
                try {
                    fin = new FileInputStream( item.getAbsolutePath() );
                    iin = new InputStreamReader(fin);
                    din = new LineNumberReader(iin);                    
                    while  ( din.ready()  ) {
                        sValue  += din.readLine()+System.getProperty("line.separator");                         
                    }                    
                }
                catch (IOException e2) {
                    System.err.println("IOException: " + e);
                }
                _previewEditor.setText(sValue);
                _previewEditor.setCaretPosition(0);  // Cursor steht am Anfang
            }
            else {                
                // Bitmap wird nicht standardmaessig unterstuetzt
                if (sExt.equals(".JPG") || sExt.equals(".JPEG") ||  sExt.equals(".PNG") ||  sExt.equals(".GIF")   ) {
                    _cardLayout.show(_panelCardLayout,"bild");
                    _previewPictFile.setIcon( loadIcon(item.getAbsolutePath(), item.getName() ) );
                }
                else {
                    _previewEditor.setText("Keine Anzeige");
                    _cardLayout.show(_panelCardLayout,"editor");
                }
            }
            _selectFile=item.getAbsolutePath();
        }
       }
   }
   
   private ImageIcon loadIcon(String name, String description) {
   	// String path = "images" + name;
   	String path = name;  // Hier eventuell den path eintragen
      return new ImageIcon(path, description);
  }



   private void FileListMouseClick(MouseEvent e) {
       if (e.getClickCount()==2) {
          myFile item = (myFile) _filelist.getSelectedValue();  //           e.getFirstIndex();
          _parent.insertFile( item.getAbsolutePath() );
           
       }
       
   }
   
   class myFile /*extends File*/ {
       File _item; 
       public myFile(File item) {
           _item = item;
       }
       
       //@Override
       public String toString() {
           //System.out.println(_item.getName());
         return _item.getName();  
       }
       
       public String getName() {
           return _item.getName();  
       }
       
       public String getAbsolutePath() {
           return _item.getAbsolutePath();  
       }
       
       public String getPath() {
           return _item.getPath();
       }
       
       public long length() {
           return _item.length();
       }
       
   }
   
   
    
}

class Basis {
    
    public static String getFileNameExt(String sFileName) {
        int k, n;
        n = sFileName.length();
        k = sFileName.lastIndexOf("\\");
        if (k == -1) {
            // test mit /
            k = sFileName.lastIndexOf("/");
            if (k == -1)
                return sFileName;
            else {
                  // beginIndex   endIndex
                return sFileName.substring(k+1, n); // ??????  n-1 ist zu klein            
            }
        }
        else {
              // beginIndex   endIndex
            return sFileName.substring(k+1, n); // ??????  n-1 ist zu klein                        
        }
    }  // getFileNameExt
    
    
    /**
    * description: Zeigt eine Fehlermeldung an   
    * @see Message, Yes-No, Yes-No-Esc, Ok-Esc
    *
    * @version     1.0  07.07.2002
    * @author      Michael Wilhelm HS Harz, FB AI
    * @param String sTitle, String sMessage
    * @return keinen
    * @exception keine
    */
  public static void Error( String sTitle, String sMessage) {
    JOptionPane.showConfirmDialog(null,sMessage,sTitle,
      JOptionPane.DEFAULT_OPTION,
      JOptionPane.ERROR_MESSAGE);  // Symbol
    /*  Optionen der Schalter:
         DEFAULT_OPTION    Ok
         YES_NO_OPTION
         YES_NO_CANCEL_OPTION
         OK_CANCEL_OPTION
     */
     /*  Symbole:
      ERROR_MESSAGE
      INFORMATION_MESSAGE
      WARNING_MESSAGE
      QUESTION_MESSAGE
      PLAIN_MESSAGE
     */

  } // Error

    /**
    * description: Zeigt eine Nachricht an   
    * @see Message, Yes-No, Yes-No-Esc, Ok-Esc
    *
    * @version     1.0  07.07.2002
    * @author      Michael Wilhelm HS Harz, FB AI
    * @param String sTitle, String sMessage
    * @return keinen
    * @exception keine
    */
  public static void Message( String sTitle, String sMessage) {
    JOptionPane.showConfirmDialog(null,sMessage,sTitle,
      JOptionPane.DEFAULT_OPTION,
      JOptionPane.INFORMATION_MESSAGE);  // Symbol
    /*  Optionen der Schalter:
         DEFAULT_OPTION    Ok
         YES_NO_OPTION
         YES_NO_CANCEL_OPTION
         OK_CANCEL_OPTION
     */
     /*  Symbole:
      ERROR_MESSAGE
      INFORMATION_MESSAGE
      WARNING_MESSAGE
      QUESTION_MESSAGE
      PLAIN_MESSAGE
     */

  } // Message

  
    /**
    * FileExists
    * description: prüft, ob die Datei existiert
    * @return boolean
    * @param String sFileName
    * @exception none
    * @version      1.1, 31.01.2006
    * @author Michael Wilhelm HS Harz, FB AI
    * @use Example
    * @see #CheckFileName
    * @see #ChangeFileExt
    * @see #getFileNameExt
    */
    public static boolean FileExists(String sFileName) {        
        try {
            // evnetuell kann auch f.pathSeparatorChar verwendet werden
            File f = new File(sFileName);
            if (f.exists())
                return f.isFile();
            else
                return false;
        }
        catch (Exception e) {
            return false;
        }
    }  // FileExists

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



    /**
    * description: holt die Extention eines Dateinamens (TXT bzw. DAT)
    * @see #CheckFileName
    * @see #changeFileExt
    *
    * @version     1.1  31.01.2006
    * @author Michael Wilhelm HS Harz, FB AI
    * @param String sFileName, String sExt
    * @return String
    * @exception keine
    * @see #CheckFileName
    * @see #ChangeFileExt
    * @see #getFileName extrahiert den Dateinamen ohne Pfad
    * @see #FileExists
    */
    // besser mit lastIndexOf(String str)
    public static String getFileExt(String sFileName) {
        int k, i, n;
        n = sFileName.length();
        // suche von hinten erstes Auftreten eines Punktes
        k = sFileName.lastIndexOf(".");
        if (k == -1) // kein Punkt vorhanden
            return new String("");
        else {
            // substring zählt von NULL
            // Anfangsindex   EndIndex
            String s;
            s = sFileName.substring(k, n);
            return sFileName.substring(k, n);
        }
    } // getFileExt
    
    

}


class Export2BIFF {

   // interne Varibalen fuer das Speichern
  private FileOutputStream _fout;
  private DataOutputStream _dout;
  private String _sFilename;

    // Felder  Beginn Ende  String  Int
  byte [] CXlsBof     = { 9, 8, 8, 0, 0, 0, 0x10, 0, 1, 0, 0, 0 };
  byte [] CXlsEof     = {0x0A, 0, 0, 0};
  byte [] CXlsString  = new byte[12];
  byte [] CXlsDouble  = new byte[10];
  byte [] CXlsInt     = new byte[10];  


  public Export2BIFF(String sFilename) {
    _sFilename = sFilename;
    ClearArrays();
  }  // Export2BIFF


  public void openFile() {
   try {
    _fout = new FileOutputStream(_sFilename);
    _dout = new DataOutputStream(_fout);
    for (int i=0; i<CXlsBof.length; i++) {
      _dout.writeByte(CXlsBof[i]);
    }
   }
   catch (IOException ee) {
         System.err.println("IOException: " + ee);
   }
  }  // Export2Modul


  public void closeFile() {
   try {
    for (int i=0; i<CXlsEof.length; i++) {
      _dout.writeByte(CXlsEof[i]);
    }
    _dout.close();
    _fout.close();
   }
   catch (IOException ee) {
         System.err.println("IOException: " + ee);
   }
  }  // close()


  public void ClearArrays() {
      // eigentlich sind das Word, unsigned short, 16 Bit, die Reihenfolge passt aber nicht
      // deshalb byteweise
     CXlsString[0] =  4;
     CXlsString[1] =  2;
     CXlsString[2] =  0;
     CXlsString[3] =  0;
     CXlsString[4] =  0;
     CXlsString[5] =  0;
     CXlsString[6] =  0;
     CXlsString[7] =  0;
     CXlsString[8] =  0;
     CXlsString[9] =  0;
     CXlsString[10]=  0;
     CXlsString[11]=  0;

      // eigentlich sind das Word, unsigned short, 16 Bit, die Reihgenfolge passt aber nicht
      // deshalb byteweise
     CXlsDouble[0] = 3;   
     CXlsDouble[1] = 2;
     CXlsDouble[2] = 14;
     CXlsDouble[3] = 0;
     CXlsDouble[4] = 0;
     CXlsDouble[5] = 0;
     CXlsDouble[6] = 0;
     CXlsDouble[7] = 0;
     CXlsDouble[8] = 0;
     CXlsDouble[9] = 0;

      // eigentlich sind das Word, unsigned short, 16 Bit, die Reihgenfolge passt aber nicht
      // deshalb byteweise
     CXlsInt[0] = 0x7E;
     CXlsInt[1] = 2;
     CXlsInt[2] = 10;
     CXlsInt[3] = 0;
     CXlsInt[4] = 0;
     CXlsInt[5] = 0;
     CXlsInt[6] = 0;
     CXlsInt[7] = 0;
     CXlsInt[8] = 0;
     CXlsInt[9] = 0;
  }  // ClearArrays


  

   // schreiben der Vorspann eines Int
  private void writeCXlsInt() {
   try {
    for (int i=0; i<CXlsInt.length; i++) {
      _dout.writeByte(CXlsInt[i]);
    }
   }
   catch (IOException e) {
         System.err.println("IOException: " + e);
   }
  }


  public void Write(int Col, int Row, int iValue) {
     short s;
     int v;
     byte i3,i2,i1,i0;
     try {
        ClearArrays();
        s = (short) (Row);
        CXlsInt[4] = (byte) (s & 255);  // 4 5   [2]
        CXlsInt[5] = (byte) ((s >> 8) & 255);  // 4 5   [2]
   
        s = (short) (Col);
        CXlsInt[6] = (byte) (s & 255);  // 6 7 [3]
        CXlsInt[7] = (byte) ((s >> 8) & 255);  // 6 7 [3]
        writeCXlsInt();
   
          // Trennung der Bytes, à Resim
        v = (iValue << 2) | 2;
        i0 = (byte) (v & 255);
        i1 = (byte) ((v >> 8) & 255);
        i2 = (byte) ((v >> 16) & 255);
        i3 = (byte) ((v >> 24) & 255);
        _dout.writeByte( i0 );
        _dout.writeByte( i1 );
        _dout.writeByte( i2 );
        _dout.writeByte( i3 );
     }
     catch (IOException e) {
         System.err.println("IOException: " + e);
     }
  }  // Write Int


   // schreiben der Vorspann eines double
  private void writeCXlsDouble() {
   try {
    for (int i=0; i<CXlsDouble.length; i++) {
      _dout.writeByte(CXlsDouble[i]);
    }
   }
   catch (IOException ee) {
         System.err.println("IOException: " + ee);
   }
  }


  // ein double-Wert wird genau verkehrt herum geschrieben
  // also extra schreiben, einlesen und neuschreiben
  public void Write(int Col, int Row, double dValue) {
     short s;
     int v;
     int i;
     byte [] bits = new byte[8];  
     PipedInputStream pipein;
     PipedOutputStream pipeout;
     DataOutputStream dout;

     try {
        ClearArrays();
        s = (short) (Row);
        CXlsDouble[4] = (byte) (s & 255);  // 4 5   [2]
        CXlsDouble[5] = (byte) ((s >> 8) & 255);  // 4 5   [2]
   
        s = (short) (Col);
        CXlsDouble[6] = (byte) (s & 255);  // 6 7 [3]
        CXlsDouble[7] = (byte) ((s >> 8) & 255);  // 6 7 [3]
        writeCXlsDouble();
        
        pipein = new PipedInputStream();
        pipeout = new PipedOutputStream();
        dout = new DataOutputStream(pipeout);
          // Erzeugen der Stream-Objekte zum Schreiben und Lesen

        pipeout.connect(pipein);   // Kopplung der Streams

        dout.writeDouble(dValue);
        pipein.read(bits, 0, bits.length);  // in dem Array wird gelesen, Startindex=0   Anzahl = 8
        pipein.close();
        dout.close();
        pipeout.close();

        for (i=bits.length-1; i>=0; i--) {
          _dout.writeByte( bits[i] );
        } 
 
        // _dout.writeDouble( Value );  // leider hier verkehrte Reihenfolge
     }
     catch (IOException e) {
         System.err.println("IOException: " + e);
     }
  }  // Write Double


   // schreiben der Vorspann eines String
  private void writeCXlsString() {
   try {
    for (int i=0; i<CXlsString.length; i++) {
      _dout.writeByte(CXlsString[i]);
    }
   }
   catch (IOException ee) {
         System.err.println("IOException: " + ee);
   }
  }


  public void Write(int Col, int Row, String sValue) {
   short len;
   short s;
   try {
     ClearArrays();
     len = (short) sValue.length() ;
    
     s = (short) (len+8);
     CXlsString[2] = (byte) (s & 255);  // 2 3   [1]   erst low dann high byte
     CXlsString[3] = (byte) ((s >> 8) & 255);  // 2 3

     
     s = (short) (Row);
     CXlsString[4] = (byte) (s & 255);  // 4 5   [2]
     CXlsString[5] = (byte) ((s >> 8) & 255);  // 4 5   [2]

     s = (short) (Col);
     CXlsString[6] = (byte) (s & 255);  // 6 7 [3]
     CXlsString[7] = (byte) ((s >> 8) & 255);  // 6 7 [3]

     s = (short) (len);
     CXlsString[10] = (byte) (s & 255);  // 10 11  [5]
     CXlsString[11] = (byte) ((s >> 8) & 255);  // 10 11  [5]
     writeCXlsString();
     for (int i=0; i<len; i++) {
      _dout.writeByte( (byte) sValue.charAt(i) );  // cahr ist unicopde, zwei Byte !
     }
   }
   catch (IOException ee) {
         System.err.println("IOException: " + ee);
   }
  }  // Write string



  // alle diese Konstanten sind nicht benutzt
   private final byte  BIFF12_DEFINEDNAME            = 0x27;
   private final short BIFF12_FILEVERSION            = 0x0180;
   private final short BIFF12_WORKBOOK               = 0x0183;
   private final short BIFF12_WORKBOOK_END           = 0x0184;
   private final short BIFF12_BOOKVIEWS              = 0x0187;
   private final short BIFF12_BOOKVIEWS_END          = 0x0188;
   private final short BIFF12_SHEETS                 = 0x018F;
   private final short BIFF12_SHEETS_END             = 0x0190;
   private final short BIFF12_WORKBOOKPR             = 0x0199;
   private final short BIFF12_SHEET                  = 0x019C;
   private final short BIFF12_CALCPR                 = 0x019D;
   private final short BIFF12_WORKBOOKVIEW           = 0x019E;
   private final short BIFF12_EXTERNALREFERENCES     = 0x02E1;
   private final short BIFF12_EXTERNALREFERENCES_END = 0x02E2;
   private final short BIFF12_EXTERNALREFERENCE      = 0x02E3;
   private final short BIFF12_WEBPUBLISHING          = 0x04A9;
   
   // Worksheet records
   private final byte BIFF12_ROW             = 0x00;
   private final byte BIFF12_BLANK           = 0x01;
   private final byte BIFF12_NUM             = 0x02;
   private final byte BIFF12_BOOLERR         = 0x03;
   private final byte BIFF12_BOOL            = 0x04;
   private final byte BIFF12_FLOAT           = 0x05;
   private final byte BIFF12_STRING          = 0x07;
   private final byte BIFF12_FORMULA_STRING  = 0x08;
   private final byte BIFF12_FORMULA_FLOAT   = 0x09;
   private final byte BIFF12_FORMULA_BOOL    = 0x0A;
   private final byte BIFF12_FORMULA_BOOLERR = 0x0B;
   private final byte BIFF12_COL             = 0x3C;
   private final short BIFF12_WORKSHEET       = 0x0181;
   private final short BIFF12_WORKSHEET_END   = 0x0182;
   private final short BIFF12_SHEETVIEWS      = 0x0185;
   private final short BIFF12_SHEETVIEWS_END  = 0x0186;
   private final short BIFF12_SHEETVIEW       = 0x0189;
   private final short BIFF12_SHEETVIEW_END   = 0x018A;
   private final short BIFF12_SHEETDATA       = 0x0191;
   private final short BIFF12_SHEETDATA_END   = 0x0192;
   private final short BIFF12_SHEETPR         = 0x0193;
   private final short BIFF12_DIMENSION       = 0x0194;
   private final short BIFF12_SELECTION       = 0x0198;
   private final short BIFF12_COLS            = 0x0386;
   private final short BIFF12_COLS_END        = 0x0387;
   private final short BIFF12_CONDITIONALFORMATTING = 0x03CD;
   private final short BIFF12_CONDITIONALFORMATTING_END = 0x03CE;
   private final short BIFF12_CFRULE          = 0x03CF;
   private final short BIFF12_CFRULE_END      = 0x03D0;
   private final short BIFF12_ICONSET         = 0x03D1;
   private final short BIFF12_ICONSET_END     = 0x03D2;
   private final short BIFF12_DATABAR         = 0x03D3;
   private final short BIFF12_DATABAR_END     = 0x03D4;
   private final short BIFF12_COLORSCALE      = 0x03D5;
   private final short BIFF12_COLORSCALE_END  = 0x03D6;
   private final short BIFF12_CFVO            = 0x03D7;
   private final short BIFF12_PAGEMARGINS     = 0x03DC;
   private final short BIFF12_PRINTOPTIONS    = 0x03DD;
   private final short BIFF12_PAGESETUP       = 0x03DE;
   private final short BIFF12_HEADERFOOTER    = 0x03DF;
   private final short BIFF12_SHEETFORMATPR   = 0x03E5;
   private final short BIFF12_HYPERLINK       = 0x03EE;
   private final short BIFF12_DRAWING         = 0x04A6;
   private final short BIFF12_LEGACYDRAWING   = 0x04A7;
   private final short BIFF12_COLOR           = 0x04B4;
   private final short BIFF12_OLEOBJECTS      = 0x04FE;
   private final short BIFF12_OLEOBJECT       = 0x04FF;
   private final short BIFF12_OLEOBJECTS_END  = 0x0580;
   private final short BIFF12_TABLEPARTS      = 0x0594;
   private final short BIFF12_TABLEPART       = 0x0595;
   private final short BIFF12_TABLEPARTS_END  = 0x0596;
   
   //SharedStrings records
   private final byte BIFF12_SI              = 0x13;
   private final short BIFF12_SST             = 0x019F;
   private final short BIFF12_SST_END         = 0x01A0;
   
   //Styles records
   private final byte BIFF12_FONT            = 0x2B;
   private final byte BIFF12_FILL            = 0x2D;
   private final byte BIFF12_BORDER          = 0x2E;
   private final byte BIFF12_XF              = 0x2F;
   private final byte BIFF12_CELLSTYLE       = 0x30;
   private final short BIFF12_STYLESHEET      = 0x0296;
   private final short BIFF12_STYLESHEET_END  = 0x0297;
   private final short BIFF12_COLORS          = 0x03D9;
   private final short BIFF12_COLORS_END      = 0x03DA;
   private final short BIFF12_DXFS            = 0x03F9;
   private final short BIFF12_DXFS_END        = 0x03FA;
   private final short BIFF12_TABLESTYLES     = 0x03FC;
   private final short BIFF12_TABLESTYLES_END = 0x03FD;
   private final short BIFF12_FILLS           = 0x04DB;
   private final short BIFF12_FILLS_END       = 0x04DC;
   private final short BIFF12_FONTS           = 0x04E3;
   private final short BIFF12_FONTS_END       = 0x04E4;
   private final short BIFF12_BORDERS         = 0x04E5;
   private final short BIFF12_BORDERS_END     = 0x04E6;
   private final short BIFF12_CELLXFS         = 0x04E9;
   private final short BIFF12_CELLXFS_END     = 0x04EA;
   private final short BIFF12_CELLSTYLES      = 0x04EB;
   private final short BIFF12_CELLSTYLES_END  = 0x04EC;
   private final short BIFF12_CELLSTYLEXFS    = 0x04F2;
   private final short BIFF12_CELLSTYLEXFS_END = 0x04F3;
   
   //Comment records
   private final short BIFF12_COMMENTS        = 0x04F4;
   private final short BIFF12_COMMENTS_END    = 0x04F5;
   private final short BIFF12_AUTHORS         = 0x04F6;
   private final short BIFF12_AUTHORS_END     = 0x04F7;
   private final short BIFF12_AUTHOR          = 0x04F8;
   private final short BIFF12_COMMENTLIST     = 0x04F9;
   private final short BIFF12_COMMENTLIST_END = 0x04FA;
   private final short BIFF12_COMMENT         = 0x04FB;
   private final short BIFF12_COMMENT_END     = 0x04FC;
   private final short BIFF12_TEXT            = 0x04FD;
   
   //Table records
   private final short BIFF12_AUTOFILTER      = 0x01A1;
   private final short BIFF12_AUTOFILTER_END  = 0x01A2;
   private final short BIFF12_FILTERCOLUMN    = 0x01A3;
   private final short BIFF12_FILTERCOLUMN_END= 0x01A4;
   private final short BIFF12_FILTERS         = 0x01A5;
   private final short BIFF12_FILTERS_END     = 0x01A6;
   private final short BIFF12_FILTER          = 0x01A7;
   private final short BIFF12_TABLE           = 0x02D7;
   private final short BIFF12_TABLE_END       = 0x02D8;
   private final short BIFF12_TABLECOLUMNS    = 0x02D9;
   private final short BIFF12_TABLECOLUMNS_END= 0x02DA;
   private final short BIFF12_TABLECOLUMN     = 0x02DB;
   private final short BIFF12_TABLECOLUMN_END = 0x02DC;
   private final short BIFF12_TABLESTYLEINFO  = 0x0481;
   private final short BIFF12_SORTSTATE       = 0x0492;
   private final short BIFF12_SORTCONDITION   = 0x0494;
   private final short BIFF12_SORTSTATE_END   = 0x0495;
   
   //QueryTable records
   private final short BIFF12_QUERYTABLE            = 0x03BF;
   private final short BIFF12_QUERYTABLE_END        = 0x03C0;
   private final short BIFF12_QUERYTABLEREFRESH     = 0x03C1;
   private final short BIFF12_QUERYTABLEREFRESH_END = 0x03C2;
   private final short BIFF12_QUERYTABLEFIELDS      = 0x03C7;
   private final short BIFF12_QUERYTABLEFIELDS_END  = 0x03C8;
   private final short BIFF12_QUERYTABLEFIELD       = 0x03C9;
   private final short BIFF12_QUERYTABLEFIELD_END   = 0x03CA;
   
   //Connection records
   private final short BIFF12_CONNECTIONS           = 0x03AD;
   private final short BIFF12_CONNECTIONS_END       = 0x03AE;
   private final short BIFF12_CONNECTION            = 0x01C9;
   private final short BIFF12_CONNECTION_END        = 0x01CA;
   private final short BIFF12_DBPR                  = 0x01CB;
   private final short BIFF12_DBPR_END              = 0x01CC;

}
