/*
 * File    : JDomTreePanel.java
 * Created : 05-dec-2002 10:46
 * 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.util;

import edu.xtec.jclic.fileSystem.FileSystem;
import edu.xtec.jclic.misc.Utils;
import java.awt.Component;
import java.awt.Dimension;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.*;

/**
 * @author Francesc Busquets (fbusquets@xtec.cat)
 * @version 13.09.17
 */
public class JDomTreePanel extends javax.swing.JPanel {

  ResourceBridge rb;
  TreeSelectionListener treeSelectionListener;
  ListSelectionListener listSelectionListener;
  JDomTreeObject current;
  DefaultMutableTreeNode currentNode;
  FileSystem fs;
  String fileName;
  org.jdom.Element element;
  private DefaultMutableTreeNode clip;
  private boolean cut;

  /** Creates new form ProjectTreePanel */
  public JDomTreePanel(org.jdom.Element element, ResourceBridge rb, FileSystem fs, String fileName) {
    this.rb = rb;
    this.fs = fs;
    this.fileName = fileName;
    this.element = element;
    initComponents();
    initMembers();
    tree.setModel(new DefaultTreeModel(JDomTreeObject.processNode(null, element, rb.getOptions())));
    tree.addTreeSelectionListener(treeSelectionListener);
    table.getSelectionModel().addListSelectionListener(listSelectionListener);
  }

