/*
 * Customized JTable with helpers to coordinate common operations.
 */

/*
    Copywrite 2013-2016 Will Winder

    This file is part of Universal Gcode Sender (UGS).

    UGS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    UGS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with UGS.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.willwinder.universalgcodesender.uielements.components;

import com.willwinder.universalgcodesender.i18n.Localization;
import com.willwinder.universalgcodesender.types.GcodeCommand;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

/**
 *
 * @author wwinder
 */
public class GcodeTable extends JTable {
    private static final Logger logger = Logger.getLogger(GcodeTable.class.getName());

    //GcodeTableModel model = null;
    private DefaultTableModel model = null;
    private int maxLines = -1;

    private boolean autoWindowScroll = false;
    private int offset = 0;
    private boolean first = true;
    
    final private static int COL_INDEX_COMMAND       = 0;
    final private static int COL_INDEX_ORIG_COMMAND  = 1;
    final private static int COL_INDEX_SENT          = 2;
    final private static int COL_INDEX_DONE          = 3;
    final private static int COL_INDEX_RESPONSE      = 4;

    private static String[] columnNames = {
        Localization.getString("gcodeTable.command"),
        Localization.getString("gcodeTable.originalCommand"),
        Localization.getString("gcodeTable.sent"),
        Localization.getString("gcodeTable.done"),
        Localization.getString("gcodeTable.response")
    };
    private static Class[] columnTypes =  {
        String.class,
        String.class,
        Boolean.class,
        Boolean.class,
        String.class
    };
    
    public GcodeTable() {
        //model = new GcodeTableModel(null, columnNames, columnTypes);
        model = new DefaultTableModel(null, columnNames) {
            @Override
            public Class<?> getColumnClass(int idx) {
                return columnTypes[idx];
            }
        };

        this.setModel(model);
        getTableHeader().setReorderingAllowed(false);
    }

    @Override
    public void setBounds(int x, int y, int width, int height)
    {
        super.setBounds(x, y, width, height);

        // This is totally bogus, but they look alright when I throw in a max
        // width for the boolean columns.
        setPreferredColumnWidths(new double[] {0.25, 0.3, 0.2, 0.2, 0.2} );

        getColumnModel().getColumn(COL_INDEX_SENT).setResizable(false);
        getColumnModel().getColumn(COL_INDEX_SENT).setMaxWidth(50);
        getColumnModel().getColumn(COL_INDEX_DONE).setResizable(false);
        getColumnModel().getColumn(COL_INDEX_DONE).setMaxWidth(50);
    }
    
    public void setAutoWindowScroll(boolean autoWindowScroll) {
        this.autoWindowScroll = autoWindowScroll;
    }

    /**
     * Delete all rows from the table.
     */
    public void clear() {
        while (model.getRowCount()>0){
            model.removeRow(0);
        }
        //model.dropData();
        this.offset = 0;
        this.first = true;
    }
    
    /**
     * Update table with a GcodeCommand.
     */
    public void addRow(final GcodeCommand command) {
        if (first) {
            offset = command.getCommandNumber() * -1;
            first = false;
        }
        model.addRow(new Object[]{
            command.getCommandString(),
            command.getOriginalCommandString(),
            command.isSent(),
            command.isDone(),
            command.getResponse()});
        
        scrollTable(this.getRowCount());
    }
    
    /**
     * Update table with a GcodeCommand.
     */
    public void updateRow(final GcodeCommand command) {
        String commandString = command.getCommandString();
        int row = command.getCommandNumber() + offset;
        
        // Check for modified command string
        String val = (String)model.getValueAt(row, COL_INDEX_COMMAND);
        if (!command.isComment() && commandString != model.getValueAt(row, COL_INDEX_COMMAND)) {
            String message = String.format(
                    "Row mismatch [%s] does not match row %d [%s].]\n",
                    commandString,
                    row,
                    model.getValueAt(row, COL_INDEX_COMMAND));
            logger.log(Level.WARNING, message) ;
        }

        model.setValueAt(command.isSent(),      row, COL_INDEX_SENT);
        model.setValueAt(command.isDone(),      row, COL_INDEX_DONE);
        model.setValueAt(command.getResponse(), row, COL_INDEX_RESPONSE);
        
        scrollTable(row);
    }
    
    /**
     * Helper function to scroll table to specific row number.
     */
    private void scrollTable(int toRow) {
        // Scroll if selected.
        if (this.autoWindowScroll) {
            if (isVisible()) {
                scrollToVisible(toRow);
            }
        }
    }
    
    /**
     * Helper function to set preferred widths as a percentage.
     * http://stackoverflow.com/questions/1046005/jtable-column-resize-isnt-working
     */
    private void setPreferredColumnWidths(double[] percentages) {
        Dimension tableDim = getPreferredSize();

        double total = 0;

        for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
            total += percentages[i];
        }

        for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
            TableColumn column = getColumnModel().getColumn(i);
            column.setPreferredWidth(
                 (int)(tableDim.width * (percentages[i] / total)));
        }
    }
    
    /**
     * Helper function to scroll table to specific row.
     */
    private void scrollToVisible(int rowIndex) {
        getSelectionModel().setSelectionInterval(rowIndex, rowIndex);
        scrollRectToVisible(new Rectangle(getCellRect(rowIndex, 0, true)));
    }

    public void setOffset() {
        setOffset(this.getRowCount());
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        return false;
    }
}
