/*
 * Copyright 2021 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.changedetection.state;

import org.gradle.internal.hash.FileContentType;
import org.gradle.internal.hash.FileContentTypeDetectingInputStream;
import org.gradle.internal.hash.HashCode;
import org.gradle.internal.hash.StreamHasher;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.function.Function;

public class NormalizedContentInfoCollector {
    private final Function<InputStream, InputStream> streamDecorator;
    private final StreamHasher streamHasher;

    public NormalizedContentInfoCollector(Function<InputStream, InputStream> normalizingStreamDecorator, StreamHasher streamHasher) {
        this.streamDecorator = normalizingStreamDecorator;
        this.streamHasher = streamHasher;
    }

    public NormalizedContentInfo collect(InputStream inputStream) {
        FileContentTypeDetectingInputStream contentTypeDetectingInputStream = new FileContentTypeDetectingInputStream(inputStream);
        InputStream normalizedInputStream = streamDecorator.apply(contentTypeDetectingInputStream);

        try {
            HashCode hashCode = streamHasher.hash(normalizedInputStream);
            return new NormalizedContentInfo(hashCode, contentTypeDetectingInputStream.getContentType());
        } finally {
            try {
                contentTypeDetectingInputStream.close();
            } catch (IOException ignored) {
                // Ignored
            }

            try {
                normalizedInputStream.close();
            } catch (IOException ignored) {
                // Ignored
            }
        }
    }

    public NormalizedContentInfo collect(File file) {
        try {
            return collect(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            throw new UncheckedIOException(String.format("Failed to create MD5 hash for file '%s' as it does not exist.", file), e);
        }
    }

    public static class NormalizedContentInfo {
        private final HashCode hash;
        private final FileContentType contentType;

        public NormalizedContentInfo(HashCode hash, FileContentType contentType) {
            this.hash = hash;
            this.contentType = contentType;
        }

        public FileContentType getContentType() {
            return contentType;
        }

        public HashCode getHash() {
            return hash;
        }
    }
}

@@ -1094,16 +1094,394 @@
 ction;%0A%0A
+/**%0A * Collects content normalization information about a file including whether the file is text or binary and the normalized hash%0A * produced by hashing the file using the provided input stream decorator.  New content normalizations can be produced by providing%0A * a decorator that creates a new input stream that filters the provided input stream in some meaningful way.%0A */%0A
 public c
@@ -2785,41 +2785,75 @@
     
-try %7B%0A            return collect(
+FileInputStream inputStream;%0A        try %7B%0A          inputStream = 
 new 
@@ -2873,17 +2873,16 @@
 am(file)
-)
 ;%0A      
@@ -3054,32 +3054,251 @@
 , e);%0A        %7D%0A
+        try %7B%0A            return collect(inputStream);%0A        %7D finally %7B%0A            try %7B%0A                inputStream.close();%0A            %7D catch (IOException e) %7B%0A                // Ignored%0A            %7D%0A        %7D%0A
     %7D%0A%0A    publi

Fix unclosed file input stream