/*
 * Copyright 2019 the original author or authors.
 *
 * 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 org.gradle.api.internal.artifacts.transform;

import com.google.common.collect.ImmutableSet;
import org.gradle.api.artifacts.transform.ArtifactTransform;
import org.gradle.api.artifacts.transform.ArtifactTransformAction;
import org.gradle.api.artifacts.transform.VariantTransformConfigurationException;
import org.gradle.api.internal.artifacts.ArtifactTransformRegistration;
import org.gradle.api.internal.attributes.AttributeContainerInternal;
import org.gradle.api.internal.attributes.ImmutableAttributes;
import org.gradle.api.internal.tasks.properties.InspectionSchemeFactory;
import org.gradle.api.internal.tasks.properties.PropertyWalker;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.CompileClasspath;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Nested;
import org.gradle.internal.classloader.ClassLoaderHierarchyHasher;
import org.gradle.internal.hash.Hasher;
import org.gradle.internal.hash.Hashing;
import org.gradle.internal.instantiation.InstantiatorFactory;
import org.gradle.internal.isolation.Isolatable;
import org.gradle.internal.isolation.IsolatableFactory;
import org.gradle.internal.snapshot.ValueSnapshotter;
import org.gradle.model.internal.type.ModelType;

import javax.annotation.Nullable;
import java.util.Arrays;

public class DefaultTransformationRegistrationFactory implements TransformationRegistrationFactory {

    private final IsolatableFactory isolatableFactory;
    private final ClassLoaderHierarchyHasher classLoaderHierarchyHasher;
    private final InstantiatorFactory instantiatorFactory;
    private final TransformerInvoker transformerInvoker;
    private final ValueSnapshotter valueSnapshotter;
    private final PropertyWalker propertyWalker;
    private final DomainObjectContextProjectStateHandler domainObjectContextProjectStateHandler;

    public DefaultTransformationRegistrationFactory(
        IsolatableFactory isolatableFactory,
        ClassLoaderHierarchyHasher classLoaderHierarchyHasher,
        InstantiatorFactory instantiatorFactory,
        TransformerInvoker transformerInvoker,
        ValueSnapshotter valueSnapshotter,
        InspectionSchemeFactory inspectionSchemeFactory, DomainObjectContextProjectStateHandler domainObjectContextProjectStateHandler
    ) {
        this.isolatableFactory = isolatableFactory;
        this.classLoaderHierarchyHasher = classLoaderHierarchyHasher;
        this.instantiatorFactory = instantiatorFactory;
        this.transformerInvoker = transformerInvoker;
        this.valueSnapshotter = valueSnapshotter;
        this.propertyWalker = inspectionSchemeFactory.inspectionScheme(ImmutableSet.of(Input.class, InputFile.class, InputFiles.class, InputDirectory.class, Classpath.class, CompileClasspath.class, Nested.class)).getPropertyWalker();
        this.domainObjectContextProjectStateHandler = domainObjectContextProjectStateHandler;
    }

    @Override
    public ArtifactTransformRegistration create(ImmutableAttributes from, ImmutableAttributes to, Class<? extends ArtifactTransformAction> implementation, @Nullable Object parameterObject) {
        Transformer transformer = new DefaultTransformer(
            implementation,
            parameterObject,
            instantiatorFactory,
            from,
            classLoaderHierarchyHasher,
            isolatableFactory,
            valueSnapshotter,
            propertyWalker,
            domainObjectContextProjectStateHandler);

        return new DefaultArtifactTransformRegistration(from, to, new TransformationStep(transformer, transformerInvoker));
    }

    @Override
    public ArtifactTransformRegistration create(ImmutableAttributes from, ImmutableAttributes to, Class<? extends ArtifactTransform> implementation, Object[] params) {
        Hasher hasher = Hashing.newHasher();
        appendActionImplementation(classLoaderHierarchyHasher, hasher, implementation);

        // TODO - should snapshot later
        Isolatable<Object[]> paramsSnapshot;
        try {
            paramsSnapshot = isolatableFactory.isolate(params);
        } catch (Exception e) {
            throw new VariantTransformConfigurationException(String.format("Could not snapshot parameters values for transform %s: %s", ModelType.of(implementation).getDisplayName(), Arrays.asList(params)), e);
        }
        paramsSnapshot.appendToHasher(hasher);
        Transformer transformer = new LegacyTransformer(implementation, params, instantiatorFactory, from, classLoaderHierarchyHasher, isolatableFactory);

        return new DefaultArtifactTransformRegistration(from, to, new TransformationStep(transformer, transformerInvoker));
    }

    private static void appendActionImplementation(ClassLoaderHierarchyHasher classLoaderHierarchyHasher, Hasher hasher, Class<?> implementation) {
        hasher.putString(implementation.getName());
        hasher.putHash(classLoaderHierarchyHasher.getClassLoaderHash(implementation.getClassLoader()));
    }


    private static class DefaultArtifactTransformRegistration implements ArtifactTransformRegistration {

        private final ImmutableAttributes from;
        private final ImmutableAttributes to;
        private final TransformationStep transformationStep;

        public DefaultArtifactTransformRegistration(ImmutableAttributes from, ImmutableAttributes to, TransformationStep transformationStep) {
            this.from = from;
            this.to = to;
            this.transformationStep = transformationStep;
        }

        @Override
        public AttributeContainerInternal getFrom() {
            return from;
        }

        @Override
        public AttributeContainerInternal getTo() {
            return to;
        }

        @Override
        public TransformationStep getTransformationStep() {
            return transformationStep;
        }
    }
}

@@ -843,90 +843,8 @@
 on;%0A
-import org.gradle.api.artifacts.transform.VariantTransformConfigurationException;%0A
 impo
@@ -1558,171 +1558,41 @@
 nal.
-hash.Hasher;%0Aimport org.gradle.internal.hash.Hashing;%0Aimport org.gradle.internal.instantiation.InstantiatorFactory;%0Aimport org.gradle.internal.isolation.Isolatable
+instantiation.InstantiatorFactory
 ;%0Aim
@@ -1702,57 +1702,8 @@
 ter;
-%0Aimport org.gradle.model.internal.type.ModelType;
 %0A%0Aim
@@ -1737,33 +1737,8 @@
 ble;
-%0Aimport java.util.Arrays;
 %0A%0Apu
@@ -4220,1194 +4220,285 @@
     
-Hasher hasher = Hashing.newHasher();%0A        appendActionImplementation(classLoaderHierarchyHasher, hasher, implementation);%0A%0A        // TODO - should snapshot later%0A        Isolatable%3CObject%5B%5D%3E paramsSnapshot;%0A        try %7B%0A            paramsSnapshot = isolatableFactory.isolate(params);%0A        %7D catch (Exception e) %7B%0A            throw new VariantTransformConfigurationException(String.format(%22Could not snapshot parameters values for transform %25s: %25s%22, ModelType.of(implementation).getDisplayName(), Arrays.asList(params)), e);%0A        %7D%0A        paramsSnapshot.appendToHasher(hasher);%0A        Transformer transformer = new LegacyTransformer(implementation, params, instantiatorFactory, from, classLoaderHierarchyHasher, isolatableFactory);%0A%0A        return new DefaultArtifactTransformRegistration(from, to, new TransformationStep(transformer, transformerInvoker));%0A    %7D%0A%0A    private static void appendActionImplementation(ClassLoaderHierarchyHasher classLoaderHierarchyHasher, Hasher hasher, Class%3C?%3E implementation) %7B%0A        hasher.putString(implementation.getName());%0A        hasher.putHash(classLoaderHierarchyHasher.getClassLoaderHash(implementation.getClassLoader()));%0A    %7D%0A
+Transformer transformer = new LegacyTransformer(implementation, params, instantiatorFactory, from, classLoaderHierarchyHasher, isolatableFactory);%0A%0A        return new DefaultArtifactTransformRegistration(from, to, new TransformationStep(transformer, transformerInvoker));%0A    %7D
 %0A%0A  
@@ -4600,17 +4600,16 @@
 ation %7B%0A
-%0A
         

Remove unused snapshotting code