/*  Copyright (C) 2003-2011 JabRef contributors.
    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.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package net.sf.jabref.external;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.*;

import javax.swing.JDialog;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

import net.sf.jabref.*;
import net.sf.jabref.gui.FileListEntry;
import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.util.FileUtil;

/**
 * This class handles the task of looking up all external files linked for a set
 * of entries. This is useful for tasks where the user wants e.g. to send a database
 * with external files included.
 */
public class AccessLinksForEntries {

    /**
     * Look up all external files linked from (at least) one of the entries in a set.
     * This method does not verify the links.
     *
     * @param entries The set of entries.
     * @return A list of FileListEntry objects pointing to the external files.
     */
    private static List<FileListEntry> getExternalLinksForEntries(List<BibtexEntry> entries) {
        List<FileListEntry> files = new ArrayList<FileListEntry>();
        FileListTableModel model = new FileListTableModel();
        for (BibtexEntry entry : entries) {
            String links = entry.getField(GUIGlobals.FILE_FIELD);
            if (links == null) {
                continue;
            }
            model.setContent(links);
            for (int i = 0; i < model.getRowCount(); i++) {
                files.add(model.getEntry(i));
            }
        }
        return files;
    }

    /**
     * Take a list of external links and copy the referred files to a given directory.
     * This method should be run off the Event Dispatch Thread. A progress bar, if given,
     * will be updated on the EDT.
     *
     * @param files The list of file links.
     * @param toDir The directory to copy the files to.
     * @param metaData The MetaData for the database containing the external links. This is needed
     *  because the database might have its own file directory.
     * @param prog A JProgressBar which will be updated to show the progress of the process.
     *  This argument can be null if no progress bar is needed.
     * @param deleteOriginalFiles if true, the files in their original locations will be deleted
     *  after copying, for each file whose source directory is different from the destination
     *  directory differs.
     * @param callback An ActionListener which should be notified when the process is finished.
     *  This parameter can be null if no callback is needed.
     */
    private static void copyExternalLinksToDirectory(final List<FileListEntry> files, File toDir,
                                                     MetaData metaData, final JProgressBar prog,
                                                     boolean deleteOriginalFiles,
                                                     final ActionListener callback) {

        if (prog != null) {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    prog.setMaximum(files.size());
                    prog.setValue(0);
                    prog.setIndeterminate(false);
                }
            });
        }

        Set<String> fileNames = new HashSet<String>();

        int i = 0;

        for (FileListEntry entry : files) {
            File file = new File(entry.getLink());

            // We try to check the extension for the file:
            String name = file.getName();
            int pos = name.lastIndexOf('.');
            String extension = ((pos >= 0) && (pos < (name.length() - 1))) ? name.substring(pos + 1)
                    .trim().toLowerCase() : null;

            // Find the default directory for this field type, if any:
            String[] dir = metaData.getFileDirectory(extension);
            // Include the standard "file" directory:
            String[] fileDir = metaData.getFileDirectory(GUIGlobals.FILE_FIELD);
            // Include the directory of the bib file:
            ArrayList<String> al = new ArrayList<String>();
            for (String aDir : dir) {
                if (!al.contains(aDir)) {
                    al.add(aDir);
                }
            }
            for (String aFileDir : fileDir) {
                if (!al.contains(aFileDir)) {
                    al.add(aFileDir);
                }
            }

            String[] dirs = al.toArray(new String[al.size()]);
            File tmp = FileUtil.expandFilename(entry.getLink(), dirs);
            if (tmp != null) {
                file = tmp;
            }

            // Check if we have arrived at an existing file:
            if (file.exists()) {
                if (fileNames.contains(name)) {
                    // Oops, a file of that name already exists....
                } else {
                    fileNames.add(name);
                    File destination = new File(toDir, name);

                    // Check if the source and destination locations differ:
                    if (!destination.equals(file)) {
                        try {
                            // Copy the file:
                            FileUtil.copyFile(file, destination, false);
                            // Delete the original file if requested:
                            if (deleteOriginalFiles) {
                                file.delete();
                            }

                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    } else {
                        // Destination and source is the same. Do nothing.
                    }
                    // Update progress bar:
                    i++;
                    final int j = i;

                    if (prog != null) {
                        SwingUtilities.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                prog.setValue(j);
                            }
                        });
                    }
                }
            } else {
                // The link could not be resolved to an existing file.

            }
        }

        if (callback != null) {
            callback.actionPerformed(null);
        }
    }


    public static class SaveWithLinkedFiles implements BaseAction {

        private final BasePanel panel;


        public SaveWithLinkedFiles(BasePanel panel) {

            this.panel = panel;
        }

        @Override
        public void action() throws Throwable {

            ArrayList<BibtexEntry> entries = new ArrayList<BibtexEntry>();
            BibtexEntry[] sel = panel.getSelectedEntries();
            Collections.addAll(entries, sel);
            final List<FileListEntry> links =
                    AccessLinksForEntries.getExternalLinksForEntries(entries);
            for (FileListEntry entry : links) {
                System.out.println("Link: " + entry.getLink());
            }

            final JProgressBar prog = new JProgressBar();
            prog.setIndeterminate(true);
            final JDialog diag = new JDialog(panel.frame(), false);
            diag.getContentPane().add(prog, BorderLayout.CENTER);
            diag.pack();
            diag.setLocationRelativeTo(panel.frame());
            diag.setVisible(true);
            JabRefExecutorService.INSTANCE.execute(new Runnable() {

                @Override
                public void run() {
                    AccessLinksForEntries.copyExternalLinksToDirectory(links,
                            new File("/home/alver/tmp"), panel.metaData(), prog, false,
                            new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent actionEvent) {
                                    diag.dispose();
                                }
                            });
                }
            });
        }
    }

}

@@ -7178,1710 +7178,6 @@
  %7D%0A%0A
-%0A    public static class SaveWithLinkedFiles implements BaseAction %7B%0A%0A        private final BasePanel panel;%0A%0A%0A        public SaveWithLinkedFiles(BasePanel panel) %7B%0A%0A            this.panel = panel;%0A        %7D%0A%0A        @Override%0A        public void action() throws Throwable %7B%0A%0A            ArrayList%3CBibtexEntry%3E entries = new ArrayList%3CBibtexEntry%3E();%0A            BibtexEntry%5B%5D sel = panel.getSelectedEntries();%0A            Collections.addAll(entries, sel);%0A            final List%3CFileListEntry%3E links =%0A                    AccessLinksForEntries.getExternalLinksForEntries(entries);%0A            for (FileListEntry entry : links) %7B%0A                System.out.println(%22Link: %22 + entry.getLink());%0A            %7D%0A%0A            final JProgressBar prog = new JProgressBar();%0A            prog.setIndeterminate(true);%0A            final JDialog diag = new JDialog(panel.frame(), false);%0A            diag.getContentPane().add(prog, BorderLayout.CENTER);%0A            diag.pack();%0A            diag.setLocationRelativeTo(panel.frame());%0A            diag.setVisible(true);%0A            JabRefExecutorService.INSTANCE.execute(new Runnable() %7B%0A%0A                @Override%0A                public void run() %7B%0A                    AccessLinksForEntries.copyExternalLinksToDirectory(links,%0A                            new File(%22/home/alver/tmp%22), panel.metaData(), prog, false,%0A                            new ActionListener() %7B%0A%0A                                @Override%0A                                public void actionPerformed(ActionEvent actionEvent) %7B%0A                                    diag.dispose();%0A                                %7D%0A                            %7D);%0A                %7D%0A            %7D);%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Remove unused inner class with reference to hard-coded reference to local path