package me.corriekay.pokegoutil.utils.windows;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import com.pokegoapi.api.PokemonGo;
import com.pokegoapi.api.pokemon.Pokemon;
import me.corriekay.pokegoutil.data.enums.PokeColumn;
import me.corriekay.pokegoutil.utils.ConfigKey;
import me.corriekay.pokegoutil.utils.ConfigNew;
import me.corriekay.pokegoutil.utils.helpers.JTableColumnPacker;
/**
* The Pokémon Table. Extended JTable which displays all Pokémon and does the needed
* configuration for that.
* <p>
* Added things are row sorter, column comparators, listener and the cell renderers.
*/
public class PokemonTable extends JTable {
// Global statics
public static final int COLUMN_MARGIN = 3;
public static final int ROW_HEIGHT_PADDING = ConfigNew.getConfig().getInt(ConfigKey.ROW_PADDING);
private final ConfigNew config = ConfigNew.getConfig();
private PokemonTableModel ptm;
private List columnErrors = new LinkedList<String>();
/**
* Constructs the PokemonTable, sets the model and defines all preset stuff.
*
* @param go The go instance of the Pogo API
*/
public PokemonTable(final PokemonGo go) {
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
setAutoResizeMode(AUTO_RESIZE_OFF);
setRowHeight(getRowHeight() + ROW_HEIGHT_PADDING * 2);
ptm = new PokemonTableModel(go, new ArrayList<>(), this);
setModel(ptm);
// Load sort configs
final int sortColIndex1 = config.getInt(ConfigKey.SORT_COLINDEX_1);
final int sortColIndex2 = config.getInt(ConfigKey.SORT_COLINDEX_2);
SortOrder sortOrder1;
SortOrder sortOrder2;
try {
sortOrder1 = SortOrder.valueOf(config.getString(ConfigKey.SORT_ORDER_1));
sortOrder2 = SortOrder.valueOf(config.getString(ConfigKey.SORT_ORDER_2));
} catch (final IllegalArgumentException e) {
e.printStackTrace();
sortOrder1 = SortOrder.ASCENDING;
sortOrder2 = SortOrder.ASCENDING;
}
final TableRowSorter<TableModel> trs = new TableRowSorter<>(ptm);
// Set the comparator for each column that is defined.
for (final PokeColumn column : PokeColumn.values()) {
trs.setComparator(column.id, column.getComparator());
}
setRowSorter(trs);
final List<SortKey> sortKeys = new ArrayList<>();
sortKeys.add(new SortKey(sortColIndex1, sortOrder1));
sortKeys.add(new SortKey(sortColIndex2, sortOrder2));
trs.setSortKeys(sortKeys);
// Add listener to save those sorting values
trs.addRowSorterListener(
e -> {
@SuppressWarnings("unchecked")
final List<SortKey> keys = (List<SortKey>) trs.getSortKeys();
if (keys.size() > 0) {
final SortKey prim = keys.get(0);
config.setString(ConfigKey.SORT_ORDER_1, prim.getSortOrder().toString());
config.setInt(ConfigKey.SORT_COLINDEX_1, prim.getColumn());
}
if (keys.size() > 1) {
final SortKey sec = keys.get(1);
config.setString(ConfigKey.SORT_ORDER_2, sec.getSortOrder().toString());
config.setInt(ConfigKey.SORT_COLINDEX_2, sec.getColumn());
}
});
// Add cell renderers
for (final PokeColumn column : PokeColumn.values()) {
columnModel.getColumn(column.id).setCellRenderer(column.getCellRenderer());
}
try {
rearrangeColumnOrder();
}
catch(Exception exc) {
System.out.println("Oooops, something went wrong with table order rearranging!");
System.out.println(exc.toString());
}
}
private void rearrangeColumnOrder()
{
List<String> myColumnEnumNames = new LinkedList<String>();
String config = ConfigNew.getConfig().getString(ConfigKey.POKEMONTABLE_COLUMNORDER);
if (config != null && ! config.isEmpty()) {
myColumnEnumNames.addAll(Arrays.asList(config.split(",")));
}
else {
myColumnEnumNames.addAll(Stream.of(PokeColumn.values())
.map(Enum::toString).collect(Collectors.toList()));
}
int newIndex = 0;
for (String enumName : myColumnEnumNames) {
try {
PokeColumn pokeColumn = PokeColumn.valueOf(enumName);
TableColumn c = this.getColumn(pokeColumn.heading);
if (c != null) {
int currentIndex = this.convertColumnIndexToView(c.getModelIndex());
if (currentIndex != newIndex) {
this.getColumnModel().moveColumn(currentIndex, newIndex);
}
newIndex++;
}
}
catch(IllegalArgumentException exc) {
columnErrors.add(enumName);
}
}
}
public void saveColumnOrderToConfig() {
List<String> enumNames = new LinkedList<String>();
Enumeration<TableColumn> e = this.getColumnModel().getColumns();
while(e.hasMoreElements()) {
String columnHeading = e.nextElement().getHeaderValue().toString();
try {
enumNames.add(PokeColumn.getForHeading(columnHeading).toString());
}
catch (IllegalArgumentException exc)
{
// can this happen in production use?
}
}
String columnOrderEnums = String.join(",", enumNames);
ConfigNew.getConfig().setString(ConfigKey.POKEMONTABLE_COLUMNORDER, columnOrderEnums);
}
/**
*
* @return Returns the list of columns which were requested in columns order
* in configuration file, but not found.
*/
public List<String> getColumnErrors() {
return columnErrors;
}
/**
* Reconstructs the table model with new list of Pokémon.
* Updates the data and repacks the columns.
*
* @param pokes A list of Pokémon to display.
*/
public void constructNewTableModel(final List<Pokemon> pokes) {
ptm.updateTableData(pokes);
pack();
}
/**
* Packs the tables.
*/
private void pack() {
for (int i = 0; i < ptm.getColumnCount(); i++) {
JTableColumnPacker.packColumn(this, i, COLUMN_MARGIN);
}
}
}