package com.jscape.crypto;

import com.jscape.util.HexFormat;
import com.jscape.util.io.ByteArrayOutputStream;
import com.jscape.util.io.LimitedInputStream;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;

/**
 * The hash-related  tool-set.
 *
 * @author Alex Usun
 */
public class HashTools {

    /**
     * Computes hash for the specified file.
     *
     * @param file a target file
     * @param hash a hash instance
     *
     * @return hash bytes
     *
     * @throws IOException if an error occurs
     */
    public static byte[] hashOf(File file, Hash hash)
            throws IOException {
        try (InputStream in = Files.newInputStream(file.toPath())) {
            return hashOf(in, hash);
        }
    }

    public static byte[] hashOf(InputStream in, Hash hash)
            throws IOException {
        hash.reset();

        byte[] buffer = new byte[8192];
        boolean updated = false;
        int read;
        while ((read = in.read(buffer)) != -1) {
            hash.update(buffer, 0, read);
            updated = true;
        }

        return updated ? hash.compute() : new byte[0];
    }

    public static byte[] hashOf(InputStream in, Hash hash, long sectionSize)
            throws IOException {
        ByteArrayOutputStream hashBuffer = new ByteArrayOutputStream();
        byte[] sectionHash;

        while ((sectionHash = hashOf(new LimitedInputStream(in, sectionSize, false), hash)).length > 0) {
            hashBuffer.write(sectionHash);
        }

        return hashBuffer.toByteArray();
    }

    /**
     * Computes hash for the specified file in hex format.
     *
     * @param file target file
     * @param hash a hash instance
     *
     * @return hash bytes in hex format
     *
     * @throws IOException if an error occurs
     */
    public static String hashStringOf(File file, Hash hash)
            throws IOException {
        byte[] hashBytes = hashOf(file, hash);
        return HexFormat.formatData(hashBytes, "");
    }

    /**
     * Private constructor to avoid unnecessary instantiation.
     */
    private HashTools() {
        // empty
    }
}
