/*
 * Copyright 2010-2016 Grzegorz Slowikowski
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.code.play;

import java.lang.reflect.Method;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.maven.plugins.annotations.Component;

import org.codehaus.plexus.archiver.AbstractArchiver;
import org.codehaus.plexus.archiver.ArchiveEntry;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ResourceIterator;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.archiver.war.WarArchiver;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import org.codehaus.plexus.components.io.resources.PlexusIoResource;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.io.RawInputStreamFacade;

/**
 * Base class for Play&#33; packaging mojos.
 * 
 * @author <a href="mailto:gslowikowski@gmail.com">Grzegorz Slowikowski</a>
 */
public abstract class AbstractArchivingMojo
    extends AbstractDependencyProcessingPlayMojo
{

    /**
     * To look up Archiver/UnArchiver implementations.
     * 
     */
    @Component
    private ArchiverManager archiverManager;

    protected void expandArchive( Archiver archiver, File destDirectory )
        throws IOException
    {
        for ( ResourceIterator iter = archiver.getResources(); iter.hasNext(); )
        {
            ArchiveEntry entry = iter.next();
            String name = entry.getName();
            name = name.replace( File.separatorChar, '/' );
            File destFile = new File( destDirectory, name );

            switch ( entry.getType() )
            {
                case ArchiveEntry.DIRECTORY:
                    getLog().debug( "adding directory " + destFile.getAbsolutePath() );
                    if ( !destFile.exists() && !destFile.mkdirs() )
                    {
                        throw new IOException( "Unable to create directory: " + destFile );
                    }
                    break;
                case ArchiveEntry.FILE:
                    getLog().debug( "adding file " + destFile.getAbsolutePath() );
                    PlexusIoResource resource = entry.getResource();
                    boolean skip = false;
                    if ( destFile.exists() )
                    {
                        long resLastModified = resource.getLastModified();
                        if ( resLastModified != PlexusIoResource.UNKNOWN_MODIFICATION_DATE )
                        {
                            long destFileLastModified = destFile.lastModified();
                            if ( resLastModified <= destFileLastModified )
                            {
                                skip = true;
                            }
                        }
                    }
                    if ( !skip )
                    {
                        InputStream contents = resource.getContents();
                        RawInputStreamFacade facade = new RawInputStreamFacade( contents );
                        FileUtils.copyStreamToFile( facade, destFile );
                    }
                    break;
                default:
                    throw new ArchiverException( "Unknown archive entry type: " + entry.getType() );
            }
        }

        // Ugly hack to close input streams (cleanUp() method is protected)
        try
        {
            Method cleanUpMethod = AbstractArchiver.class.getDeclaredMethod( "cleanUp" );
            cleanUpMethod.setAccessible( true );
            cleanUpMethod.invoke( archiver );
        }
        catch ( Exception e )
        {
            getLog().info( "Error: " + e.getMessage() ); //FIXME
            // ignore
        }
    }
    
    protected ZipArchiver getZipArchiver() throws NoSuchArchiverException
    {
        ZipArchiver result = (ZipArchiver) archiverManager.getArchiver( "zip" );
        result.setDuplicateBehavior( Archiver.DUPLICATES_FAIL ); // Just in case
        return result;
    }
    
    protected WarArchiver getWarArchiver() throws NoSuchArchiverException
    {
        WarArchiver result = (WarArchiver) archiverManager.getArchiver( "war" );
        result.setDuplicateBehavior( Archiver.DUPLICATES_FAIL ); // Just in case
        return result;
    }

    /**
     * Check for potential "Duplicate file" exception before archive processing starts
     * 
     * @param archiver
     */
    protected void checkArchiverForProblems( Archiver archiver )
    {
        for ( ResourceIterator iter = archiver.getResources(); iter.hasNext(); )
        {
            iter.next();
        }
    }

}

@@ -2338,16 +2338,88 @@
 ECTORY:%0A
+                    if ( !destFile.exists() )%0A                    %7B%0A    
         
@@ -2472,38 +2472,26 @@
 %22 + 
-destFile.getAbsolutePath() );%0A
+name + '/' );%0A    
     
@@ -2514,30 +2514,8 @@
 if (
- !destFile.exists() &&
  !de
@@ -2544,34 +2544,42 @@
                 
-%7B%0A
+    %7B%0A    
                 
@@ -2646,32 +2646,58 @@
 %22 + destFile );%0A
+                        %7D%0A
                 
@@ -2773,91 +2773,8 @@
 LE:%0A
-                    getLog().debug( %22adding file %22 + destFile.getAbsolutePath() );%0A
     
@@ -2905,16 +2905,17 @@
    if ( 
+!
 destFile
@@ -2940,32 +2940,166 @@
               %7B%0A
+                        getLog().debug( %22adding file %22 + name );%0A                    %7D%0A                    else%0A                    %7B%0A
                 
@@ -3529,32 +3529,200 @@
               %7D%0A
+                            else%0A                            %7B%0A                                getLog().debug( %22updating file %22 + name );%0A                            %7D%0A
                 

Refactor AbstractArchivingMojo.expandArchive(Archiver, File) method - more readable and precise debug messages.