/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.vv.infrastructure.log;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.primitives.service.PrimitivesService;

public final class SecureLoggerUtil {
	private static PrimitivesService primitivesService;
	
	private SecureLoggerUtil() {
	}
	
    private synchronized static PrimitivesService getPrimitivesService() {
        if (primitivesService == null) {
            try {
                primitivesService = new PrimitivesService();
            } catch (GeneralCryptoLibException e) {
                throw new IllegalStateException(e);
            }
        }
        return primitivesService;
    }

    public static <K, V> List<V> getValuesOrderedByKeyList(List<K> keyList, Map<K, V> valuesMap) {
        ArrayList<V> orderedComputedOptionRepresentations = new ArrayList<>();
        for (K orderedKey : keyList) {
            orderedComputedOptionRepresentations.add(valuesMap.get(orderedKey));
        }
        return orderedComputedOptionRepresentations;
    }

    public static String getHashForLogFromBigIntegerCollection(List<BigInteger> elements)
            throws GeneralCryptoLibException {
        return getHashForLogFromCollectionWithMapper(elements, BigInteger::toByteArray);
    }

    public static String getHashForLogFromZpGroupElementIntegerCollection(List<ZpGroupElement> elements)
            throws GeneralCryptoLibException {
        Function<ZpGroupElement, byte[]> mapper = element -> element.getValue().toByteArray();
        return getHashForLogFromCollectionWithMapper(elements, mapper);

    }

    public static String getHashForLogFromExponentCollection(List<Exponent> elements) throws GeneralCryptoLibException {
        Function<Exponent, byte[]> mapper = element -> element.getValue().toByteArray();
        return getHashForLogFromCollectionWithMapper(elements, mapper);

    }

    private static <T> String getHashForLogFromCollectionWithMapper(List<T> elements, Function<T, byte[]> mapper)
            throws GeneralCryptoLibException {
        PrimitivesService ps = getPrimitivesService();
        StringBuilder sBuilder = new StringBuilder();
        sBuilder.append("[");
        boolean first = true;
        Encoder encoder = Base64.getEncoder();
        for (T object : elements) {
            byte[] value = mapper.apply(object);
            if (first) {
                first = false;
            } else {
                sBuilder.append(";");
            }
            byte[] valueHash = ps.getHash(value);
            sBuilder.append(encoder.encodeToString(valueHash));
        }
        sBuilder.append("]");
        return sBuilder.toString();
    }
}
