/**
 * This class file was automatically generated by jASN1 v1.6.0 (http://www.openmuc.org)
 */

package org.openmuc.josistack.internal.acse.asn1;

import java.io.IOException;
import java.io.InputStream;

import org.openmuc.jasn1.ber.BerByteArrayOutputStream;
import org.openmuc.jasn1.ber.BerIdentifier;
import org.openmuc.jasn1.ber.BerLength;
import org.openmuc.jasn1.ber.types.BerBitString;
import org.openmuc.jasn1.ber.types.BerObjectIdentifier;

public class AARQApdu {

    public static final BerIdentifier identifier = new BerIdentifier(BerIdentifier.APPLICATION_CLASS,
            BerIdentifier.CONSTRUCTED, 0);
    protected BerIdentifier id;

    public byte[] code = null;
    public BerBitString protocolVersion = null;

    public BerObjectIdentifier applicationContextName = null;

    public APTitle calledAPTitle = null;

    public AEQualifier calledAEQualifier = null;

    public APInvocationIdentifier calledAPInvocationIdentifier = null;

    public AEInvocationIdentifier calledAEInvocationIdentifier = null;

    public APTitle callingAPTitle = null;

    public AEQualifier callingAEQualifier = null;

    public APInvocationIdentifier callingAPInvocationIdentifier = null;

    public AEInvocationIdentifier callingAEInvocationIdentifier = null;

    public ACSERequirements senderAcseRequirements = null;

    public MechanismName mechanismName = null;

    public AuthenticationValue callingAuthenticationValue = null;

    public ApplicationContextNameList applicationContextNameList = null;

    public ImplementationData implementationInformation = null;

    public AssociationInformation userInformation = null;

    public AARQApdu() {
        id = identifier;
    }

    public AARQApdu(byte[] code) {
        id = identifier;
        this.code = code;
    }

    public AARQApdu(BerBitString protocolVersion, BerObjectIdentifier applicationContextName, APTitle calledAPTitle,
            AEQualifier calledAEQualifier, APInvocationIdentifier calledAPInvocationIdentifier,
            AEInvocationIdentifier calledAEInvocationIdentifier, APTitle callingAPTitle, AEQualifier callingAEQualifier,
            APInvocationIdentifier callingAPInvocationIdentifier, AEInvocationIdentifier callingAEInvocationIdentifier,
            ACSERequirements senderAcseRequirements, MechanismName mechanismName,
            AuthenticationValue callingAuthenticationValue, ApplicationContextNameList applicationContextNameList,
            ImplementationData implementationInformation, AssociationInformation userInformation) {
        id = identifier;
        this.protocolVersion = protocolVersion;
        this.applicationContextName = applicationContextName;
        this.calledAPTitle = calledAPTitle;
        this.calledAEQualifier = calledAEQualifier;
        this.calledAPInvocationIdentifier = calledAPInvocationIdentifier;
        this.calledAEInvocationIdentifier = calledAEInvocationIdentifier;
        this.callingAPTitle = callingAPTitle;
        this.callingAEQualifier = callingAEQualifier;
        this.callingAPInvocationIdentifier = callingAPInvocationIdentifier;
        this.callingAEInvocationIdentifier = callingAEInvocationIdentifier;
        this.senderAcseRequirements = senderAcseRequirements;
        this.mechanismName = mechanismName;
        this.callingAuthenticationValue = callingAuthenticationValue;
        this.applicationContextNameList = applicationContextNameList;
        this.implementationInformation = implementationInformation;
        this.userInformation = userInformation;
    }

