package com.fitbank.pdfmerger;

import lombok.extern.slf4j.Slf4j;
import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import javax.swing.Box;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileFilter;

/**
 * Programa para juntar PDFs
 *
 * @author FitBank CI
 */
@Slf4j
public class Main extends javax.swing.JFrame {

    private File currentFile = null;

    private List<PageSourceProvider> providers =
            new LinkedList<PageSourceProvider>();

    private OutputStream out = null;

    private int numberOfPages = -1;

    private boolean oneAsJPG = false;

    private final Object lock = new Object();

    public Main() {
        this(null, - 1, null, false);
    }

    public Main(OutputStream out, int numberOfPages, PageSourceProvider provider,
            boolean oneAsJPG) {
        this.out = out;
        this.numberOfPages = numberOfPages;
        this.oneAsJPG = oneAsJPG;

        initComponents();

        pdfFileChooser.setFileFilter(new FileFilter() {

            @Override
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().toLowerCase().endsWith(
                        ".pdf");
            }

            @Override
            public String getDescription() {
                return "PDF Files";
            }

        });

        if (out == null) {
            mainToolbar.remove(acceptButton);
            mainToolbar.remove(cancelButton);
        } else {
            mainToolbar.remove(newButton);
            mainToolbar.remove(openButton);
            mainToolbar.remove(saveButton);
            mainToolbar.remove(saveAsButton);
            setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
        }

        if (provider != null) {
            providers.add(provider);
            setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
        }

        providers.add(new FilePageSourceProvider(this, contentsFileChooser));

