/*
 *  @author Ranides Atterwim <ranides@gmail.com>
 *  @copyright Ranides Atterwim
 *  @license WTFPL
 *  @url http://ranides.net/projects/assira
 */

package net.ranides.assira.math;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import net.ranides.assira.text.TextEncoding;
import net.ranides.assira.trace.AdvLogger;
import net.ranides.assira.trace.LoggerUtils;

/**
 *
 * @author ranides
 */
public final class HashHelper {
    
    private static final AdvLogger LOGGER = LoggerUtils.getLogger();

    private HashHelper() { }

    /**
     * Wylicza hash dla podanego tekstu za pomocą określonej metody. Nazwa metody
     * jest rozpoznawana za pomocą klasy {@link MessageDigest}.
     * @param value
     * @param method
     * @return
     */
    public static String encode(String value, String method) {
        if( (null== value) || value.isEmpty() ) { 
            return null; 
        }
        try {
            MessageDigest mdt = MessageDigest.getInstance(method);
            byte[] digest = mdt.digest( value.getBytes(TextEncoding.NIO_UTF8) );
            BigInteger number = new BigInteger(1, digest);
            return number.toString(16);
        } catch (NoSuchAlgorithmException cause) {
            LOGGER.warn(cause);
            return null;
        }
    }
    
    /**
     * Tworzy HashCode kompatybilny z kodem automatycznie wygenerowanym przez NetBeans 7 IDE
     * @param initial wartość początkowa, zalecana liczba pierwsza.
     * @param multiplier mnożnik, zalecana liczba pierwsza większa o rząd wielkości większa od ilości składników
     * @param values wartości pól, na podstawie których będzie liczony HashCode
     * @return
     */
    public static int hashValues(int initial, int multiplier, Object... values) {
        return hashIterable(initial, multiplier, Arrays.asList(values));
    }
    
    /**
     * Tworzy HashCode kompatybilny z kodem automatycznie wygenerowanym przez NetBeans 7 IDE
     * @param initial wartość początkowa, zalecana liczba pierwsza.
     * @param multiplier mnożnik, zalecana liczba pierwsza większa o rząd wielkości większa od ilości składników
     * @param values wartości na podstawie których będzie liczony HashCode
     * @return
     */
    public static int hashIterable(int initial, int multiplier, Iterable<?> values) {
        int hash = initial;
        for(Object value: values) {
            hash *= multiplier;
            if(null == value) {
                continue;
            }
            if( value.getClass().isArray() ) {
                hash += Arrays.hashCode((Object[])value);
            } else {
                hash += value.hashCode();
            }
        }
        return hash;
    }

    /**
     * Wylicza hash dla podanego tekstu za pomocą metody SHA-512
     * @param value
     * @return
     */
    public static String encode(String value) {
        return encode(value, "SHA-512");
    }

}
