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

public class Feditor
  extends JPanel
  implements ActionListener{
  static JFrame frame;
  JPanel pnl1;
  JMenu menuFile;
  JMenu menuView;
  Image img;
  byte[] abText;
  int COLS= 64;
  int MAXROWS= 16 * 2; // 64 * 16 * 2 = 2K
  int nRowsOff;
  Font font;
  FontMetrics fm;
  int ROWSIZE;
  int COLSIZE;
  //----------------------------------------------------------------------------

  Feditor(String sFile){
    loadText(sFile);
    frame= new JFrame("Feditor");
    createMenu();
    frame.getContentPane().setLayout(new BorderLayout());
    frame.addWindowListener(new WindowAdapter(){
      /** Als je het window sluit, wil je dat het programma stopt. */
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
    });
    addVisibleElements();
    frame.getContentPane().add(this, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
    draw(pnl1);
    frame.pack();
  }
  //----------------------------------------------------------------------------

  void loadText(String sFile){
    try{
      FileInputStream fis= new FileInputStream(sFile);
      abText= new byte[fis.available()];
      fis.read(abText);
    } catch(Exception e){
      System.err.println(sFile + ": " + e);
    }
  }

  //----------------------------------------------------------------------------
  void createMenu(){
    JMenuBar bar= new JMenuBar();
    menuFile= new JMenu("Bestand");
    menuFile.setMnemonic(java.awt.event.KeyEvent.VK_B);
    addMenuItem(menuFile, "Opslaan").setEnabled(false);
    menuFile.addSeparator();
    addMenuItem(menuFile, "Sluiten");
    menuView= new JMenu("Beeld", true);
    menuView.setMnemonic(java.awt.event.KeyEvent.VK_D);
    addMenuItem(menuView, "Begin").
        setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0));
    addMenuItem(menuView, "Vorige").
        setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0));
    addMenuItem(menuView, "Volgende").
        setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0));
    addMenuItem(menuView, "Eind").
        setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0));
    bar.add(menuFile);
    bar.add(menuView);
    frame.setJMenuBar(bar);
  }
  //----------------------------------------------------------------------------

  JMenuItem addMenuItem(JMenu menu, String sItem){
    JMenuItem item= new JMenuItem(sItem);
    item.addActionListener(this);
    menu.add(item);
    return item;
  }
  //----------------------------------------------------------------------------

  /**
   *  Hier maken we alle tekstregels op dit frame.
   */
  void addVisibleElements(){
    setLayout(new BorderLayout());
    pnl1= new JPanel();
    // nu we het panel hebben, kunnen we afmetingen aanpassen op het lettertype
    font= new Font("Monospace", 0, 12);
    fm= pnl1.getFontMetrics(font);
    ROWSIZE= fm.getMaxAscent() + fm.getMaxDescent() + 1;
    COLSIZE= fm.charWidth('W') + 1;
    pnl1.setPreferredSize(new Dimension(COLSIZE * (COLS + 1), 600));
    pnl1.setLayout(new BorderLayout());
    add(pnl1, BorderLayout.CENTER);
  }
  //----------------------------------------------------------------------------

  public void actionPerformed(ActionEvent e){
    Object o= e.getSource();
    if (o instanceof JMenuItem){
      String sCmd= ((JMenuItem) o).getText();
      if (sCmd.equals("Sluiten")){
        System.exit(0);
      } else if (sCmd.equals("Opslaan")){
        savePng();
      } else if (sCmd.equals("Begin")){
        nRowsOff = 0;
        draw(pnl1);
      } else if (sCmd.equals("Vorige")){
        if (nRowsOff <= 0){
          return;
        }
        nRowsOff -= MAXROWS;
        draw(pnl1);
      } else if (sCmd.equals("Volgende")){
        if (nRowsOff + MAXROWS > abText.length / COLS){
          return;
        }
        nRowsOff += MAXROWS;
        draw(pnl1);
      } else if (sCmd.equals("Eind")){
        nRowsOff= (abText.length / COLS / MAXROWS) * MAXROWS;
        draw(pnl1);
      }
    }
  }
  //----------------------------------------------------------------------------

  public static void main(String[] asArg){
    Feditor frame= new Feditor(asArg[0]);
  }
  //----------------------------------------------------------------------------

  void savePng(){
    /*
    try{
      FileOutputStream fosPng= new FileOutputStream("Feditor.png");
      BufferedImage BufImg= toBufferedImage(img);
      PngEncoderB pngEnc= new PngEncoderB(BufImg, PngEncoder.NO_ALPHA, PngEncoder.FILTER_NONE, 9);
      byte[] abBytes= pngEnc.pngEncode(false);
      fosPng.write(abBytes);
      fosPng.flush();
      fosPng.close();
    } catch(Exception e){
      e.printStackTrace();
    }
    */
  }
  //----------------------------------------------------------------------------
  BufferedImage toBufferedImage(Image image){
    BufferedImage bufferedImage = new BufferedImage(
        image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
    // Copy image to buffered image.
    Graphics g = bufferedImage.createGraphics();
    // Clear background and paint the image.
    g.setColor(Color.white);
    g.fillRect(0, 0, image.getWidth(null), image.getHeight(null));
    g.drawImage(image, 0, 0, null);
    g.dispose();
    return bufferedImage;
  }
  //----------------------------------------------------------------------------

  /**
   *  Teken alles op het gegeven paneel
   */
  void draw(JPanel p){
    int nCols= COLS;
    int nRows= (abText.length + nCols - 1) / nCols;
    nRows= Math.min(MAXROWS, nRows);
    int iImgHeight= nRows * ROWSIZE;
    int iImgWidth= nCols * COLSIZE;
    if (img==null){
      img= this.createImage(iImgWidth, iImgHeight);
      JLabel lbl= new JLabel();
      ImageIcon icon= new ImageIcon(img);
      lbl.setIcon(icon);
      p.add(new JScrollPane(lbl), BorderLayout.CENTER);
    }
    Graphics g= img.getGraphics();
    g.setFont(font);
    g.setColor(Color.white);
    g.fillRect(0, 0, iImgWidth, iImgHeight);

    // teken 1 frame:
    for (int i= (nRowsOff * COLS); 
        i < abText.length && i - (nRowsOff * COLS) < nRows * COLS; i++){
      int iRow= (i -(nRowsOff * COLS)) / COLS;
      int iCol= (i -(nRowsOff * COLS)) % COLS;
      byte c= abText[i];

      g.setColor(new Color(220, 220, 220));
      g.drawRect(iCol * COLSIZE, iRow * ROWSIZE, COLSIZE, ROWSIZE);

      if (c < -64){
        g.setColor(new Color(192, 255, 128)); // groen
        g.fillRect(iCol * COLSIZE + 1, iRow * ROWSIZE + 1, COLSIZE - 1, ROWSIZE - 1);
        c+= (128 + 64);
        g.setColor(Color.black);
      } else if (c < 0){
        g.setColor(new Color(255, 255, 128)); // geel
        g.fillRect(iCol * COLSIZE + 1, iRow * ROWSIZE + 1, COLSIZE - 1, ROWSIZE - 1);
        c+= (64 + 64);
        g.setColor(Color.black);
      } else if (c < 32){
        g.setColor(new Color(255, 192, 192)); // rood
        g.fillRect(iCol * COLSIZE + 1, iRow * ROWSIZE + 1, COLSIZE - 1, ROWSIZE - 1);
        c+= 64;
        g.setColor(Color.white);
      } else if (c > 127){ // komt niet voor
        g.setColor(new Color(220, 220, 255)); // lichtblauw
        g.fillRect(iCol * COLSIZE + 1, iRow * ROWSIZE + 1, COLSIZE - 1, ROWSIZE - 1);
        g.setColor(Color.black);
      } else{
        g.setColor(Color.black);
      }
      Character cOut= new Character((char) c);
      g.drawString("" + cOut, 
          iCol * COLSIZE + (COLSIZE - fm.charWidth(cOut.charValue())) / 2, 
          (iRow + 1) * ROWSIZE - fm.getMaxDescent());
    }
    p.repaint();
  }
  //----------------------------------------------------------------------------

} // class Feditor
//------------------------------------------------------------------------------

