/*******************************************************************************
 * Copyright (c) 2014 Jens Reimann.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Jens Reimann - initial API and implementation
 *******************************************************************************/
package de.dentrassi.pm.aspect.common.eclipse;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.osgi.framework.Constants;

import com.google.common.io.ByteStreams;
import com.google.gson.GsonBuilder;

import de.dentrassi.pm.aspect.common.osgi.OsgiExtractor;
import de.dentrassi.pm.aspect.virtual.Virtualizer;
import de.dentrassi.pm.common.ArtifactInformation;
import de.dentrassi.pm.common.MetaKey;
import de.dentrassi.pm.osgi.bundle.BundleInformation;

public class MavenSourceBundleVirtualizer implements Virtualizer
{

    @Override
    public void virtualize ( final Context context )
    {
        final ArtifactInformation ai = context.getArtifactInformation ();
        if ( !ai.getName ().endsWith ( "-sources.jar" ) )
        {
            return;
        }

        final BundleInformation bi = findBundleInformation ( context );
        if ( bi == null )
        {
            return;
        }

        try
        {
            createSourceBundle ( context, bi );
        }
        catch ( final Exception e )
        {
            throw new RuntimeException ( "Failed to create virtual source bundle", e );
        }
    }

    protected void createSourceBundle ( final Context context, final BundleInformation bi ) throws Exception
    {
        final Map<MetaKey, String> providedMetaData = new HashMap<> ();

        final Path tmp = Files.createTempFile ( "src-", null );
        try
        {
            final String name = String.format ( "%s.source_%s.jar", bi.getId (), bi.getVersion () );

            createSourceBundle ( tmp, context, bi );

            try ( BufferedInputStream in = new BufferedInputStream ( new FileInputStream ( tmp.toFile () ) ) )
            {
                context.createVirtualArtifact ( name, in, providedMetaData );
            }
        }
        finally
        {
            Files.deleteIfExists ( tmp );
        }
    }

    private void createSourceBundle ( final Path tmp, final Context context, final BundleInformation bi ) throws Exception
    {
        try ( ZipInputStream zis = new ZipInputStream ( new BufferedInputStream ( new FileInputStream ( context.getFile ().toFile () ) ) );
              ZipOutputStream zos = new ZipOutputStream ( new BufferedOutputStream ( new FileOutputStream ( tmp.toFile () ) ) ) )
        {
            ZipEntry entry;
            while ( ( entry = zis.getNextEntry () ) != null )
            {
                if ( entry.getName ().equals ( "META-INF/MANIFEST.MF" ) )
                {
                    continue;
                }

                zos.putNextEntry ( entry );
                ByteStreams.copy ( zis, zos );

            }

            entry = new ZipEntry ( "META-INF/MANIFEST.MF" );
            zos.putNextEntry ( entry );
            final Manifest mf = new Manifest ();
            fillManifest ( mf, bi );
            mf.write ( zos );

            if ( bi.getLocalization () != null && !bi.getLocalization ().isEmpty () )
            {
                for ( final Map.Entry<String, Properties> le : bi.getLocalization ().entrySet () )
                {
                    final String locale = le.getKey ();
                    final String suffix = locale != null && !locale.isEmpty () ? "_" + locale : "";
                    entry = new ZipEntry ( bi.getLocalization () + suffix );
                    zos.putNextEntry ( entry );
                    le.getValue ().store ( zos, null );
                }
            }
        }
    }

    private void fillManifest ( final Manifest mf, final BundleInformation bi )
    {
        final Attributes attr = mf.getMainAttributes ();

        attr.put ( Attributes.Name.MANIFEST_VERSION, "1.0" );

        attr.putValue ( Constants.BUNDLE_SYMBOLICNAME, bi.getId () + ".source" );
        attr.putValue ( Constants.BUNDLE_VERSION, bi.getVersion () );
        attr.putValue ( Constants.BUNDLE_MANIFESTVERSION, "2" );
        attr.putValue ( Constants.BUNDLE_VENDOR, bi.getVendor () );
        attr.putValue ( Constants.BUNDLE_NAME, String.format ( "Source bundle for '%s'", bi.getId () ) );

        attr.putValue ( "Created-By", "Package Drone" );

        attr.putValue ( "Eclipse-SourceBundle", makeSourceString ( bi ) );

        if ( bi.getBundleLocalization () != null )
        {
            attr.putValue ( Constants.BUNDLE_LOCALIZATION, bi.getBundleLocalization () );
        }
    }

    private String makeSourceString ( final BundleInformation bi )
    {
        final StringBuilder sb = new StringBuilder ();

        sb.append ( bi.getId () );
        sb.append ( ';' );
        sb.append ( "version=\"" ).append ( bi.getVersion () ).append ( "\"" );
        sb.append ( ';' );
        sb.append ( "roots:=" );
        sb.append ( "\".\"" );

        return sb.toString ();
    }

    private BundleInformation findBundleInformation ( final Context context )
    {
        final ArtifactInformation parent = context.getOtherArtifactInformation ( context.getArtifactInformation ().getParentId () );
        if ( parent == null )
        {
            return null;
        }

        final String biString = parent.getMetaData ().get ( new MetaKey ( OsgiExtractor.NAMESPACE, OsgiExtractor.KEY_BUNDLE_INFORMATION ) );

        final GsonBuilder gb = new GsonBuilder ();
        return gb.create ().fromJson ( biString, BundleInformation.class );
    }
}

@@ -95,16 +95,22 @@
 (c) 2014
+, 2015
  Jens Re
@@ -116,16 +116,16 @@
 eimann.%0A
-
  * All r
@@ -1042,16 +1042,73 @@
 nstants;
+%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;
 %0A%0Aimport
@@ -1498,16 +1498,121 @@
 alizer%0A%7B
+%0A    private final static Logger logger = LoggerFactory.getLogger ( MavenSourceBundleVirtualizer.class );
 %0A%0A    @O
@@ -1748,24 +1748,172 @@
 rmation ();%0A
+%0A        if ( ai.getParentId () == null )%0A        %7B%0A            logger.debug ( %22don't create - parent id is null%22 );%0A            return;%0A        %7D%0A%0A
         if (
@@ -1960,32 +1960,99 @@
 %22 ) )%0A        %7B%0A
+            logger.debug ( %22don't create - name does not match%22 );%0A
             retu
@@ -2156,32 +2156,32 @@
  ( bi == null )%0A
-
         %7B%0A      
@@ -2166,32 +2166,112 @@
 ull )%0A        %7B%0A
+            logger.debug ( %22don't create - parent has no bundle information%22 );%0A
             retu

check for parent id and log