    public int encode(BerByteArrayOutputStream os, boolean explicit) throws IOException {

        int codeLength;

        if (code != null) {
            codeLength = code.length;
            for (int i = code.length - 1; i >= 0; i--) {
                os.write(code[i]);
            }
        }
        else {
            codeLength = 0;
            int sublength;

            if (userInformation != null) {
                codeLength += userInformation.encode(os, false);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 30
                os.write(0xbe);
                codeLength += 1;
            }

            if (implementationInformation != null) {
                codeLength += implementationInformation.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 29
                os.write(0x9d);
                codeLength += 1;
            }

            if (applicationContextNameList != null) {
                codeLength += applicationContextNameList.encode(os, false);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 13
                os.write(0xad);
                codeLength += 1;
            }

            if (callingAuthenticationValue != null) {
                sublength = callingAuthenticationValue.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 12
                os.write(0xac);
                codeLength += 1;
            }

            if (mechanismName != null) {
                codeLength += mechanismName.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 11
                os.write(0x8b);
                codeLength += 1;
            }

            if (senderAcseRequirements != null) {
                codeLength += senderAcseRequirements.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 10
                os.write(0x8a);
                codeLength += 1;
            }

            if (callingAEInvocationIdentifier != null) {
                sublength = callingAEInvocationIdentifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 9
                os.write(0xa9);
                codeLength += 1;
            }

            if (callingAPInvocationIdentifier != null) {
                sublength = callingAPInvocationIdentifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 8
                os.write(0xa8);
                codeLength += 1;
            }

            if (callingAEQualifier != null) {
                sublength = callingAEQualifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 7
                os.write(0xa7);
                codeLength += 1;
            }

            if (callingAPTitle != null) {
                sublength = callingAPTitle.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 6
                os.write(0xa6);
                codeLength += 1;
            }

            if (calledAEInvocationIdentifier != null) {
                sublength = calledAEInvocationIdentifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 5
                os.write(0xa5);
                codeLength += 1;
            }

            if (calledAPInvocationIdentifier != null) {
                sublength = calledAPInvocationIdentifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 4
                os.write(0xa4);
                codeLength += 1;
            }

            if (calledAEQualifier != null) {
                sublength = calledAEQualifier.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 3
                os.write(0xa3);
                codeLength += 1;
            }

            if (calledAPTitle != null) {
                sublength = calledAPTitle.encode(os, true);
                codeLength += sublength;
                codeLength += BerLength.encodeLength(os, sublength);
                // write tag: CONTEXT_CLASS, CONSTRUCTED, 2
                os.write(0xa2);
                codeLength += 1;
            }

            sublength = applicationContextName.encode(os, true);
            codeLength += sublength;
            codeLength += BerLength.encodeLength(os, sublength);
            // write tag: CONTEXT_CLASS, CONSTRUCTED, 1
            os.write(0xa1);
            codeLength += 1;

            if (protocolVersion != null) {
                codeLength += protocolVersion.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 0
                os.write(0x80);
                codeLength += 1;
            }

            codeLength += BerLength.encodeLength(os, codeLength);
        }

        if (explicit) {
            codeLength += id.encode(os);
        }

        return codeLength;

    }

