/*
 * 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.mixnet.commons.io.ciphertext;

import static java.util.Collections.emptyList;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
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.ZpGroupElement;

public class CiphertextDeserializer extends JsonDeserializer<Ciphertext> {

    private static final String DELIMITER_WITHIN_ELEMENTS = ";";

    private static final String DELIMITER_BETWEEN_ELEMENTS = ",";

    @Override
    public Ciphertext deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {

        try {

            JsonNode tree = jp.readValueAsTree();
            Iterator<Entry<String, JsonNode>> fieldNameIt = tree.fields();

            ZpGroupElement gamma = null;
            List<ZpGroupElement> phis = emptyList();

            while (fieldNameIt.hasNext()) {

                Entry<String, JsonNode> current = fieldNameIt.next();
                String key = current.getKey();
                String value = current.getValue().asText();

                if ("gamma".equals(key)) {
                    gamma = deserializeGamma(value);
                } else if ("phis".equals(key)) {
                    phis = deserializePhis(value);
                }
            }

            return new CiphertextImpl(gamma, phis);

        } catch (GeneralCryptoLibException e) {
            throw new IOException("Exception when trying to deserialize ciphertext", e);
        }
    }

	private static List<ZpGroupElement> deserializePhis(String value) throws GeneralCryptoLibException {
        List<ZpGroupElement> phis = new ArrayList<>();
        if (!value.contains(DELIMITER_BETWEEN_ELEMENTS)) {

            String[] parts = value.split(DELIMITER_WITHIN_ELEMENTS);
            BigInteger phiValue = new BigInteger(parts[0]);
            BigInteger phiP = new BigInteger(parts[1]);
            BigInteger phiQ = new BigInteger(parts[2]);

            phis.add(new ZpGroupElement(phiValue, phiP, phiQ));

        } else {

            String[] arrayOfPhis = value.split(DELIMITER_BETWEEN_ELEMENTS);

            for (int i = 0; i < arrayOfPhis.length; i++) {

                String[] parts = arrayOfPhis[i].split(DELIMITER_WITHIN_ELEMENTS);
                BigInteger phiValue = new BigInteger(parts[0]);
                BigInteger phiP = new BigInteger(parts[1]);
                BigInteger phiQ = new BigInteger(parts[2]);

                phis.add(new ZpGroupElement(phiValue, phiP, phiQ));
            }
        }
        return phis;
    }

	private static ZpGroupElement deserializeGamma(String value) throws GeneralCryptoLibException {
        String[] parts = value.split(DELIMITER_WITHIN_ELEMENTS);

        BigInteger gammaValue = new BigInteger(parts[0]);
        BigInteger gammaP = new BigInteger(parts[1]);
        BigInteger gammaQ = new BigInteger(parts[2]);

        return new ZpGroupElement(gammaValue, gammaP, gammaQ);
    }
}
