/*
 * 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 com.scytl.products.ov.commons.beans.domain.model.messaging.SafeStreamDeserializationException;
import static com.scytl.products.ov.commons.safestream.StreamSerializableUtil.retrieveStringValueWithNullCheck;
import static com.scytl.products.ov.commons.safestream.StreamSerializableUtil.storeStringValueWithNullCheck;

import java.io.IOException;
import java.util.UUID;

import org.msgpack.core.MessagePacker;
import org.msgpack.core.MessageUnpacker;

import com.scytl.products.ov.commons.beans.domain.model.messaging.StreamSerializable;
import com.scytl.products.ov.commons.beans.domain.model.messaging.StreamSerializableClassType;
import com.scytl.products.ov.commons.safestream.StreamSerializableUtil;

public class ChoiceCodeVerificationDTO<T> extends CorrelatedSupport implements StreamSerializable, WithDTOResultsKeyFields {

    private String electionEventId;

    private String verificationCardSetId;

    private String verificationCardId;

    private String requestId;

    private T payload;
    
    public ChoiceCodeVerificationDTO() {
    }

    public ChoiceCodeVerificationDTO(UUID correlationId, String requestId, String electionEventId, 
            String verificationCardSetId, String verificationCardId, T payload) {
        super(correlationId);
        this.requestId = requestId;
        this.payload = payload;
        this.electionEventId = electionEventId;
        this.verificationCardSetId = verificationCardSetId;
        this.verificationCardId = verificationCardId;
    }

    public String getElectionEventId() {
        return electionEventId;
    }

    public void setElectionEventId(String electionEventId) {
        this.electionEventId = electionEventId;
    }

    public String getVerificationCardSetId() {
        return verificationCardSetId;
    }

    public void setVerificationCardSetId(String verificationCardSetId) {
        this.verificationCardSetId = verificationCardSetId;
    }

    public String getVerificationCardId() {
        return verificationCardId;
    }

    public void setVerificationCardId(String verificationCardId) {
        this.verificationCardId = verificationCardId;
    }

    public String getRequestId() {
        return requestId;
    }

    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }

    public T getPayload() {
        return payload;
    }

    public void setPayload(T payload) {
        this.payload = payload;
    }

    @Override
    public String[] getResultsKeyFields() {
        return new String[] {getElectionEventId(), getVerificationCardId(), getRequestId() };
    }

    @Override
    public void serialize(MessagePacker packer) throws IOException {
        storeStringValueWithNullCheck(packer, getCorrelationId().toString());
        storeStringValueWithNullCheck(packer, electionEventId);
        storeStringValueWithNullCheck(packer, verificationCardSetId);
        storeStringValueWithNullCheck(packer, verificationCardId);
        storeStringValueWithNullCheck(packer, requestId);
        if(payload instanceof StreamSerializable) {
            packer.packString(((StreamSerializable) payload).type().name());
            ((StreamSerializable) payload).serialize(packer);
        } else if(payload instanceof String) {
            packer.packString(String.class.getName());
            storeStringValueWithNullCheck(packer, (String) payload);
        } else {
            throw new IOException(payload.getClass().getName() + " type is not supported");
        }
        
    }

    @SuppressWarnings("unchecked")
    @Override
    public void deserialize(MessageUnpacker unpacker) throws SafeStreamDeserializationException {
        try {
            setCorrelationId(UUID.fromString(retrieveStringValueWithNullCheck(unpacker)));
            this.electionEventId = retrieveStringValueWithNullCheck(unpacker);
            this.verificationCardSetId = retrieveStringValueWithNullCheck(unpacker);
            this.verificationCardId = retrieveStringValueWithNullCheck(unpacker);
            this.requestId = retrieveStringValueWithNullCheck(unpacker);
            String unpackString = unpacker.unpackString();
            if(String.class.getName().equals(unpackString)) {
                payload = (T) retrieveStringValueWithNullCheck(unpacker);
            } else {
                StreamSerializable resolveByName = (StreamSerializable) StreamSerializableUtil.resolveByName(unpackString);
                resolveByName.deserialize(unpacker);
                payload = (T) resolveByName;
            }
        } catch (IOException e) {
            throw new SafeStreamDeserializationException(e);
        }
        
    }

    @Override
    public StreamSerializableClassType type() {
        return StreamSerializableClassType.CHOICE_CODE_VERIFICATION_DTO;
    }
}
