/*
 * File    : TextListEditor.java
 * Created : 23-may-2003 11:19
 * By      : fbusquets
 *
 * JClic - Authoring and playing system for educational activities
 *
 * Copyright (C) 2000 - 2018 Francesc Busquets & Departament
 * d'Educacio de la Generalitat de Catalunya
 *
 * 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 (see the LICENSE file).
 */

package edu.xtec.jclic.beans;

import edu.xtec.util.Options;
import edu.xtec.util.StrUtils;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.DefaultListModel;

/**
 * @author Francesc Busquets (fbusquets@xtec.cat)
 * @version 13.10.29
 */
public class TextListEditor extends javax.swing.JPanel implements javax.swing.event.ListSelectionListener {

  public static final String PROP_LIST = "list";

  Options options;
  DefaultListModel<Object> listModel;
  boolean modified;
  int maxItems = 999;
  int minItems = 0;
  boolean upperCase;

  /** Creates new form TextListEditor */
  public TextListEditor() {
    this(null);
  }

  /** Creates new form TextListEditor */
  public TextListEditor(Options options) {
    this.options = options;
    listModel = new DefaultListModel<Object>();
    initComponents();
    list.addListSelectionListener(this);
  }

  /**
   * 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() {
    java.awt.GridBagConstraints gridBagConstraints;

    javax.swing.JScrollPane listScroll = new javax.swing.JScrollPane();
    list = new javax.swing.JList<Object>();
    btnPanel = new javax.swing.JPanel();
    addBtn = new javax.swing.JButton();
    removeBtn = new javax.swing.JButton();
    editBtn = new javax.swing.JButton();
    upBtn = new javax.swing.JButton();
    downBtn = new javax.swing.JButton();

    setLayout(new java.awt.GridBagLayout());

    listScroll.setPreferredSize(new java.awt.Dimension(100, 60));

    list.setModel(listModel);
    list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
    listScroll.setViewportView(list);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
    gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
    gridBagConstraints.weightx = 1.0;
    gridBagConstraints.weighty = 1.0;
    gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2);
    add(listScroll, gridBagConstraints);

    btnPanel.setLayout(new javax.swing.BoxLayout(btnPanel, javax.swing.BoxLayout.LINE_AXIS));

    addBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/plus16.gif"))); // NOI18N
    addBtn.setToolTipText(options == null ? "" : options.getMsg("edit_list_newElement_tooltip"));
    addBtn.setMargin(new java.awt.Insets(0, 0, 0, 0));
    addBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        addBtnActionPerformed(evt);
      }
    });
    btnPanel.add(addBtn);

    removeBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/minus16.gif"))); // NOI18N
    removeBtn.setToolTipText(options == null ? "" : options.getMsg("edit_list_deleteElement_tooltip"));
    removeBtn.setMargin(new java.awt.Insets(0, 0, 0, 0));
    removeBtn.setEnabled(false);
    removeBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        removeBtnActionPerformed(evt);
      }
    });
    btnPanel.add(removeBtn);

    editBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/edit.gif"))); // NOI18N
    editBtn.setToolTipText(options == null ? "" : options.getMsg("edit_list_editElement_tooltip"));
    editBtn.setMargin(new java.awt.Insets(0, 0, 0, 0));
    editBtn.setEnabled(false);
    editBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        editBtnActionPerformed(evt);
      }
    });
    btnPanel.add(editBtn);

    upBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/up.gif"))); // NOI18N
    upBtn.setToolTipText(options == null ? "" : options.getMsg("edit_list_upBtn_tooltip"));
    upBtn.setMargin(new java.awt.Insets(0, 0, 0, 0));
    upBtn.setEnabled(false);
    upBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        upBtnActionPerformed(evt);
      }
    });
    btnPanel.add(upBtn);

    downBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/down.gif"))); // NOI18N
    downBtn.setToolTipText(options == null ? "" : options.getMsg("edit_list_downBtn_tooltip"));
    downBtn.setMargin(new java.awt.Insets(0, 0, 0, 0));
    downBtn.setEnabled(false);
    downBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        downBtnActionPerformed(evt);
      }
    });
    btnPanel.add(downBtn);

    gridBagConstraints = new java.awt.GridBagConstraints();
    gridBagConstraints.gridx = 0;
    gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
    gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
    gridBagConstraints.insets = new java.awt.Insets(0, 2, 2, 2);
    add(btnPanel, gridBagConstraints);
  } // </editor-fold>//GEN-END:initComponents

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

    int v = list.getSelectedIndex();
    if (options != null) {
      Object s = editItem(null, true);
      if (s != null && s.toString().length() > 0) {
        if (upperCase)
          s = s.toString().toUpperCase();
        listModel.add(v + 1, s);
        list.setSelectedIndex(v + 1);
        firePropertyChange(PROP_LIST, "", s);
        modified = true;
      }
    }
  } // GEN-LAST:event_addBtnActionPerformed

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

    int v = list.getSelectedIndex();
    if (v >= 0 && options != null) {
      Object s = listModel.getElementAt(v);
      Object r = editItem(s, false);
      if (r != null && r.toString().length() > 0 && !r.equals(s)) {
        if (upperCase)
          r = r.toString().toUpperCase();
        listModel.setElementAt(r, v);
        firePropertyChange(PROP_LIST, s, r);
        modified = true;
      }
    }
  } // GEN-LAST:event_editBtnActionPerformed

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

    int i = list.getSelectedIndex();
    if (i >= 0 && i < listModel.getSize() - 1) {
      listModel.add(i + 1, listModel.remove(i));
      list.setSelectedIndex(i + 1);
      firePropertyChange(PROP_LIST, i, i + 1);
      modified = true;
    }
  } // GEN-LAST:event_downBtnActionPerformed

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

    int i = list.getSelectedIndex();
    if (i > 0) {
      listModel.add(i - 1, listModel.remove(i));
      list.setSelectedIndex(i - 1);
      firePropertyChange(PROP_LIST, i, i - 1);
      modified = true;
    }
  } // GEN-LAST:event_upBtnActionPerformed

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

    Object o = list.getSelectedValue();
    if (o != null) {
      listModel.removeElement(o);
      firePropertyChange(PROP_LIST, o, null);
      modified = true;
      checkEnabled();
    }
  } // GEN-LAST:event_removeBtnActionPerformed

  /**
   * Getter for property options.
   *
   * @return Value of property options.
   */
  public edu.xtec.util.Options getOptions() {
    return options;
  }

