package control;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Objects;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

public class ControlPanel {
  static final class DataModel implements TableModel {
    private final int[] values;
    private final Runnable runnable;
    private TableModelListener modelListener;
    
    DataModel(int[] values, Runnable runnable) {
      this.values = values;
      this.runnable = runnable;
    }
    
    @Override
    public int getColumnCount() {
      return values.length;
    }
    @Override
    public int getRowCount() {
      return 1;
    }
    
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
      return values[columnIndex];
    }
    
    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
      values[columnIndex] = (Integer)aValue;
      runnable.run();
      if (modelListener == null) {
        return;
      }
      modelListener.tableChanged(new TableModelEvent(this, 0));
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      return true;
    }

    @Override
    public String getColumnName(int columnIndex) {
      return Integer.toString(columnIndex);
    }
    @Override
    public Class<?> getColumnClass(int columnIndex) {
      return Integer.class;
    }

    @Override
    public void addTableModelListener(TableModelListener l) {
      if (modelListener != null) {
        throw new IllegalStateException("model already registered");
      }
      this.modelListener = l;
    }
    @Override
    public void removeTableModelListener(TableModelListener l) {
      throw new UnsupportedOperationException();
    }
  }
  
  public static void show(int width, int height, String title, int[] values) {
    Objects.requireNonNull(title);
    Objects.requireNonNull(values);
    
    BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    
    @SuppressWarnings("serial")
    JComponent component = new JComponent() {
      @Override
      protected void paintComponent(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
      }
      
      @Override
      public Dimension getPreferredSize() {
        return new Dimension(width, height);
      }
    };
    
    CanvasArea area = new CanvasArea(width, height);
    Runnable runnable = () -> {
      Graphics2D graphics = buffer.createGraphics();
      try {
        area.inject(graphics);
        Main.callback(area);  //FIXME hard coded dependency
      } finally {
        area.inject(null);
        graphics.dispose();
      }
      component.paintImmediately(0, 0, width, height);
    };
    runnable.run();
    
    TableModel model = new DataModel(values, runnable);
    
    JTable table = new JTable(model);
    table.setPreferredScrollableViewportSize(new Dimension(width, 50));
    JScrollPane scrollPane = new JScrollPane(table);
    
    JFrame frame = new JFrame(title);
    frame.setResizable(false);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container contentPane = frame.getContentPane();
    contentPane.add(BorderLayout.CENTER, component);
    contentPane.add(BorderLayout.SOUTH, scrollPane);
    frame.pack();
    frame.setVisible(true);
  }
}
