/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.content.packager;

import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.crosswalk.CrosswalkException;
import org.dspace.core.Constants;
import org.dspace.core.Context;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * An abstract implementation of a DSpace Package Disseminator, which
 * implements a few helper/utility methods that most (all?) PackageDisseminators
 * may find useful.
 * <P>
 * First, implements recursive functionality in the disseminateAll()
 * method of the PackageIngester interface.  This method is setup to
 * recursively call disseminate() method.
 * <P>
 * All Package disseminators should either extend this abstract class
 * or implement <code>PackageDisseminator</code> to better suit their needs.
 *
 * @author Tim Donohue
 * @see PackageDisseminator
 */
public abstract class AbstractPackageDisseminator
        implements PackageDisseminator
{
    /**  List of all successfully disseminated package files */
    private List<File> packageFileList = new ArrayList<File>();

    /**
     * Recursively export one or more DSpace Objects as a series of packages.
     * This method will export the given DSpace Object as well as all referenced
     * DSpaceObjects (e.g. child objects) into a series of packages. The
     * initial object is exported to the location specified by the OutputStream.
     * All other packages are exported to the same directory location.
     * <p>
     * Package is any serialized representation of the item, at the discretion
     * of the implementing class.  It does not have to include content bitstreams.
     * <br>
     * Use the <code>params</code> parameter list to adjust the way the
     * package is made, e.g. including a "<code>metadataOnly</code>"
     * parameter might make the package a bare manifest in XML
     * instead of a Zip file including manifest and contents.
     * <br>
     * Throws an exception of the initial object is not acceptable or there is
     * a failure creating the package.
     *
     * @param context  DSpace context.
     * @param dso  initial DSpace object
     * @param params Properties-style list of options specific to this packager
     * @param pkgFile File where initial package should be written. All other
     *          packages will be written to the same directory as this File.
     * @throws PackageValidationException if package cannot be created or there is
     *  a fatal error in creating it.
     */
    public List<File> disseminateAll(Context context, DSpaceObject dso,
                     PackageParameters params, File pkgFile)
        throws PackageException, CrosswalkException,
               AuthorizeException, SQLException, IOException
    {
        //If unset, make sure the Parameters specifies this is a recursive dissemination
        if(!params.recursiveModeEnabled())
        {
            params.setRecursiveModeEnabled(true);
        }

        //try to disseminate the first object using provided PackageDisseminator
        disseminate(context, dso, params, pkgFile);

        //check if package was disseminated
        if(pkgFile.exists())
        {
            //add to list of successfully disseminated packages
            addToPackageList(pkgFile);

            //We can only recursively disseminate non-Items
            //(NOTE: Items have no children, as Bitstreams/Bundles are created from Item packages)
            if(dso.getType()!=Constants.ITEM)
            {
                //Determine where first file package was disseminated to, as all
                //others will be written to same directory
                String pkgDirectory = pkgFile.getCanonicalFile().getParent();
                if(!pkgDirectory.endsWith(File.separator))
                {
                    pkgDirectory += File.separator;
                }
                String fileExtension = PackageUtils.getFileExtension(pkgFile.getName());

                //recursively disseminate content, based on object type
                switch (dso.getType())
                {
                    case Constants.COLLECTION :
                        //Also find all Items in this Collection and disseminate
                        Collection collection = (Collection) dso;
                        ItemIterator iterator = collection.getItems();
                        while(iterator.hasNext())
                        {
                            Item item = iterator.next();

                            //disseminate all items (recursively!)
                            String childFileName = pkgDirectory + PackageUtils.getPackageName(item, fileExtension);
                            disseminateAll(context, item, params, new File(childFileName));
                        }

                        break;
                    case Constants.COMMUNITY :
                        //Also find all SubCommunities in this Community and disseminate
                        Community community = (Community) dso;
                        Community[] subcommunities = community.getSubcommunities();
                        for(int i=0; i<subcommunities.length; i++)
                        {
                            //disseminate all sub-communities (recursively!)
                            String childFileName = pkgDirectory + PackageUtils.getPackageName(subcommunities[i], fileExtension);
                            disseminateAll(context, subcommunities[i], params, new File(childFileName));
                        }

                        //Also find all Collections in this Community and disseminate
                        Collection[] collections = community.getCollections();
                        for(int i=0; i<collections.length; i++)
                        {
                            //disseminate all collections (recursively!)
                            String childFileName = pkgDirectory + PackageUtils.getPackageName(collections[i], fileExtension);
                            disseminateAll(context, collections[i], params, new File(childFileName));
                        }

                        break;
                    case Constants.SITE :
                        //Also find all top-level Communities and disseminate
                        Community[] topCommunities = Community.findAllTop(context);
                        for(int i=0; i<topCommunities.length; i++)
                        {
                            //disseminate all top-level communities (recursively!)
                            String childFileName = pkgDirectory + PackageUtils.getPackageName(topCommunities[i], fileExtension);
                            disseminateAll(context, topCommunities[i], params, new File(childFileName));
                        }

                        break;
                }//end switch
            }//end if not an Item
        }//end if pkgFile exists

        //return list of all successfully disseminated packages
        return getPackageList();
    }

    /**
     * Add File to list of successfully disseminated package files
     * @param file File
     */
    protected void addToPackageList(File f)
    {
        //add to list of successfully disseminated packages
        packageFileList.add(f);
    }

    /**
     * Return List of all package Files which have been disseminated
     * this instance of the Disseminator.
     * <P>
     * This list can be useful in reporting back to the user what content has
     * been disseminated as packages.  It's used by disseminateAll() to report
     * what packages were created.
     *
     * @return List of Files which correspond to the disseminated packages
     */
    protected List<File> getPackageList()
    {
        return packageFileList;
    }
}

@@ -3023,24 +3023,39 @@
 .%0D%0A     */%0D%0A
+    @Override%0D%0A
     public L
@@ -7863,32 +7863,89 @@
 nated packages%0D%0A
+        if(!packageFileList.contains(f))%0D%0A        %7B%0D%0A    
         packageF
@@ -7957,24 +7957,35 @@
 st.add(f);%0D%0A
+        %7D%0D%0A
     %7D%0D%0A%0D%0A   

Fix minor bug in count of packages disseminated. Before adding a package to list of those disseminated, make sure it isn't already listed. This only occurs for mapped item packages, which may be listed multiple places and were accidently being counted multiple times.