  private void initMembers() {
    treeSelectionListener = new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        checkEnabled();
      }
    };

    listSelectionListener = new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        if (!e.getValueIsAdjusting()) {
          delAttributeBtn.setEnabled(e.getFirstIndex() >= 0);
        }
      }
    };
  }

  private void checkEnabled() {
    current = null;
    currentNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
    if (currentNode == null) {
      newElementBtn.setEnabled(false);
      delElementBtn.setEnabled(false);
      copyBtn.setEnabled(false);
      cutBtn.setEnabled(false);
      pasteBtn.setEnabled(false);
    } else {
      current = (JDomTreeObject) currentNode.getUserObject();
      setTableModel();
      String s = current.getElement().getText();
      boolean empty = (s == null || s.length() == 0);
      boolean root = current.getElement().isRootElement();
      newElementBtn.setEnabled(empty);
      delElementBtn.setEnabled(!root);
      copyBtn.setEnabled(!root);
      cutBtn.setEnabled(!root);
      pasteBtn.setEnabled(clip != null && empty && clip != currentNode && !clip.isNodeChild(currentNode));
    }
  }

  private void setTableModel() {
    AbstractTableModel model = current;
    if (model == null)
      model = new DefaultTableModel();
    table.setModel(model);
    model.fireTableStructureChanged();
    newAttributeBtn.setEnabled(current != null);
    delAttributeBtn.setEnabled(false);
  }

  /**
   * 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.
   */
  private void initComponents() { // GEN-BEGIN:initComponents
    javax.swing.JPanel buttonsPanel;
    javax.swing.JSplitPane split;
    javax.swing.JPanel tablePanel;
    javax.swing.JScrollPane tableScroll;
    javax.swing.JPanel treeButtonsPanel;
    javax.swing.JPanel treePanel;
    javax.swing.JScrollPane treeScroll;

    split = new javax.swing.JSplitPane();
    treePanel = new javax.swing.JPanel();
    treeScroll = new javax.swing.JScrollPane();
    tree = new javax.swing.JTree();
    treeButtonsPanel = new javax.swing.JPanel();
    newElementBtn = new javax.swing.JButton();
    delElementBtn = new javax.swing.JButton();
    copyBtn = new javax.swing.JButton();
    pasteBtn = new javax.swing.JButton();
    cutBtn = new javax.swing.JButton();
    saveBtn = new javax.swing.JButton();
    tablePanel = new javax.swing.JPanel();
    tableScroll = new javax.swing.JScrollPane();
    table = new javax.swing.JTable();
    buttonsPanel = new javax.swing.JPanel();
    newAttributeBtn = new javax.swing.JButton();
    delAttributeBtn = new javax.swing.JButton();

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

    treePanel.setLayout(new java.awt.BorderLayout());

    treeScroll.setMinimumSize(new java.awt.Dimension(150, 22));
    treeScroll.setViewportView(tree);

    treePanel.add(treeScroll, java.awt.BorderLayout.CENTER);

    newElementBtn
        .setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/new_element.gif")));
    newElementBtn.setToolTipText(rb.getMsg("XML_NEW_ELEMENT"));
    newElementBtn.setEnabled(false);
    newElementBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        newElementBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(newElementBtn);

    delElementBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/delete.gif")));
    delElementBtn.setToolTipText(rb.getMsg("XML_DEL_ELEMENT"));
    delElementBtn.setEnabled(false);
    delElementBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        delElementBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(delElementBtn);

    copyBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/copy.gif")));
    copyBtn.setToolTipText(rb.getMsg("COPY"));
    copyBtn.setEnabled(false);
    copyBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        copyBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(copyBtn);

    pasteBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/paste.gif")));
    pasteBtn.setToolTipText(rb.getMsg("PASTE"));
    pasteBtn.setEnabled(false);
    pasteBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        pasteBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(pasteBtn);

    cutBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/cut.gif")));
    cutBtn.setToolTipText(rb.getMsg("CUT"));
    cutBtn.setEnabled(false);
    cutBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        cutBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(cutBtn);

    saveBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/file_save.gif")));
    saveBtn.setToolTipText(rb.getMsg("FILE_SAVE"));
    saveBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        saveBtnActionPerformed(evt);
      }
    });

    treeButtonsPanel.add(saveBtn);

    treePanel.add(treeButtonsPanel, java.awt.BorderLayout.SOUTH);

    split.setLeftComponent(treePanel);

    tablePanel.setLayout(new java.awt.BorderLayout());

    table.setModel(new javax.swing.table.DefaultTableModel(new Object[][] {}, new String[] {}));

    tableScroll.setViewportView(table);

    tablePanel.add(tableScroll, java.awt.BorderLayout.CENTER);

    newAttributeBtn
        .setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/new_attribute.gif")));
    newAttributeBtn.setToolTipText(rb.getMsg("XML_NEW_ATTRIBUTE"));
    newAttributeBtn.setEnabled(false);
    newAttributeBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        newAttributeBtnActionPerformed(evt);
      }
    });

    buttonsPanel.add(newAttributeBtn);

    delAttributeBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/edu/xtec/resources/icons/delete.gif")));
    delAttributeBtn.setToolTipText(rb.getMsg("XML_DEL_ATTRIBUTE"));
    delAttributeBtn.setEnabled(false);
    delAttributeBtn.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        delAttributeBtnActionPerformed(evt);
      }
    });

    buttonsPanel.add(delAttributeBtn);

    tablePanel.add(buttonsPanel, java.awt.BorderLayout.SOUTH);

    split.setRightComponent(tablePanel);

    add(split, java.awt.BorderLayout.CENTER);
  } // GEN-END:initComponents

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

    if (currentNode != null && current != null && !current.getElement().isRootElement()) {
      clip = currentNode;
      cut = true;
      checkEnabled();
    }
  } // GEN-LAST:event_cutBtnActionPerformed

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

    if (currentNode != null && current != null && clip != null && clip != currentNode
        && !clip.isNodeChild(currentNode)) {
      org.jdom.Element clipElement = ((JDomTreeObject) clip.getUserObject()).getElement();
      org.jdom.Element el = (org.jdom.Element) clipElement.clone();
      current.getElement().addContent(el);
      TreeNode node = JDomTreeObject.processNode(currentNode, el, rb.getOptions());
      ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(currentNode);
      if (cut) {
        clipElement.detach();
        ((DefaultTreeModel) tree.getModel()).removeNodeFromParent(clip);
        clip = null;
      }
      setTableModel();
      checkEnabled();
    }
  } // GEN-LAST:event_pasteBtnActionPerformed

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

    if (currentNode != null && current != null && !current.getElement().isRootElement()) {
      clip = currentNode;
      cut = false;
      checkEnabled();
    }
  } // GEN-LAST:event_copyBtnActionPerformed

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

    if (fs == null)
      fs = new FileSystem(rb);

    int[] filters = { Utils.JCLIC_FF };
    String result = fs.chooseFile(fileName + ".jclic", true, filters, rb.getOptions(), null, this, false);
    if (result != null) {
      String fullFileName = fs.getFullFileNamePath(result);
      try {
        FileOutputStream fos = fs.createSecureFileOutputStream(fullFileName, false);
        JDomUtility.saveDocument(fos, new org.jdom.Document(element));
        fos.close();
        // addRecentFile(fileName);
      } catch (Exception ex) {
        rb.getOptions().getMessages().showErrorWarning(this, "FILE_ERR_SAVING", fullFileName, ex, null);
      }
    }
  } // GEN-LAST:event_saveBtnActionPerformed

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

    if (currentNode != null && current != null && !current.getElement().isRootElement()) {
      if (clip == currentNode)
        clip = null;
      current.getElement().detach();
      ((DefaultTreeModel) tree.getModel()).removeNodeFromParent(currentNode);
      setTableModel();
    }
  } // GEN-LAST:event_delElementBtnActionPerformed

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

    if (currentNode != null && current != null) {
      String s = current.getElement().getText();
      if (s == null || s.length() == 0) {
        JTextField[] fields = new JTextField[] { new JTextField() };
        Dimension dim = new Dimension(100, 20);
        for (int i = 0; i < fields.length; i++)
          fields[i].setPreferredSize(dim);
        String[] promptKeys = new String[] { "XML_NAME" };
        if (rb.getOptions().getMessages().showInputDlg(JDomTreePanel.this, null, promptKeys, fields,
            "XML_NEW_ELEMENT")) {
          String elementName = fields[0].getText();
          if (elementName != null && elementName.length() > 0) {
            org.jdom.Element el = new org.jdom.Element(elementName);
            current.getElement().addContent(el);
            JDomTreeObject te = new JDomTreeObject(el, rb.getOptions());
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(te);
            ((DefaultTreeModel) tree.getModel()).insertNodeInto(node, currentNode, currentNode.getChildCount());
            setTableModel();
          }
        }
      }
    }
  } // GEN-LAST:event_newElementBtnActionPerformed

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

    if (current != null) {
      int r = table.getSelectedRow();
      if (r >= 0) {
        if (r == 0) {
          List<org.jdom.Text> toRemove = new ArrayList<org.jdom.Text>();
          List<?> ls = current.getElement().getContent();
          for (Object o : ls) {
            if (o instanceof org.jdom.Text)
              toRemove.add((org.jdom.Text) o);
          }
          ls.removeAll(toRemove);
        } else {
          String s = (String) current.getValueAt(r, 0);
          if (s != null)
            current.getElement().removeAttribute(s);
        }
        setTableModel();
      }
    }
  } // GEN-LAST:event_delAttributeBtnActionPerformed

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

    if (current != null) {
      JTextField[] fields = new JTextField[] { new JTextField(), new JTextField() };
      Dimension dim = new Dimension(100, 20);
      for (int i = 0; i < fields.length; i++)
        fields[i].setPreferredSize(dim);
      String[] promptKeys = new String[] { "XML_ATTRIBUTE", "XML_VALUE" };
      if (rb.getOptions().getMessages().showInputDlg(JDomTreePanel.this, null, promptKeys, fields,
          "XML_NEW_ATTRIBUTE")) {
        String atrName = fields[0].getText();
        String atrValue = fields[1].getText();
        if (atrName != null && atrValue != null && atrName.length() > 0) {
          current.getElement().setAttribute(atrName, atrValue);
          setTableModel();
        }
      }
    }
  } // GEN-LAST:event_newAttributeBtnActionPerformed

  public static org.jdom.Element editElement(Component parent, org.jdom.Element element, ResourceBridge rb,
      FileSystem fs, String fileName, String titleKey) {
    org.jdom.Element clon = (org.jdom.Element) element.clone();
    boolean b = rb.getOptions().getMessages().showInputDlg(parent, new JDomTreePanel(clon, rb, fs, fileName), titleKey);
    return b ? clon : null;
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton copyBtn;
  private javax.swing.JButton cutBtn;
  private javax.swing.JButton delAttributeBtn;
  private javax.swing.JButton delElementBtn;
  private javax.swing.JButton newAttributeBtn;
  private javax.swing.JButton newElementBtn;
  private javax.swing.JButton pasteBtn;
  private javax.swing.JButton saveBtn;
  private javax.swing.JTable table;
  private javax.swing.JTree tree;
  // End of variables declaration//GEN-END:variables

}
