/*
 * 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.commons.dto;

import static java.util.Arrays.asList;
import static java.util.Arrays.copyOf;
import static org.junit.Assert.assertEquals;

import java.math.BigInteger;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalComputationsValues;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;

/**
 * Tests of {@link ElGamalComputationsValuesCodecImpl}.
 */
public class ElGamalComputationsValuesCodecImplTest {
    private static final BigInteger P = BigInteger.valueOf(23);

    private static final BigInteger Q = BigInteger.valueOf(11);

    private static final BigInteger VALUE1 = BigInteger.valueOf(2);

    private static final BigInteger VALUE2 = BigInteger.valueOf(4);

    private static final BigInteger VALUE3 = BigInteger.valueOf(8);

    private static final BigInteger VALUE4 = BigInteger.valueOf(16);

    private static final BigInteger VALUE5 = BigInteger.valueOf(9);

    private static final BigInteger VALUE6 = BigInteger.valueOf(18);

    private ZpGroupElement element1;

    private ZpGroupElement element2;

    private ZpGroupElement element3;

    private ZpGroupElement element4;

    private ZpGroupElement element5;

    private ZpGroupElement element6;

    private ElGamalComputationsValuesCodec codec;

    @Before
    public void setUp() throws GeneralCryptoLibException {
        element1 = new ZpGroupElement(VALUE1, P, Q);
        element2 = new ZpGroupElement(VALUE2, P, Q);
        element3 = new ZpGroupElement(VALUE3, P, Q);
        element4 = new ZpGroupElement(VALUE4, P, Q);
        element5 = new ZpGroupElement(VALUE5, P, Q);
        element6 = new ZpGroupElement(VALUE6, P, Q);
        codec = ElGamalComputationsValuesCodecImpl.getInstance();
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testDecodeListTrancated()
            throws GeneralCryptoLibException {
        ElGamalComputationsValues values1 =
            new ElGamalComputationsValues(asList(element1, element2));
        ElGamalComputationsValues values2 =
            new ElGamalComputationsValues(asList(element3, element4));
        ElGamalComputationsValues values3 =
            new ElGamalComputationsValues(asList(element5, element6));
        List<ElGamalComputationsValues> list =
            asList(values1, values2, values3);

        String encoding = codec.encodeList(list);
        byte[] bytes = Base64.getDecoder().decode(encoding);
        bytes = copyOf(bytes, bytes.length - 1);
        encoding = Base64.getEncoder().encodeToString(bytes);

        codec.decodeList(encoding);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testDecodeMapTrancated() throws GeneralCryptoLibException {
        ElGamalComputationsValues values1 =
            new ElGamalComputationsValues(asList(element1, element2));
        ElGamalComputationsValues values2 =
            new ElGamalComputationsValues(asList(element3, element4));
        ElGamalComputationsValues values3 =
            new ElGamalComputationsValues(asList(element5, element6));
        Map<ElGamalComputationsValues, ElGamalComputationsValues> map =
            new HashMap<>();
        map.put(values1, values2);
        map.put(values2, values3);
        map.put(values3, values1);

        String encoding = codec.encodeMap(map);
        byte[] bytes = Base64.getDecoder().decode(encoding);
        bytes = copyOf(bytes, bytes.length - 1);
        encoding = Base64.getEncoder().encodeToString(bytes);

        codec.decodeMap(encoding);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void testDecodeSingleTrancated()
            throws GeneralCryptoLibException {
        ElGamalComputationsValues values =
            new ElGamalComputationsValues(asList(element1, element2));

        String encoding = codec.encodeSingle(values);
        byte[] bytes = Base64.getDecoder().decode(encoding);
        bytes = copyOf(bytes, bytes.length - 1);
        encoding = Base64.getEncoder().encodeToString(bytes);

        codec.decodeSingle(encoding);
    }

    @Test
    public void testEncodeList() throws GeneralCryptoLibException {
        ElGamalComputationsValues values1 =
            new ElGamalComputationsValues(asList(element1, element2));
        ElGamalComputationsValues values2 =
            new ElGamalComputationsValues(asList(element3, element4));
        ElGamalComputationsValues values3 =
            new ElGamalComputationsValues(asList(element5, element6));
        List<ElGamalComputationsValues> list =
            asList(values1, values2, values3);

        String encoding = codec.encodeList(list);

        List<ElGamalComputationsValues> list2 = codec.decodeList(encoding);
        assertEquals(list.size(), list2.size());
        for (int i = 0; i < list.size(); i++) {
            assertEquals(list.get(i), list2.get(i));
        }
    }

    @Test
    public void testEncodeMap() throws GeneralCryptoLibException {
        ElGamalComputationsValues values1 =
            new ElGamalComputationsValues(asList(element1, element2));
        ElGamalComputationsValues values2 =
            new ElGamalComputationsValues(asList(element3, element4));
        ElGamalComputationsValues values3 =
            new ElGamalComputationsValues(asList(element5, element6));
        Map<ElGamalComputationsValues, ElGamalComputationsValues> map =
            new HashMap<>();
        map.put(values1, values2);
        map.put(values2, values3);
        map.put(values3, values1);

        String encoding = codec.encodeMap(map);

        Map<ElGamalComputationsValues, ElGamalComputationsValues> map2 =
            codec.decodeMap(encoding);
        assertEquals(map.size(), map2.size());
        assertEquals(values2, map2.get(values1));
        assertEquals(values3, map2.get(values2));
        assertEquals(values1, map2.get(values3));
    }

    @Test
    public void testEncodeSingle() throws GeneralCryptoLibException {
        ElGamalComputationsValues values =
            new ElGamalComputationsValues(asList(element1, element2));

        String encoding = codec.encodeSingle(values);

        assertEquals(values, codec.decodeSingle(encoding));
    }
}
