/*
 * 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.ov.mixing.commons.tools;

import java.math.BigInteger;
import java.util.List;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.CiphertextImpl;
import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.ov.mixing.shuffle.Permutation;

public final class MatrixArranger {

	/**
	 * Non-public constructor
	 */
	private MatrixArranger() {
	}
	
	/**
     * Arranges the received {@link ElGamalEncryptedBallot} into a matrix of {@link Ciphertext}.
     *
     * @param reencryptedBallots
     *            the EncryptedBallots to be arranged.
     * @param m
     *            the m parameter.
     * @param n
     *            the n parameter.
     * @return a matrix of Ciphertexts (arranged as m * n).
     */
    public static Ciphertext[][] arrangeInCiphertextMatrix(List<Ciphertext> reencryptedBallotsList, final int m,
            final int n) {

        if (reencryptedBallotsList.size() != (m * n)) {
            throw new IllegalArgumentException("Incorrect combination of m, n and ballot size: " + m + ", " + n + ", "
                + reencryptedBallotsList.size());
        }

        final Ciphertext[][] ret = new Ciphertext[m][n];

        int j = -1;
        for (int i = 0, size = reencryptedBallotsList.size(); i < size; i++) {
            final int k = i % n;
            if (k == 0) {
                j++;
            }

            try {
                // NOTE: we need to convert the structure to an equivalent CiphertextImpl to ensure that the result of
                // its toString() method is equal to the value produce when toString() is called on an equal

                ret[j][k] = new CiphertextImpl(reencryptedBallotsList.get(i).getGamma(),
                    reencryptedBallotsList.get(i).getPhis());
            } catch (GeneralCryptoLibException e) {
                throw new CryptoLibException(e);
            }
        }

        return ret;
    }

    /**
     * Transforms and arranges the received {@link Permutation} into a matrix of {@link Exponent}.
     * <P>
     * Note: all of the values in the permutation (which in reality represent indexes in a list of elements) are
     * incremented by one during this transformation.
     *
     * @param permutation
     *            the permutation to be transformed and arranged.
     * @param order
     *            the order of the group. This is needed when creating the Exponents.
     * @param m
     *            the m parameter.
     * @param n
     *            the n parameter.
     * @return a matrix of Exponents (arranged as m * n).
     */
    public static Exponent[][] transformPermutationToExponentMatrix(
            final com.scytl.ov.mixing.shuffle.Permutation permutation, final BigInteger order, final int m,
            final int n) {

        try {

            int indexIncrementedByOne;
            final Exponent[][] ret = new Exponent[m][n];
            int k = 0;
            for (int i = 0; i < m; i++, k = 0) {
                for (int j = 0; j < n; j++, k++) {
                    indexIncrementedByOne = permutation.getCorrespondingIndexInSourceList(i * n + j) + 1;
                    ret[i][k] = new Exponent(order, BigInteger.valueOf(indexIncrementedByOne));
                }
            }
            return ret;
        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }
    }
}
