/*
 * Copyright (C) 2009-2017 Alistair Neil <info@dazzleships.net>
 *
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package client;

import lib.InfoDialog;
import java.awt.Component;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.event.ItemEvent;
import java.util.ArrayList;
import java.util.regex.Pattern;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import lib.Localisation;

/**
 *
 * @author Alistair Neil, <info@dazzleships.net>
 */
public final class PatternsEditor extends javax.swing.JDialog {

    public static final int CANCEL = 0;
    public static final int APPLY = 1;
    private final PACTableModel pactm = new PACTableModel();
    private PacFactory pacFactory = null;
    private String strChange = null;
    private Frame parent = null;
    private String strSelectedCountry = null;
    private static final Localisation LOCAL = new Localisation("resources/MessagesBundle");

    /**
     * Creates a PatternsEditor dialog
     *
     * @param parent Parent frame
     * @param modal Modality
     * @param pacfactory PacFactory being edited
     */
    public PatternsEditor(java.awt.Frame parent, boolean modal, PacFactory pacfactory) {
        super(parent, modal);
        this.parent = parent;
        pacFactory = pacfactory;
        initComponents();
        pactm.setColumnName(LOCAL.getString("patterntable_col1"), 0);
        pactm.setColumnName(LOCAL.getString("patterntable_col2"), 1);
        pactm.setColumnName(LOCAL.getString("patterntable_col3"), 2);
        jTablePatterns.setModel(pactm);
        jTablePatterns.setDefaultRenderer(String.class, new CustomTableCellRenderer());
        // Adjust our column widths
        adjustTableColumnWidth(0, "AAAAAAAAAA");
        adjustTableColumnWidth(1, "AAAAAAAAAAAAAAAAAAAAAAAA");
        adjustTableColumnWidth(2, "AAA");
        jTablePatterns.setRowHeight(jLabel1.getHeight() + 1);
        jTablePatterns.setShowGrid(true);
        jTextDoNotProxy.setText(pacFactory.getDoNotProxy());
    }

    /**
     * Populate the country combobox with a list of countries
     *
     * @param countries String[] of countries
     */
    public void populateCountryComboBox(String[] countries) {
        jComboCountry.setModel(new DefaultComboBoxModel<>(countries));
        jComboCountry.setSelectedIndex(-1);
    }

    /**
     * Set the selected country
     *
     * @param country
     */
    public void setSelectedCountry(String country) {
        jComboCountry.setSelectedItem(country);
    }

    /**
     * Populate the patterns table
     *
     * @param patterns an ArrayList<String> of pattern rules
     */
    private void populatePatternsTable(ArrayList<String> patterns) {

        // Clear all entries from table
        while (pactm.getRowCount() > 0) {
            pactm.removeRow(0);
        }
        // If patterns null just return;
        if (patterns == null) {
            strChange = pactm.toString() + jTextDoNotProxy.getText();
            return;
        }

        // Populate table
        Pattern pat = Pattern.compile(",");
        String[] split;
        Object[] obj = new Object[3];
        for (String s : patterns) {
            split = pat.split(s);
            if (split.length < 4) {
                continue;
            }
            obj[0] = split[0];
            obj[1] = split[1];
            try {
                obj[2] = Boolean.valueOf(split[2]);
            } catch (Exception ex) {
                obj[2] = true;
            }
            pactm.addRow(obj, (split[3]).contains("user"));
        }
        strChange = pactm.toString() + jTextDoNotProxy.getText();
    }

    /**
     * Test to see if patterns table has changed
     *
     * @return boolean True if changed
     */
    private boolean isPatternsTableChanged() {
        if (strChange == null) {
            return false;
        }
        String temp = pactm.toString() + jTextDoNotProxy.getText();
        return (!temp.contentEquals(strChange));
    }

    /**
     * Save patterns and rebuild active country pac if required
     */
    private void savePatterns() {
        String s;
        Boolean b;

        ArrayList<String> listUser = new ArrayList<>();
        int rowCount = pactm.getRowCount();
        if (rowCount > 0) {
            for (int i = 0; i < rowCount; i++) {
                s = pactm.getValueAt(i, 0) + "," + pactm.getValueAt(i, 1);
                b = (Boolean) pactm.getValueAt(i, 2);
                if (b) {
                    s += ",true";
                } else {
                    s += ",false";
                }
                listUser.add(s);
            }
        }

        if (listUser.isEmpty()) {
            pacFactory.deletePatternsFile(strSelectedCountry, PacFactory.FILEUSER);
        } else {
            pacFactory.savePatternsList(strSelectedCountry, PacFactory.FILEUSER, listUser);
        }
        pacFactory.setDoNotProxy(jTextDoNotProxy.getText());
        strChange = pactm.toString() + jTextDoNotProxy.getText();
    }

