package xyz.danielcortes.framework;

import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

/**
 * Este es el TableModel que usare para todas las tablas que creare en el sistema
 * Esto es debido a la falta de metodos de edicion directa comoda que existe en el modelo default
 * es por esto que se usa el generico, para poder entregar y recibir el objeto directamente
 * sin embargo, debido a esto sera necesario otorgar una TriFunction la cual debe resolver cual es el valor
 * que es entregado al momento de solicitar un valor en la tabla.
 * Ademas de necesitar que se definan los nombres de las columnas para funcionar.
 * Supongo que es mas bonito que definir todo aparte XD <3
 *
 */
public class BaseTableModel<T> extends AbstractTableModel {

  private String[] columns;
  private List<T> rows;
  private TriFunction<List<T>, Integer, Integer, Object> valueAt;

  /**
   * Crea un BaseModel, para esto sera necesario otorgar las columnas que tendra la tabla y una funcion
   * que calcule que valor se mostrara en una posicion de la tabla.
   *
   * @param columns
   * Lista de columnas que tendra la tabla de la forma:
   *    {"Columna 1", "Columna 2", "Columna 3"};
   *
   *
   * @param valueAt
   * TriFunction la cual recibe por parametros:
   *    - La lista de filas de la tabla
   *    - Un Integer indicando la fila del que se necesita el valor
   *    - Un Integer indicando la columna de la que se necesita el valor
   * Y esta debe retornar un objeto con toString para poder ser mostrado en la tabla
   *
   * Se sugiere el siguiente tipo de implementacion para la funcion
   *    (row, rowIndex, colIndex) -> {
   *      switch (colIndex) {
   *        case 0:
   *          return row.get(rowIndex).getColumn1();
   *        case 1:
   *          return row.get(rowIndex).getColumn2();
   *        case 2:
   *          return row.get(rowIndex).getColumn3();
   *        case 3:
   *          return row.get(rowIndex).getColumn4();
   *      }
   *      return null;
   *    }
   *
   */
  public BaseTableModel(String[] columns, TriFunction<List<T>, Integer, Integer, Object> valueAt) {
    super();
    this.columns = columns;
    this.valueAt = valueAt;
    this.rows = new ArrayList<>();
  }

  @Override
  public String getColumnName(int index) {
    return columns[index];
  }

  @Override
  public Object getValueAt(int rowIndex, int columnIndex) {
    return valueAt.apply(this.rows, rowIndex, columnIndex);
  }

  @Override
  public int getRowCount() {
    return rows.size();
  }

  @Override
  public int getColumnCount() {
    return columns.length;
  }

  public void addRow(T item) {
    rows.add(item);
    this.fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
  }

  public void addRows(List<T> items) {
    rows.clear();
    rows.addAll(items);
    this.fireTableRowsInserted(0, getRowCount() - 1);
  }

  public void removeRow(int row) {
    rows.remove(row);
    this.fireTableRowsDeleted(row, row);
  }

  public void removeRows() {
    int rowCount = this.getRowCount();
    if (rowCount > 0) {
      rows.clear();
      this.fireTableRowsDeleted(0, rowCount - 1);
    }
  }
}
