// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@

package example;

import java.awt.*;
import java.beans.DefaultPersistenceDelegate;
import java.beans.Encoder;
import java.beans.Statement;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public final class MainPanel extends JPanel {
  private MainPanel() {
    super(new BorderLayout());
    String[] columnNames = {"A", "B"};
    Object[][] data = {
      {"aaa", "ccccccc"}, {"bbb", "☀☁☂☃"}
    };
    DefaultTableModel model = new DefaultTableModel(data, columnNames);
    JTable table = new JTable(model);

    JTextArea textArea = new JTextArea();

    JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
    sp.setResizeWeight(.5);
    sp.setTopComponent(new JScrollPane(table));
    sp.setBottomComponent(new JScrollPane(textArea));

    JButton encButton = new JButton("XMLEncoder");
    encButton.addActionListener(e -> {
      try {
        File file = File.createTempFile("output", ".xml");
        // try (XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(file)))) {
        try (XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(Files.newOutputStream(file.toPath())))) {
          xe.setPersistenceDelegate(DefaultTableModel.class, new DefaultTableModelPersistenceDelegate());
          // xe.setExceptionListener(new ExceptionListener() {
          //   @Override public void exceptionThrown(Exception ex) {
          //     // XXX: ex.printStackTrace();
          //   }
          // });
          DefaultTableModel m = (DefaultTableModel) table.getModel();
          xe.writeObject(m);
          // xe.flush();
          // xe.close();
        }
        // try (Reader r = new BufferedReader(new InputStreamReader(
        //                                    new FileInputStream(file), StandardCharsets.UTF_8))) {
        try (Reader r = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
          textArea.read(r, "temp");
        }
      } catch (IOException ex) {
        ex.printStackTrace();
        textArea.setText(ex.getMessage());
      }
    });

    JButton decButton = new JButton("XMLDecoder");
    decButton.addActionListener(e -> {
      String text = textArea.getText();
      if (text.isEmpty()) {
        return;
      }
      byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
      try (XMLDecoder xd = new XMLDecoder(new BufferedInputStream(new ByteArrayInputStream(bytes)))) {
        DefaultTableModel m = (DefaultTableModel) xd.readObject();
        table.setModel(m);
      }
    });

    JButton clearButton = new JButton("clear");
    clearButton.addActionListener(e -> table.setModel(new DefaultTableModel()));

    JPanel p = new JPanel();
    p.add(encButton);
    p.add(decButton);
    p.add(clearButton);

    add(sp);
    add(p, BorderLayout.SOUTH);
    setPreferredSize(new Dimension(320, 240));
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(MainPanel::createAndShowGui);
  }

  private static void createAndShowGui() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
      ex.printStackTrace();
      Toolkit.getDefaultToolkit().beep();
    }
    JFrame frame = new JFrame("@title@");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

// http://web.archive.org/web/20090806075316/http://java.sun.com/products/jfc/tsc/articles/persistence4/
// http://www.oracle.com/technetwork/java/persistence4-140124.html
class DefaultTableModelPersistenceDelegate extends DefaultPersistenceDelegate {
  @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
  @Override protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder encoder) {
    super.initialize(type, oldInstance, newInstance, encoder);
    DefaultTableModel m = (DefaultTableModel) oldInstance;
    // Vector v = m.getDataVector();
    // for (int i = 0; i < m.getRowCount(); i++) {
    //   encoder.writeStatement(new Statement(oldInstance, "addRow", new Object[] { (Vector) v.get(i) }));
    // }
    for (int row = 0; row < m.getRowCount(); row++) {
      for (int col = 0; col < m.getColumnCount(); col++) {
        Object[] o = {m.getValueAt(row, col), row, col};
        encoder.writeStatement(new Statement(oldInstance, "setValueAt", o));
      }
    }
  }
}

@@ -777,15 +777,18 @@
 %22, %22
-ccccccc
+1234567890
 %22%7D, 
@@ -818,34 +818,34 @@
     
-DefaultTableModel model = 
+JTable table = new JTable(
 new 
@@ -884,45 +884,8 @@
 mes)
-;%0A    JTable table = new JTable(model
 );%0A%0A
@@ -1132,24 +1132,27 @@
  JButton enc
+ode
 Button = new
@@ -1182,16 +1182,19 @@
 %0A    enc
+ode
 Button.a
@@ -2421,24 +2421,27 @@
  JButton dec
+ode
 Button = new
@@ -2471,16 +2471,19 @@
 %0A    dec
+ode
 Button.a
@@ -3044,16 +3044,19 @@
 .add(enc
+ode
 Button);
@@ -3069,16 +3069,19 @@
 .add(dec
+ode
 Button);
@@ -3105,17 +3105,16 @@
 utton);%0A
-%0A
     add(

better variable name