/*
 * 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.cryptolib.mathematical.groups.activity;

import java.util.ArrayList;
import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.commons.utils.validations.Validate;
import com.scytl.cryptolib.mathematical.groups.GroupElement;
import com.scytl.cryptolib.mathematical.groups.MathematicalGroup;

/**
 * Provides functionality for dividing the elements in one list by the elements
 * in another list.
 */
public final class GroupElementsDivider {

    /**
     * Given two lists of groups elements, this method produces a new list of
     * group elements that represents the result of dividing
     * {@code groupElementsList1} by {@code groupElementsList2}.
     * <p>
     * Note: it is assumed that all of the elements in
     * {@code groupElementsList1} and {@code groupElementsList2} are members of
     * {@code group}.
     * 
     * @param <T>
     *            the group element value type
     * @param <S>
     *            the group element type
     * @param groupElementsList1
     *            a list of group elements.
     * @param groupElementsList2
     *            a list of group elements.
     * @param group
     *            a mathematical group, that both lists should belong to.
     * @return a new list of group elements.
     * @throws GeneralCryptoLibException
     *             if either list contains any value that is not a group
     *             element.
     */
    @SuppressWarnings("unchecked")
    public <T, S extends GroupElement<T>> List<S> divide(
            final List<S> groupElementsList1,
            final List<S> groupElementsList2,
            final MathematicalGroup<S> group)
            throws GeneralCryptoLibException {

        validateInput(groupElementsList1, groupElementsList2, group);

        List<S> newList = new ArrayList<S>();

        for (int i = 0; i < groupElementsList1.size(); i++) {

            S newElement = (S) groupElementsList1.get(i)
                .multiply(groupElementsList2.get(i).invert());

            newList.add(newElement);
        }

        return newList;
    }

    private <T, S extends GroupElement<T>> void validateInput(
            final List<S> groupElementsList1,
            final List<S> groupElementsList2,
            final MathematicalGroup<S> group)
            throws GeneralCryptoLibException {

        Validate.notNullOrEmptyAndNoNulls(groupElementsList1,
            "List of elements to be divided");
        Validate.notNullOrEmptyAndNoNulls(groupElementsList2,
            "List of elements to act as divisor");
        Validate.notNull(group, "Zp subgroup");
        Validate.equals(groupElementsList1.size(),
            groupElementsList2.size(),
            "Length of element list to be divided",
            "length of element list to act as divisor");
    }
}