    /**
     * This is a check to see if any pattern save are required before exiting
     * the pattern editor
     */
    private int saveOnExitCheck() {
        int result = CANCEL;
        if (jButtonSave.isEnabled()) {
            jComboCountry.hidePopup();
            InfoDialog id = new InfoDialog(parent);
            id.createWarn(LOCAL.getString("dlg_patterneditsave_title"),
                    LOCAL.getString("dlg_patterneditsave_body"));
            id.setVisible(true);
            strChange = null;
            if (id.getReturnStatus() == InfoDialog.OK) {
                savePatterns();
                result = APPLY;
            }
            jButtonSave.setEnabled(isPatternsTableChanged());
        }
        return result;
    }

    /**
     * Will adjust table column widths based on fontmetrics
     *
     * @param col Column to be adjusted
     * @param text Text string to adjust for
     */
    private void adjustTableColumnWidth(int col, String text) {
        FontMetrics ourFontMetrics = getFontMetrics(jTablePatterns.getTableHeader().getFont());
        jTablePatterns.getColumn(jTablePatterns.getColumnName(col)).setPreferredWidth(ourFontMetrics.stringWidth(text));
    }

    /**
     * @return the return status of this dialog - one of RET_OK or RET_CANCEL
     */
    public int getReturnStatus() {
        return returnStatus;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButtonSave = new javax.swing.JButton();
        jButtonCancel = new javax.swing.JButton();
        jComboCountry = new javax.swing.JComboBox<>();
        jButtonDeletePattern = new javax.swing.JButton();
        jButtonAddPattern = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTablePatterns = new javax.swing.JTable();
        jLabel17 = new javax.swing.JLabel();
        jTextDoNotProxy = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Proxy Pattern Editor");
        setIconImage(null);
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                closeDialog(evt);
            }
        });

        jButtonSave.setText(LOCAL.getString("button_save")); // NOI18N
        jButtonSave.setEnabled(false);
        jButtonSave.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonSaveActionPerformed(evt);
            }
        });

        jButtonCancel.setText(LOCAL.getString("button_close")); // NOI18N
        jButtonCancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonCancelActionPerformed(evt);
            }
        });

        jComboCountry.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        jComboCountry.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                jComboCountryItemStateChanged(evt);
            }
        });

        jButtonDeletePattern.setText(LOCAL.getString("button_delete")); // NOI18N
        jButtonDeletePattern.setEnabled(false);
        jButtonDeletePattern.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonDeletePatternActionPerformed(evt);
            }
        });

        jButtonAddPattern.setText(LOCAL.getString("button_addnew")); // NOI18N
        jButtonAddPattern.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonAddPatternActionPerformed(evt);
            }
        });

        jLabel1.setText(LOCAL.getString("label_editcountry")); // NOI18N

        jTablePatterns.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        jTablePatterns.setToolTipText(LOCAL.getString("ttip_patterntable")); // NOI18N
        jTablePatterns.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
        jTablePatterns.setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        jTablePatterns.getTableHeader().setResizingAllowed(false);
        jTablePatterns.getTableHeader().setReorderingAllowed(false);
        jTablePatterns.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTablePatternsMouseReleased(evt);
            }
        });
        jTablePatterns.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTablePatternsKeyReleased(evt);
            }
        });
        jScrollPane1.setViewportView(jTablePatterns);

        jLabel17.setText(LOCAL.getString("label_donotproxy")); // NOI18N

        jTextDoNotProxy.setToolTipText(LOCAL.getString("ttip_donotproxy")); // NOI18N
        jTextDoNotProxy.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                jTextDoNotProxyFocusLost(evt);
            }
        });
        jTextDoNotProxy.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTextDoNotProxyKeyReleased(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jComboCountry, javax.swing.GroupLayout.PREFERRED_SIZE, 264, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel1))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jButtonDeletePattern)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButtonAddPattern)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jButtonCancel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jButtonSave))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel17)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jTextDoNotProxy)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(jComboCountry, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 341, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextDoNotProxy, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel17))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButtonDeletePattern)
                    .addComponent(jButtonCancel)
                    .addComponent(jButtonSave)
                    .addComponent(jButtonAddPattern))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButtonSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSaveActionPerformed
        savePatterns();
        jButtonSave.setEnabled(isPatternsTableChanged());
        doClose(APPLY);
    }//GEN-LAST:event_jButtonSaveActionPerformed

    private void jButtonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCancelActionPerformed
        doClose(saveOnExitCheck());
    }//GEN-LAST:event_jButtonCancelActionPerformed

    /**
     * Closes the dialog
     */
    private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
        doClose(CANCEL);
    }//GEN-LAST:event_closeDialog

private void jComboCountryItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jComboCountryItemStateChanged

    if (evt.getStateChange() != ItemEvent.SELECTED) {
        return;
    }

    saveOnExitCheck();

    // Check for no entries
    if (jComboCountry.getItemCount() == 0) {
        jTablePatterns.setEnabled(false);
        jButtonDeletePattern.setEnabled(false);
        jButtonAddPattern.setEnabled(false);
        jButtonSave.setEnabled(false);
        populatePatternsTable(null);
        return;
    }

    // We reach here if we have selected a valid country
    jTablePatterns.setEnabled(true);
    jButtonAddPattern.setEnabled(true);
    strSelectedCountry = (String) jComboCountry.getSelectedItem();
    ArrayList<String> patterns = new ArrayList<>();
    pacFactory.loadPatternsList(strSelectedCountry, patterns);
    populatePatternsTable(patterns);
}//GEN-LAST:event_jComboCountryItemStateChanged