  /**
   * Setter for property options.
   *
   * @param options New value of property options.
   */
  public void setOptions(edu.xtec.util.Options options) {
    this.options = options;
  }

  public void valueChanged(javax.swing.event.ListSelectionEvent listSelectionEvent) {
    if (listSelectionEvent == null || !listSelectionEvent.getValueIsAdjusting()) {
      checkEnabled();
    }
  }

  protected void checkEnabled() {
    boolean enabled = isEnabled();
    int v = list.getSelectedIndex();
    int c = listModel.size();
    addBtn.setEnabled(enabled && c < maxItems);
    upBtn.setEnabled(enabled && v > 0);
    downBtn.setEnabled(enabled && v >= 0 && v < list.getModel().getSize() - 1);
    removeBtn.setEnabled(enabled && v >= 0 && c > minItems);
    editBtn.setEnabled(enabled && v >= 0);
  }

  /**
   * Getter for property listData.
   *
   * @return Value of property listData.
   */
  public List<Object> getListData() {
    Enumeration en = listModel.elements();
    List<Object> result = new ArrayList<Object>(listModel.getSize());
    while (en.hasMoreElements()) {
      Object o = en.nextElement();
      // In some cases, DefaultListModel returns elements as a "list of elements"
      // with only one object inside
      if (o instanceof List) {
        List al = (List) o;
        o = al.get(0);
      }
      result.add(o);
    }
    return result;
  }

  /**
   * Setter for property listData.
   *
   * @param listData New value of property listData.
   */
  public void setListData(List<Object> listData) {
    listModel.removeAllElements();
    if (listData != null) {
      for (Object o : listData) {
        if (upperCase)
          o = o.toString().toUpperCase();
        listModel.addElement(o);
      }
    }
    modified = false;
    checkEnabled();
  }

  /**
   * Setter for property listData.
   *
   * @param textList String array with the list values.
   */
  public void setTextList(String[] textList) {
    listModel.removeAllElements();
    if (textList != null) {
      for (int i = 0; i < textList.length && i < maxItems; i++) {
        String s = textList[i];
        if (upperCase)
          s = s.toUpperCase();
        listModel.addElement(s);
      }
    }
    modified = false;
    checkEnabled();
  }

  public String[] getTextList() {
    List v = getListData();
    int n = v.size();
    String[] result = new String[n];
    for (int i = 0; i < n; i++)
      result[i] = v.get(i).toString();
    return result;
  }

  /**
   * Getter for property modified.
   *
   * @return Value of property modified.
   */
  public boolean isModified() {
    return modified;
  }

  /**
   * Setter for property modified.
   *
   * @param modified New value of property modified.
   */
  public void setModified(boolean modified) {
    this.modified = modified;
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    checkEnabled();
  }

  /**
   * Getter for property maxItems.
   *
   * @return Value of property maxItems.
   */
  public int getMaxItems() {
    return maxItems;
  }

  /**
   * Setter for property maxItems.
   *
   * @param maxItems New value of property maxItems.
   */
  public void setMaxItems(int maxItems) {
    this.maxItems = maxItems;
    checkEnabled();
  }

  /**
   * Getter for property minItems.
   *
   * @return Value of property minItems.
   */
  public int getMinItems() {
    return minItems;
  }

  /**
   * Setter for property minItems.
   *
   * @param minItems New value of property minItems.
   */
  public void setMinItems(int minItems) {
    this.minItems = minItems;
    checkEnabled();
  }

  protected Object editItem(Object currentValue, boolean newValue) {
    Object result;
    if (newValue)
      result = options.getMessages().showInputDlg(this, (String) null, "edit_list_newValue", "", "edit_list_addElement",
          false);
    else
      result = options.getMessages().showInputDlg(this, (String) null, "edit_list_newValue",
          StrUtils.nullableString(currentValue), "edit_list_modifyValue", false);
    return result;
  }

  @Override
  public void setToolTipText(String text) {
    super.setToolTipText(text);
    list.setToolTipText(text);
    btnPanel.setToolTipText(text);
  }

  /**
   * Getter for property upperCase.
   *
   * @return Value of property upperCase.
   */
  public boolean isUpperCase() {
    return upperCase;
  }

  /**
   * Setter for property upperCase.
   *
   * @param upperCase New value of property upperCase.
   */
  public void setUpperCase(boolean upperCase) {
    this.upperCase = upperCase;
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton addBtn;
  private javax.swing.JPanel btnPanel;
  private javax.swing.JButton downBtn;
  private javax.swing.JButton editBtn;
  private javax.swing.JList<Object> list;
  private javax.swing.JButton removeBtn;
  private javax.swing.JButton upBtn;
  // End of variables declaration//GEN-END:variables

}