        setLocationRelativeTo(null);
    }

    public void waitDone() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        pagesListModel = new com.fitbank.pdfmerger.PagesListModel();
        pdfFileChooser = new javax.swing.JFileChooser();
        contentsFileChooser = new javax.swing.JFileChooser();
        mainToolbar = new javax.swing.JToolBar();
        newButton = new javax.swing.JButton();
        openButton = new javax.swing.JButton();
        saveButton = new javax.swing.JButton();
        saveAsButton = new javax.swing.JButton();
        acceptButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        mainSplitPane = new javax.swing.JSplitPane();
        pagesPanel = new javax.swing.JPanel();
        pagesScrollPane = new javax.swing.JScrollPane();
        pages = new javax.swing.JList();
        pagesToolbar = new javax.swing.JToolBar();
        add = new javax.swing.JButton();
        remove = new javax.swing.JButton();
        up = new javax.swing.JButton();
        down = new javax.swing.JButton();
        previewPane = new javax.swing.JScrollPane();
        previewPanel = new javax.swing.JPanel();

        contentsFileChooser.setFileSelectionMode(javax.swing.JFileChooser.FILES_AND_DIRECTORIES);
        contentsFileChooser.setMultiSelectionEnabled(true);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("PDF Merger");
        setMinimumSize(new java.awt.Dimension(640, 480));

        mainToolbar.setFloatable(false);
        mainToolbar.setRollover(true);

        newButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/document-new.png"))); // NOI18N
        newButton.setText("Nuevo");
        newButton.setFocusable(false);
        newButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        newButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        newButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(newButton);

        openButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/document-open.png"))); // NOI18N
        openButton.setText("Abrir");
        openButton.setFocusable(false);
        openButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        openButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        openButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(openButton);

        saveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/document-save.png"))); // NOI18N
        saveButton.setText("Guardar");
        saveButton.setEnabled(false);
        saveButton.setFocusable(false);
        saveButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        saveButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        saveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(saveButton);

        saveAsButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/document-save-as.png"))); // NOI18N
        saveAsButton.setText("Guardar como...");
        saveAsButton.setFocusable(false);
        saveAsButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        saveAsButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        saveAsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(saveAsButton);

        acceptButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/document-save.png"))); // NOI18N
        acceptButton.setText("Aceptar");
        acceptButton.setFocusable(false);
        acceptButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        acceptButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        acceptButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                acceptButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(acceptButton);

        cancelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/edit-clear.png"))); // NOI18N
        cancelButton.setText("Cancelar");
        cancelButton.setFocusable(false);
        cancelButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        cancelButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });
        mainToolbar.add(cancelButton);

        getContentPane().add(mainToolbar, java.awt.BorderLayout.NORTH);

        mainSplitPane.setDividerLocation(250);

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

        pages.setModel(pagesListModel);
        pages.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                pagesValueChanged(evt);
            }
        });
        pagesScrollPane.setViewportView(pages);

        pagesPanel.add(pagesScrollPane, java.awt.BorderLayout.CENTER);

        pagesToolbar.setFloatable(false);
        pagesToolbar.setOrientation(1);
        pagesToolbar.setRollover(true);

        add.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/list-add.png"))); // NOI18N
        add.setFocusable(false);
        add.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        add.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        add.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addActionPerformed(evt);
            }
        });
        pagesToolbar.add(add);

        remove.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/list-remove.png"))); // NOI18N
        remove.setEnabled(false);
        remove.setFocusable(false);
        remove.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        remove.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        remove.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeActionPerformed(evt);
            }
        });
        pagesToolbar.add(remove);

        up.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/go-up.png"))); // NOI18N
        up.setEnabled(false);
        up.setFocusable(false);
        up.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        up.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        up.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                upActionPerformed(evt);
            }
        });
        pagesToolbar.add(up);

        down.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/freedesktop/tango/16x16/actions/go-down.png"))); // NOI18N
        down.setEnabled(false);
        down.setFocusable(false);
        down.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        down.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        down.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downActionPerformed(evt);
            }
        });
        pagesToolbar.add(down);

        pagesPanel.add(pagesToolbar, java.awt.BorderLayout.WEST);

        mainSplitPane.setLeftComponent(pagesPanel);

        previewPanel.setLayout(new javax.swing.BoxLayout(previewPanel, javax.swing.BoxLayout.LINE_AXIS));
        previewPane.setViewportView(previewPanel);

        mainSplitPane.setRightComponent(previewPane);

        getContentPane().add(mainSplitPane, java.awt.BorderLayout.CENTER);

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

    private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
        currentFile = null;
        pagesListModel.newPDF();

        previewPanel.removeAll();
        previewPanel.repaint();
        saveButton.setEnabled(false);
    }//GEN-LAST:event_newButtonActionPerformed

    private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
        if (pdfFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            currentFile = pdfFileChooser.getSelectedFile();
            pagesListModel.loadPDF(currentFile);

            previewPanel.removeAll();
            saveButton.setEnabled(true);
        }
    }//GEN-LAST:event_openButtonActionPerformed

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
        try {
            pagesListModel.savePDF(currentFile);

            saveButton.setEnabled(false);
        } catch (IOException e) {
            JOptionPane.showMessageDialog(this, "Error al guardar: " + e);
        }
    }//GEN-LAST:event_saveButtonActionPerformed

    private void saveAsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsButtonActionPerformed
        if (pdfFileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            currentFile = pdfFileChooser.getSelectedFile();
            if (!currentFile.getName().endsWith(".pdf")) {
                currentFile = new File(currentFile.getAbsoluteFile() + ".pdf");
            }
            saveButtonActionPerformed(evt);
        }
    }//GEN-LAST:event_saveAsButtonActionPerformed

    private void upActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upActionPerformed
        pages.setSelectedIndices(pagesListModel.moveUp(
                pages.getSelectedIndices()));
        saveButton.setEnabled(currentFile != null);
    }//GEN-LAST:event_upActionPerformed

    private void downActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downActionPerformed
        pages.setSelectedIndices(pagesListModel.moveDown(pages.
                getSelectedIndices()));
        saveButton.setEnabled(currentFile != null);
    }//GEN-LAST:event_downActionPerformed

    private void addActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addActionPerformed
        PageSourceProvider provider;

        if (providers.size() > 1) {
            provider = (PageSourceProvider) JOptionPane.showInputDialog(this,
                    "Escoja la fuente de ingreso",
                    "Fuente", JOptionPane.QUESTION_MESSAGE, null,
                    providers.toArray(), providers.get(0));
        } else {
            provider = providers.get(0);
        }

        pagesListModel.addAll(pages.getSelectedIndex() + 1,
                provider.getPageSources());

        saveButton.setEnabled(currentFile != null);
    }//GEN-LAST:event_addActionPerformed

    private void removeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeActionPerformed
        pagesListModel.removeAll(pages.getSelectedIndices());
        pages.clearSelection();
        previewPanel.repaint();
        saveButton.setEnabled(currentFile != null);
    }//GEN-LAST:event_removeActionPerformed

    private void pagesValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_pagesValueChanged
        boolean hasSelection = pages.getSelectedIndices().length > 0;

        up.setEnabled(hasSelection && pages.getSelectedIndex() > 0);
        down.setEnabled(hasSelection && pages.getSelectedIndex() + 1 < pagesListModel.
                getSize());
        remove.setEnabled(hasSelection);

        previewPanel.removeAll();

        if (pages.getSelectedIndices().length == 0) {
            return;
        }

        PageSource pageSource = (PageSource) pages.getSelectedValue();
        Component component = pageSource.getPreview();

        previewPanel.add(Box.createHorizontalGlue());
        previewPanel.add(component);
        previewPanel.add(Box.createHorizontalGlue());
        SwingUtilities.updateComponentTreeUI(this);
        pages.requestFocusInWindow();
    }//GEN-LAST:event_pagesValueChanged

    private void acceptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_acceptButtonActionPerformed
        if (numberOfPages != -1 && pagesListModel.getSize() != numberOfPages) {
            JOptionPane.showMessageDialog(this, "Se requieren exactamente "
                    + numberOfPages + " páginas, pero actualmente hay "
                    + pagesListModel.getSize());
            return;
        }

        try {
            if (oneAsJPG && pagesListModel.getSize() == 1) {
                pagesListModel.saveJPG(out);
            } else {
                pagesListModel.savePDF(out);
            }
        } catch (Exception e) {
            log.error("", e);
        }

        setVisible(false);
    }//GEN-LAST:event_acceptButtonActionPerformed

    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
        setVisible(false);
    }//GEN-LAST:event_cancelButtonActionPerformed

    @Override
    public void setVisible(boolean b) {
        if (!b) {
            synchronized (lock) {
                lock.notify();
            }
        }
        super.setVisible(b);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Main().setVisible(true);
            }

        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton acceptButton;
    private javax.swing.JButton add;
    private javax.swing.JButton cancelButton;
    private javax.swing.JFileChooser contentsFileChooser;
    private javax.swing.JButton down;
    private javax.swing.JSplitPane mainSplitPane;
    private javax.swing.JToolBar mainToolbar;
    private javax.swing.JButton newButton;
    private javax.swing.JButton openButton;
    private javax.swing.JList pages;
    private com.fitbank.pdfmerger.PagesListModel pagesListModel;
    private javax.swing.JPanel pagesPanel;
    private javax.swing.JScrollPane pagesScrollPane;
    private javax.swing.JToolBar pagesToolbar;
    private javax.swing.JFileChooser pdfFileChooser;
    private javax.swing.JScrollPane previewPane;
    private javax.swing.JPanel previewPanel;
    private javax.swing.JButton remove;
    private javax.swing.JButton saveAsButton;
    private javax.swing.JButton saveButton;
    private javax.swing.JButton up;
    // End of variables declaration//GEN-END:variables

}
