/*
 * 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.elgamal.bean;

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

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

/**
 * Class which encapsulates a gamma and a set of phi values that are of generic
 * type.
 * <P>
 * This class is used to represent the result of ElGamal computations. These
 * computations include pre-computations and as well as encryptions. Instances
 * of this class can therefore act as both an input or as an output, depending
 * on the operation being performed.
 * 
 * @param <T>
 *            type of the group.
 */
public class BaseElGamalComputationsValues<T extends GroupElement<?>>
        extends AbstractJsonSerializable {

    /**
     * Gamma to be used by subclasses.
     */
    protected final T _gamma;

    /**
     * Phis to be used by subclasses.
     */
    protected final List<T> _phis;

    /**
     * Creates a BaseElGamalComputationsValues using the specified gamma and phi
     * values.
     * 
     * @param gamma
     *            the gamma (first element) of the ciphertext.
     * @param phis
     *            the phis of the ciphertext.
     * @throws GeneralCryptoLibException
     *             if the gamma element is null or the list of phi elements is
     *             null, empty or contains one or more null values.
     */
    public BaseElGamalComputationsValues(final T gamma, final List<T> phis)
            throws GeneralCryptoLibException {
        Validate.notNull(gamma, "ElGamal gamma element");
        Validate.notNullOrEmptyAndNoNulls(phis,
            "List of ElGamal phi elements");

        _gamma = gamma;
        _phis = new ArrayList<>(phis);
    }

    /**
     * Creates a {@code BaseElGamalComputationsValues} using the specified list
     * of elements. This list must fulfill this contract:
     * <ul>
     * <li>The first element has to be the {@code gamma}.</li>
     * <li>The other elements have to be the {@code phis} in the correct
     * order.</li>
     * <li>All elements should be members of the same mathematical group.</li>
     * </ul>
     * 
     * @param ciphertext
     *            the sequence of the elements, first the {@code gamma}, then
     *            the phis with the correct order.
     * @throws GeneralCryptoLibException
     *             if the ciphertext is null, empty or contains one or more null
     *             values.
     */
    public BaseElGamalComputationsValues(final List<T> ciphertext)
            throws GeneralCryptoLibException {
        Validate.notNullOrEmptyAndNoNulls(ciphertext,
            "ElGamal ciphertext");
        Validate.notLessThan(ciphertext.size(), 2,
            "ElGamal ciphertext length", "");

        _gamma = ciphertext.get(0);
        _phis = new ArrayList<T>(ciphertext.subList(1, ciphertext.size()));
    }

    public final T getGamma() {
        return _gamma;
    }

    public final List<T> getPhis() {
        return new ArrayList<>(_phis);
    }

    /**
     * Get a single list containing all the values of this
     * {@code BaseElGamalComputationsValues}. First the {@code gamma} , followed
     * by all of the {@code phi} values in order.
     * 
     * @return a single list containing all of the values of this
     *         {@code BaseElGamalComputationsValues} (gamma and phis).
     */
    public final List<T> getValues() {

        List<T> result = new ArrayList<T>(_phis.size() + 1);

        result.add(_gamma);
        result.addAll(_phis);

        return result;
    }
}
