package net.sf.jabref.gui.auximport;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.nio.file.Path;
import java.util.Optional;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.logic.auxparser.AuxParser;
import net.sf.jabref.logic.auxparser.AuxParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.database.BibDatabase;

import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.FormLayout;

/**
 * A wizard dialog for generating a new sub database from existing TeX AUX file
 */
public class FromAuxDialog extends JDialog {

    private final JPanel statusPanel = new JPanel();
    private final JPanel buttons = new JPanel();
    private final JButton generateButton = new JButton();
    private final JButton cancelButton = new JButton();
    private final JButton parseButton = new JButton();

    private final JComboBox<String> dbChooser = new JComboBox<>();
    private JTextField auxFileField;

    private JList<String> notFoundList;
    private JTextArea statusInfos;

    // all open databases from JabRefFrame
    private final JTabbedPane parentTabbedPane;

    private boolean generatePressed;

    private AuxParser auxParser;

    private final JabRefFrame parentFrame;


    public FromAuxDialog(JabRefFrame frame, String title, boolean modal, JTabbedPane viewedDBs) {
        super(frame, title, modal);

        parentTabbedPane = viewedDBs;
        parentFrame = frame;

        jbInit();
        pack();
        setSize(600, 500);
    }

    private void jbInit() {
        JPanel panel1 = new JPanel();

        panel1.setLayout(new BorderLayout());
        generateButton.setText(Localization.lang("Generate"));
        generateButton.setEnabled(false);
        generateButton.addActionListener(e -> {
            generatePressed = true;
            dispose();
        });
        cancelButton.setText(Localization.lang("Cancel"));
        cancelButton.addActionListener(e -> dispose());

        parseButton.setText(Localization.lang("Parse"));
        parseButton.addActionListener(e -> parseActionPerformed());

        initPanels();

        // insert the buttons
        ButtonBarBuilder bb = new ButtonBarBuilder();
        JPanel buttonPanel = bb.getPanel();
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        bb.addGlue();
        bb.addButton(parseButton);
        bb.addRelatedGap();
        bb.addButton(generateButton);
        bb.addButton(cancelButton);
        bb.addGlue();
        this.setModal(true);
        this.setResizable(true);
        this.setTitle(Localization.lang("AUX file import"));
        JLabel desc = new JLabel("<html><h3>" + Localization.lang("AUX file import") + "</h3><p>"
                + Localization.lang("This feature generates a new database based on which entries "
                        + "are needed in an existing LaTeX document.")
                + "</p>" + "<p>"
                + Localization.lang("You need to select one of your open databases from which to choose "
                        + "entries, as well as the AUX file produced by LaTeX when compiling your document.")
                + "</p></html>");
        desc.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        panel1.add(desc, BorderLayout.NORTH);

        JPanel centerPane = new JPanel(new BorderLayout());
        centerPane.add(buttons, BorderLayout.NORTH);
        centerPane.add(statusPanel, BorderLayout.CENTER);

        getContentPane().add(panel1, BorderLayout.NORTH);
        getContentPane().add(centerPane, BorderLayout.CENTER);
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);

        // Key bindings:
        ActionMap am = statusPanel.getActionMap();
        InputMap im = statusPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
        am.put("close", new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

    }

    private void initPanels() {
        // collect the names of all open databases
        int len = parentTabbedPane.getTabCount();
        int toSelect = -1;
        for (int i = 0; i < len; i++) {
            dbChooser.addItem(parentTabbedPane.getTitleAt(i));
            if (parentFrame.getBasePanelAt(i) == parentFrame.getCurrentBasePanel()) {
                toSelect = i;
            }
        }
        if (toSelect >= 0) {
            dbChooser.setSelectedIndex(toSelect);
        }

        auxFileField = new JTextField("", 25);
        JButton browseAuxFileButton = new JButton(Localization.lang("Browse"));

        FileDialog dialog = new FileDialog(parentFrame).withExtension(FileExtensions.AUX);
        dialog.setDefaultExtension(FileExtensions.AUX);
        browseAuxFileButton.addActionListener(e -> {
            Optional<Path> file = dialog.showDialogAndGetSelectedFile();
            file.ifPresent(f -> auxFileField.setText(f.toAbsolutePath().toString()));
        });

        notFoundList = new JList<>();
        JScrollPane listScrollPane = new JScrollPane(notFoundList);
        statusInfos = new JTextArea("", 5, 20);
        JScrollPane statusScrollPane = new JScrollPane(statusInfos);
        statusInfos.setEditable(false);

        DefaultFormBuilder b = new DefaultFormBuilder(new FormLayout("left:pref, 4dlu, fill:pref:grow, 4dlu, left:pref", ""), buttons);
        b.appendSeparator(Localization.lang("Options"));
        b.append(Localization.lang("Reference database") + ":");
        b.append(dbChooser, 3);
        b.nextLine();
        b.append(Localization.lang("LaTeX AUX file") + ":");
        b.append(auxFileField);
        b.append(browseAuxFileButton);
        b.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        b = new DefaultFormBuilder(new FormLayout("fill:pref:grow, 4dlu, fill:pref:grow", "pref, pref, fill:pref:grow"),
                statusPanel);
        b.appendSeparator(Localization.lang("Result"));
        b.append(Localization.lang("Unknown BibTeX entries") + ":");
        b.append(Localization.lang("Messages") + ":");
        b.nextLine();
        b.append(listScrollPane);
        b.append(statusScrollPane);
        b.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    }

    private void parseActionPerformed() {
        parseButton.setEnabled(false);
        BasePanel bp = (BasePanel) parentTabbedPane.getComponentAt(dbChooser.getSelectedIndex());
        notFoundList.removeAll();
        statusInfos.setText(null);
        BibDatabase refBase = bp.getDatabase();
        String auxName = auxFileField.getText();

        if ((auxName != null) && (refBase != null) && !auxName.isEmpty()) {
            auxParser = new AuxParser(auxName, refBase);
            AuxParserResult result = auxParser.parse();
            notFoundList.setListData(result.getUnresolvedKeys().toArray(new String[result.getUnresolvedKeys().size()]));
            statusInfos.append(result.getInformation(false));

            generateButton.setEnabled(true);

            // the generated database contains no entries -> no active generate-button
            if (!result.getGeneratedBibDatabase().hasEntries()) {
                statusInfos.append("\n" + Localization.lang("empty database"));
                generateButton.setEnabled(false);
            }
        } else {
            generateButton.setEnabled(false);
        }

        parseButton.setEnabled(true);
    }

    public boolean generatePressed() {
        return generatePressed;
    }

    public BibDatabase getGenerateDB() {
        return auxParser.parse().getGeneratedBibDatabase();
    }

}