private void jTablePatternsMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTablePatternsMouseReleased
    jButtonDeletePattern.setEnabled(jTablePatterns.isCellEditable(jTablePatterns.getSelectedRow(), 0));
    jButtonSave.setEnabled(isPatternsTableChanged());
}//GEN-LAST:event_jTablePatternsMouseReleased

private void jButtonDeletePatternActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDeletePatternActionPerformed

    int[] i;
    while (true) {
        i = jTablePatterns.getSelectedRows();
        if (i.length == 0) {
            break;
        }
        pactm.removeRow(i[0]);
    }
    jButtonDeletePattern.setEnabled(false);
    jButtonSave.setEnabled(isPatternsTableChanged());
}//GEN-LAST:event_jButtonDeletePatternActionPerformed

private void jTablePatternsKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTablePatternsKeyReleased
    jButtonSave.setEnabled(isPatternsTableChanged());
}//GEN-LAST:event_jTablePatternsKeyReleased

private void jButtonAddPatternActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonAddPatternActionPerformed

    QuickAddDialog qad = new QuickAddDialog(parent, true);
    qad.setTitle("Add new pattern");
    qad.setLocationRelativeTo(this);
    qad.setVisible(true);
    if (qad.getReturnStatus() == QuickAddDialog.CANCEL) {
        return;
    }
    if (!qad.getPattern().isEmpty()) {
        pactm.addRow(new Object[]{qad.getDescription(), qad.getPattern(), Boolean.TRUE}, true);
    }
    jButtonSave.setEnabled(isPatternsTableChanged());
}//GEN-LAST:event_jButtonAddPatternActionPerformed

    private void jTextDoNotProxyKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextDoNotProxyKeyReleased
        jButtonSave.setEnabled(isPatternsTableChanged());
    }//GEN-LAST:event_jTextDoNotProxyKeyReleased

    private void jTextDoNotProxyFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_jTextDoNotProxyFocusLost
        jButtonSave.setEnabled(isPatternsTableChanged());
    }//GEN-LAST:event_jTextDoNotProxyFocusLost

    private void doClose(int retStatus) {
        returnStatus = retStatus;
        setVisible(false);
        dispose();
    }

    /**
     * CustomTableCellRenderer
     */
    public class CustomTableCellRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = super.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column);

            // Only for specific cell
            if (table.isRowSelected(row)) {
                return c;
            }
            if (column < 2) {
                if (table.getModel().isCellEditable(row, column)) {
                    c.setBackground(javax.swing.UIManager.getDefaults().getColor("Table.background"));
                } else {
                    c.setBackground(javax.swing.UIManager.getDefaults().getColor("control"));
                }
            }
            return c;
        }
    }

    /**
     * PACTableModel class
     */
    public class PACTableModel extends DefaultTableModel {

        @SuppressWarnings("rawtypes")
        private final String[] columnNames = {"Description", "Pattern", "Enabled"};
        private final Class[] types = new Class[]{
            java.lang.String.class, java.lang.String.class, java.lang.Boolean.class
        };
        private final ArrayList<Boolean> rowedit = new ArrayList<>();

        public void addRow(Object[] obj, boolean editable) {
            addRow(obj);
            rowedit.add(editable);
        }

        /**
         * Constructor
         */
        public PACTableModel() {
        }

        /**
         * Get column count as integer
         *
         * @return columns as integer
         */
        @Override
        public int getColumnCount() {
            return types.length;
        }

        /**
         * Get column class
         *
         * @param columnIndex
         * @return object Class
         */
        @Override
        @SuppressWarnings("rawtypes")
        public Class getColumnClass(int columnIndex) {
            return types[columnIndex];
        }

        /**
         * Test if cell at given row, col is editable
         *
         * @param row
         * @param column
         * @return True if editable
         */
        @Override
        public boolean isCellEditable(int row, int column) {
            if (column == 2) {
                return true;
            } else {
                return rowedit.get(row);
            }
        }

        /**
         * Get column name at given index
         *
         * @param index
         * @return name as string
         */
        @Override
        public String getColumnName(int index) {
            return columnNames[index];
        }

        /**
         * Set the column name at the specified index
         *
         * @param name
         * @param index
         */
        public void setColumnName(String name, int index) {
            if (index < columnNames.length) {
                columnNames[index] = name;
            }
        }

        /**
         * Returns all data as a single string
         *
         * @return string
         */
        @Override
        public String toString() {
            return getDataVector().toString();
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButtonAddPattern;
    private javax.swing.JButton jButtonCancel;
    private javax.swing.JButton jButtonDeletePattern;
    private javax.swing.JButton jButtonSave;
    private javax.swing.JComboBox<String> jComboCountry;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel17;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTablePatterns;
    private javax.swing.JTextField jTextDoNotProxy;
    // End of variables declaration//GEN-END:variables
    private int returnStatus = CANCEL;
}