    public int decode(InputStream is, boolean explicit) throws IOException {
        int codeLength = 0;
        int subCodeLength = 0;
        BerIdentifier berIdentifier = new BerIdentifier();

        if (explicit) {
            codeLength += id.decodeAndCheck(is);
        }

        BerLength length = new BerLength();
        codeLength += length.decode(is);

        int totalLength = length.val;
        codeLength += totalLength;

        subCodeLength += berIdentifier.decode(is);
        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 0)) {
            protocolVersion = new BerBitString();
            subCodeLength += protocolVersion.decode(is, false);
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 1)) {
            subCodeLength += length.decode(is);
            applicationContextName = new BerObjectIdentifier();
            subCodeLength += applicationContextName.decode(is, true);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }
        else {
            throw new IOException("Identifier does not match the mandatory sequence element identifer.");
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 2)) {
            subCodeLength += length.decode(is);
            calledAPTitle = new APTitle();
            subCodeLength += calledAPTitle.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 3)) {
            subCodeLength += length.decode(is);
            calledAEQualifier = new AEQualifier();
            subCodeLength += calledAEQualifier.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 4)) {
            subCodeLength += length.decode(is);
            calledAPInvocationIdentifier = new APInvocationIdentifier();
            subCodeLength += calledAPInvocationIdentifier.decode(is, true);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 5)) {
            subCodeLength += length.decode(is);
            calledAEInvocationIdentifier = new AEInvocationIdentifier();
            subCodeLength += calledAEInvocationIdentifier.decode(is, true);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 6)) {
            subCodeLength += length.decode(is);
            callingAPTitle = new APTitle();
            subCodeLength += callingAPTitle.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 7)) {
            subCodeLength += length.decode(is);
            callingAEQualifier = new AEQualifier();
            subCodeLength += callingAEQualifier.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 8)) {
            subCodeLength += length.decode(is);
            callingAPInvocationIdentifier = new APInvocationIdentifier();
            subCodeLength += callingAPInvocationIdentifier.decode(is, true);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 9)) {
            subCodeLength += length.decode(is);
            callingAEInvocationIdentifier = new AEInvocationIdentifier();
            subCodeLength += callingAEInvocationIdentifier.decode(is, true);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 10)) {
            senderAcseRequirements = new ACSERequirements();
            subCodeLength += senderAcseRequirements.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 11)) {
            mechanismName = new MechanismName();
            subCodeLength += mechanismName.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 12)) {
            subCodeLength += length.decode(is);
            callingAuthenticationValue = new AuthenticationValue();
            subCodeLength += callingAuthenticationValue.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 13)) {
            applicationContextNameList = new ApplicationContextNameList();
            subCodeLength += applicationContextNameList.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 29)) {
            implementationInformation = new ImplementationData();
            subCodeLength += implementationInformation.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.CONSTRUCTED, 30)) {
            userInformation = new AssociationInformation();
            subCodeLength += userInformation.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
        }
        throw new IOException("Unexpected end of sequence, length tag: " + totalLength + ", actual sequence length: "
                + subCodeLength);

    }

    public void encodeAndSave(int encodingSizeGuess) throws IOException {
        BerByteArrayOutputStream os = new BerByteArrayOutputStream(encodingSizeGuess);
        encode(os, false);
        code = os.getArray();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("SEQUENCE{");
        boolean firstSelectedElement = true;
        if (protocolVersion != null) {
            sb.append("protocolVersion: ").append(protocolVersion);
            firstSelectedElement = false;
        }

        if (!firstSelectedElement) {
            sb.append(", ");
        }
        sb.append("applicationContextName: ").append(applicationContextName);

        if (calledAPTitle != null) {
            sb.append(", ");
            sb.append("calledAPTitle: ").append(calledAPTitle);
        }

        if (calledAEQualifier != null) {
            sb.append(", ");
            sb.append("calledAEQualifier: ").append(calledAEQualifier);
        }

        if (calledAPInvocationIdentifier != null) {
            sb.append(", ");
            sb.append("calledAPInvocationIdentifier: ").append(calledAPInvocationIdentifier);
        }

        if (calledAEInvocationIdentifier != null) {
            sb.append(", ");
            sb.append("calledAEInvocationIdentifier: ").append(calledAEInvocationIdentifier);
        }

        if (callingAPTitle != null) {
            sb.append(", ");
            sb.append("callingAPTitle: ").append(callingAPTitle);
        }

        if (callingAEQualifier != null) {
            sb.append(", ");
            sb.append("callingAEQualifier: ").append(callingAEQualifier);
        }

        if (callingAPInvocationIdentifier != null) {
            sb.append(", ");
            sb.append("callingAPInvocationIdentifier: ").append(callingAPInvocationIdentifier);
        }

        if (callingAEInvocationIdentifier != null) {
            sb.append(", ");
            sb.append("callingAEInvocationIdentifier: ").append(callingAEInvocationIdentifier);
        }

        if (senderAcseRequirements != null) {
            sb.append(", ");
            sb.append("senderAcseRequirements: ").append(senderAcseRequirements);
        }

        if (mechanismName != null) {
            sb.append(", ");
            sb.append("mechanismName: ").append(mechanismName);
        }

        if (callingAuthenticationValue != null) {
            sb.append(", ");
            sb.append("callingAuthenticationValue: ").append(callingAuthenticationValue);
        }

        if (applicationContextNameList != null) {
            sb.append(", ");
            sb.append("applicationContextNameList: ").append(applicationContextNameList);
        }

        if (implementationInformation != null) {
            sb.append(", ");
            sb.append("implementationInformation: ").append(implementationInformation);
        }

        if (userInformation != null) {
            sb.append(", ");
            sb.append("userInformation: ").append(userInformation);
        }

        sb.append("}");
        return sb.toString();
    }

}
