/*
 Copyright (C) 2003 Morten O.Alver & Nizar N. Batada

 All programs in this directory and
 subdirectories are published under the GNU General Public License as
 described below.

 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

 Further information about the GNU GPL is available at:
 http://www.gnu.org/copyleft/gpl.ja.html

 */

package net.sf.jabref;

import java.util.*;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.table.TableColumnModel;

//
class KeyBindingsDialog
    extends JDialog {
  KeystrokeTable table;
  KeystrokeTableModel tableModel;
  //JList list = new JList();
  JTextField keyTF = new JTextField();
  JButton ok, cancel, grabB, defB;
  HashMap bindHM, defBinds;
  boolean clickedSave = false;
  int selectedRow = -1;
  boolean getAction() {
    return clickedSave;
  }

  HashMap getNewKeyBindings() {
    return bindHM;
  }

  public KeyBindingsDialog(HashMap name2binding, HashMap defBinds) {
    super();
    this.defBinds = defBinds;
    setTitle(Globals.lang("Key bindings"));
    setModal(true); //this needs to be modal so that client knows when ok or cancel was clicked
    getContentPane().setLayout(new BorderLayout());
    bindHM = name2binding;
    setList();
    //JScrollPane listScroller = new JScrollPane(list);
    JScrollPane listScroller = new JScrollPane(table);
    listScroller.setPreferredSize(new Dimension(250, 400));
    getContentPane().add(listScroller, BorderLayout.CENTER);

    Box buttonBox = new Box(BoxLayout.X_AXIS);
    ok = new JButton(Globals.lang("Ok"));
    cancel = new JButton(Globals.lang("Cancel"));
    grabB = new JButton(Globals.lang("Grab"));
    defB = new JButton(Globals.lang("Default"));
    grabB.addKeyListener(new JBM_CustomKeyBindingsListener());
    /*grabB.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        selectedRow = (table.getSelectedRows())[0];
        Util.pr(""+selectedRow);
      }
    });*/
    buttonBox.add(grabB);
    buttonBox.add(defB);
    buttonBox.add(ok);
    buttonBox.add(cancel);

    getContentPane().add(buttonBox, BorderLayout.SOUTH);
    //setTop();
    setButtons();
    keyTF.setEditable(false);

    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        clickedSave = false;
        dispose();
      }
    });
  }

  void setTop() {
    Box topBox = new Box(BoxLayout.X_AXIS);

    topBox.add(new JLabel(Globals.lang("Binding") + ":", JLabel.RIGHT));
    topBox.add(keyTF);
    getContentPane().add(topBox, BorderLayout.NORTH);

  }

  //##################################################
  // respond to grabKey and display the key binding
  //##################################################
  public class JBM_CustomKeyBindingsListener
      extends KeyAdapter {
    public void keyPressed(KeyEvent evt) {
      // first check if anything is selected if not the return
      int selRow = table.getSelectedRow();
      if (selRow < 0)
        return;
      //Util.pr("dei"+selectedRow+" "+table.getSelectedRow());
      //Object[] selected = list.getSelectedValues();
      //if (selected.length == 0) {
      //  return;
      //}

      String code = KeyEvent.getKeyText(evt.getKeyCode());
      String mod = KeyEvent.getKeyModifiersText(evt.getModifiers());
      // all key bindings must have a modifier: ctrl alt etc

      if (mod.equals("")) {
        int kc = evt.getKeyCode();
        if ( (kc < KeyEvent.VK_F1) && (kc > KeyEvent.VK_F12) &&
            (kc != KeyEvent.VK_ESCAPE) && (kc != KeyEvent.VK_DELETE)) {
          return; // need a modifier except for function keys
        }
      }
      // second key cannot be a modifiers
      //if ( evt.isActionKey()) {
      //Util.pr(code);
      if ( //code.equals("Escape")
          code.equals("Tab")
          || code.equals("Backspace")
          || code.equals("Enter")
          //|| code.equals("Delete")
          || code.equals("Space")
          || code.equals("Ctrl")
          || code.equals("Shift")
          || code.equals("Alt")) {
        return;
      }
      //}
      String newKey;
      if (!mod.equals("")) {
        newKey = mod.toLowerCase().replaceAll("\\+"," ") + " " + code;
      }
      else {
        newKey = code;
      }
      keyTF.setText(newKey);
      //find which key is selected and set its value int the bindHM
      String selectedFunction = (String) table.getOriginalName(selRow);
      table.setValueAt(newKey, selRow, 1);
      table.revalidate();
      table.repaint();
      //Util.pr(selectedFunction);
      //String selectedFunction = (String) list.getSelectedValue();
      // log print
      // System.out.println("selectedfunction " + selectedFunction + " new key: " + newKey);
      bindHM.put(selectedFunction, newKey);
      //table.setValueAt(newKey, );
    }
  }

  //##################################################
  // put the corresponding key binding into keyTF
  //##################################################
  class MyListSelectionListener
      implements ListSelectionListener {
    // This method is called each time the user changes the set of selected items
    public void valueChanged(ListSelectionEvent evt) {
      // When the user release the mouse button and completes the selection,
      // getValueIsAdjusting() becomes false
      if (!evt.getValueIsAdjusting()) {
        JList list = (JList) evt.getSource();

        // Get all selected items
        Object[] selected = list.getSelectedValues();

        // Iterate all selected items
        for (int i = 0; i < selected.length; i++) {
          Object sel = selected[i];
          keyTF.setText( (String) bindHM.get(sel));
        }
      }
    }
  }

  class MyListDataListener
      implements ListDataListener {
    // This method is called when new items have been added to the list
    public void intervalAdded(ListDataEvent evt) {
      DefaultListModel model = (DefaultListModel) evt.getSource();

      // Get range of new  items
      int start = evt.getIndex0();
      int end = evt.getIndex1();
      int count = end - start + 1;

      // Get new items
      for (int i = start; i <= end; i++) {
        Object item = model.getElementAt(i);
      }
    }

    // This method is called when items have been removed from the list
    public void intervalRemoved(ListDataEvent evt) {
      // Get range of removed items
      int start = evt.getIndex0();
      int end = evt.getIndex1();
      int count = end - start + 1;

      // The removed items are not available
    }

    // This method is called when items in the list are replaced
    public void contentsChanged(ListDataEvent evt) {
      DefaultListModel model = (DefaultListModel) evt.getSource();

      // Get range of changed items
      int start = evt.getIndex0();
      int end = evt.getIndex1();
      int count = end - start + 1;

      // Get changed items
      for (int i = start; i <= end; i++) {
        Object item = model.getElementAt(i);
      }
    }
  }

  //setup so that clicking on list will display the current binding
  void setList() {

    DefaultListModel listModel = new DefaultListModel();
    Iterator it = bindHM.keySet().iterator();
    String[][] tableData = new String[bindHM.size()][3];
    int i=0;
    while (it.hasNext()) {
      String s = (String) it.next();
      tableData[i][2] = s;
      tableData[i][1] = (String) bindHM.get(s);
      tableData[i][0] = Globals.lang(s);
      i++;
      //listModel.addElement(s + " (" + bindHM.get(s) + ")");
   }
   TreeMap sorted = new TreeMap();
   for (i=0; i<tableData.length; i++)
     sorted.put(tableData[i][0], tableData[i]);

    tableModel = new KeystrokeTableModel(sorted);
    table = new KeystrokeTable(tableModel);
    //table.setCellSelectionEnabled(false);
    table.setRowSelectionAllowed(true);
    table.setColumnSelectionAllowed(false);
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    //list.setModel(listModel);
    TableColumnModel cm = table.getColumnModel();
    cm.getColumn(0).setPreferredWidth(GUIGlobals.KEYBIND_COL_0);
    cm.getColumn(1).setPreferredWidth(GUIGlobals.KEYBIND_COL_1);
    table.setRowSelectionInterval(0, 0); //select the first entry
  }

  class KeystrokeTable extends JTable {
    public KeystrokeTable(KeystrokeTableModel model) { super(model); }
     public boolean isCellEditable(int row, int col) { return false; }
     public String getOriginalName(int row) { return ((KeystrokeTableModel)getModel()).data[row][2]; }
   }

    class KeystrokeTableModel extends AbstractTableModel {
      String[][] data;
      //String[] trData;
      public KeystrokeTableModel(TreeMap sorted) {
        data = new String[sorted.size()][3];
        Iterator i = sorted.keySet().iterator();
        int row = 0;
        while (i.hasNext()) {
          data[row++] = ((String[])sorted.get(i.next()));
        }
        //for (int i=0; i<trData.length; i++)
        //  trData[i] = Globals.lang(data[i][0]);
      }
      public boolean isCellEditable(int row, int col) { return false; }
      public String getColumnName(int col) {
        return (col==0 ? Globals.lang("Action") : Globals.lang("Shortcut"));
      }
      public int getColumnCount() {
        return 2;
      }

      public int getRowCount() {
        return data.length;
      }
      public Object getValueAt(int rowIndex, int columnIndex) {
        //if (columnIndex == 0)
        return data[rowIndex][columnIndex];
        //else
        //return data[rowIndex][0];
      }
      public void setValueAt(Object o, int row, int col) {
        data[row][col] = (String)o;
      }
    }

  // listners
  void setButtons() {
    ok.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        // save all the key bindings
        dispose();
        clickedSave = true;
        // message: key bindings will take into effect next time you start JBM
      }
    });
    cancel.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        dispose();
        clickedSave = false;
        //System.exit(-1);//get rid of this
      }
    });
    defB.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        /*Object[] selected = list.getSelectedValues();
        if (selected.length == 0) {
          return;
        }
        keyTF.setText(setToDefault( (String) list.getSelectedValue()));*/
      }
    });

  }

  String setToDefault(String name) {
    String defKey = (String) defBinds.get(name);
    bindHM.put(name, defKey);
    return defKey;
  }

  /*
       public static void main(String args[])
       {
    HashMap h=new HashMap();
    h.put("new-bibtex","ctrl N");
    h.put("edit-bibtex","ctrl E");
    h.put("exit-bibtex","ctrl Q");
    KeyBindingsDialog d= new KeyBindingsDialog(h);
    d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    d.setSize(200,300);
    d.setVisible(true);

    }*/
}
