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

package org.openmuc.openiec61850.internal.mms.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.BerInteger;
import org.openmuc.jasn1.ber.types.string.BerVisibleString;

public class ServiceError {

    public static class ErrorClass {

        public byte[] code = null;
        private BerInteger vmdState = null;

        private BerInteger applicationReference = null;

        private BerInteger definition = null;

        private BerInteger resource = null;

        private BerInteger service = null;

        private BerInteger servicePreempt = null;

        private BerInteger timeResolution = null;

        private BerInteger access = null;

        private BerInteger initiate = null;

        private BerInteger conclude = null;

        private BerInteger cancel = null;

        private BerInteger file = null;

        private BerInteger others = null;

        public ErrorClass() {
        }

        public ErrorClass(byte[] code) {
            this.code = code;
        }

        public void setVmdState(BerInteger vmdState) {
            this.vmdState = vmdState;
        }

        public BerInteger getVmdState() {
            return vmdState;
        }

        public void setApplicationReference(BerInteger applicationReference) {
            this.applicationReference = applicationReference;
        }

        public BerInteger getApplicationReference() {
            return applicationReference;
        }

        public void setDefinition(BerInteger definition) {
            this.definition = definition;
        }

        public BerInteger getDefinition() {
            return definition;
        }

        public void setResource(BerInteger resource) {
            this.resource = resource;
        }

        public BerInteger getResource() {
            return resource;
        }

        public void setService(BerInteger service) {
            this.service = service;
        }

        public BerInteger getService() {
            return service;
        }

        public void setServicePreempt(BerInteger servicePreempt) {
            this.servicePreempt = servicePreempt;
        }

        public BerInteger getServicePreempt() {
            return servicePreempt;
        }

        public void setTimeResolution(BerInteger timeResolution) {
            this.timeResolution = timeResolution;
        }

        public BerInteger getTimeResolution() {
            return timeResolution;
        }

        public void setAccess(BerInteger access) {
            this.access = access;
        }

        public BerInteger getAccess() {
            return access;
        }

        public void setInitiate(BerInteger initiate) {
            this.initiate = initiate;
        }

        public BerInteger getInitiate() {
            return initiate;
        }

        public void setConclude(BerInteger conclude) {
            this.conclude = conclude;
        }

        public BerInteger getConclude() {
            return conclude;
        }

        public void setCancel(BerInteger cancel) {
            this.cancel = cancel;
        }

        public BerInteger getCancel() {
            return cancel;
        }

        public void setFile(BerInteger file) {
            this.file = file;
        }

        public BerInteger getFile() {
            return file;
        }

        public void setOthers(BerInteger others) {
            this.others = others;
        }

        public BerInteger getOthers() {
            return others;
        }

        public int encode(BerByteArrayOutputStream os, boolean explicit) throws IOException {
            if (code != null) {
                for (int i = code.length - 1; i >= 0; i--) {
                    os.write(code[i]);
                }
                return code.length;

            }
            int codeLength = 0;
            if (others != null) {
                codeLength += others.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 12
                os.write(0x8c);
                codeLength += 1;
                return codeLength;

            }

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

            }

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

            }

            if (conclude != null) {
                codeLength += conclude.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 9
                os.write(0x89);
                codeLength += 1;
                return codeLength;

            }

            if (initiate != null) {
                codeLength += initiate.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 8
                os.write(0x88);
                codeLength += 1;
                return codeLength;

            }

            if (access != null) {
                codeLength += access.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 7
                os.write(0x87);
                codeLength += 1;
                return codeLength;

            }

            if (timeResolution != null) {
                codeLength += timeResolution.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 6
                os.write(0x86);
                codeLength += 1;
                return codeLength;

            }

            if (servicePreempt != null) {
                codeLength += servicePreempt.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 5
                os.write(0x85);
                codeLength += 1;
                return codeLength;

            }

            if (service != null) {
                codeLength += service.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 4
                os.write(0x84);
                codeLength += 1;
                return codeLength;

            }

            if (resource != null) {
                codeLength += resource.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 3
                os.write(0x83);
                codeLength += 1;
                return codeLength;

            }

            if (definition != null) {
                codeLength += definition.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 2
                os.write(0x82);
                codeLength += 1;
                return codeLength;

            }

            if (applicationReference != null) {
                codeLength += applicationReference.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 1
                os.write(0x81);
                codeLength += 1;
                return codeLength;

            }

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

            }

            throw new IOException("Error encoding BerChoice: No item in choice was selected.");
        }

        public int decode(InputStream is, BerIdentifier berIdentifier) throws IOException {
            int codeLength = 0;
            BerIdentifier passedIdentifier = berIdentifier;

            if (berIdentifier == null) {
                berIdentifier = new BerIdentifier();
                codeLength += berIdentifier.decode(is);
            }

            BerLength length = new BerLength();
            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 0)) {
                vmdState = new BerInteger();
                codeLength += vmdState.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 1)) {
                applicationReference = new BerInteger();
                codeLength += applicationReference.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 2)) {
                definition = new BerInteger();
                codeLength += definition.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 3)) {
                resource = new BerInteger();
                codeLength += resource.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 4)) {
                service = new BerInteger();
                codeLength += service.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 5)) {
                servicePreempt = new BerInteger();
                codeLength += servicePreempt.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 6)) {
                timeResolution = new BerInteger();
                codeLength += timeResolution.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 7)) {
                access = new BerInteger();
                codeLength += access.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 8)) {
                initiate = new BerInteger();
                codeLength += initiate.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 9)) {
                conclude = new BerInteger();
                codeLength += conclude.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 10)) {
                cancel = new BerInteger();
                codeLength += cancel.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 11)) {
                file = new BerInteger();
                codeLength += file.decode(is, false);
                return codeLength;
            }

            if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 12)) {
                others = new BerInteger();
                codeLength += others.decode(is, false);
                return codeLength;
            }

            if (passedIdentifier != null) {
                return 0;
            }
            throw new IOException("Error decoding BerChoice: Identifier matched to no item.");
        }

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

        @Override
        public String toString() {
            if (vmdState != null) {
                return "CHOICE{vmdState: " + vmdState + "}";
            }

            if (applicationReference != null) {
                return "CHOICE{applicationReference: " + applicationReference + "}";
            }

            if (definition != null) {
                return "CHOICE{definition: " + definition + "}";
            }

            if (resource != null) {
                return "CHOICE{resource: " + resource + "}";
            }

            if (service != null) {
                return "CHOICE{service: " + service + "}";
            }

            if (servicePreempt != null) {
                return "CHOICE{servicePreempt: " + servicePreempt + "}";
            }

            if (timeResolution != null) {
                return "CHOICE{timeResolution: " + timeResolution + "}";
            }

            if (access != null) {
                return "CHOICE{access: " + access + "}";
            }

            if (initiate != null) {
                return "CHOICE{initiate: " + initiate + "}";
            }

            if (conclude != null) {
                return "CHOICE{conclude: " + conclude + "}";
            }

            if (cancel != null) {
                return "CHOICE{cancel: " + cancel + "}";
            }

            if (file != null) {
                return "CHOICE{file: " + file + "}";
            }

            if (others != null) {
                return "CHOICE{others: " + others + "}";
            }

            return "unknown";
        }

    }

    public static final BerIdentifier identifier = new BerIdentifier(BerIdentifier.UNIVERSAL_CLASS,
            BerIdentifier.CONSTRUCTED, 16);
    protected BerIdentifier id;

    public byte[] code = null;
    private ErrorClass errorClass = null;

    private BerInteger additionalCode = null;

    private BerVisibleString additionalDescription = null;

    public ServiceError() {
        id = identifier;
    }

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

    public void setErrorClass(ErrorClass errorClass) {
        this.errorClass = errorClass;
    }

    public ErrorClass getErrorClass() {
        return errorClass;
    }

    public void setAdditionalCode(BerInteger additionalCode) {
        this.additionalCode = additionalCode;
    }

    public BerInteger getAdditionalCode() {
        return additionalCode;
    }

    public void setAdditionalDescription(BerVisibleString additionalDescription) {
        this.additionalDescription = additionalDescription;
    }

    public BerVisibleString getAdditionalDescription() {
        return additionalDescription;
    }

    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 (additionalDescription != null) {
                codeLength += additionalDescription.encode(os, false);
                // write tag: CONTEXT_CLASS, PRIMITIVE, 2
                os.write(0x82);
                codeLength += 1;
            }

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

            sublength = errorClass.encode(os, true);
            codeLength += sublength;
            codeLength += BerLength.encodeLength(os, sublength);
            // write tag: CONTEXT_CLASS, CONSTRUCTED, 0
            os.write(0xa0);
            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.CONSTRUCTED, 0)) {
            subCodeLength += length.decode(is);
            errorClass = new ErrorClass();
            subCodeLength += errorClass.decode(is, null);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }
        else {
            throw new IOException("Identifier does not match required sequence element identifer.");
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 1)) {
            additionalCode = new BerInteger();
            subCodeLength += additionalCode.decode(is, false);
            if (subCodeLength == totalLength) {
                return codeLength;
            }
            subCodeLength += berIdentifier.decode(is);
        }

        if (berIdentifier.equals(BerIdentifier.CONTEXT_CLASS, BerIdentifier.PRIMITIVE, 2)) {
            additionalDescription = new BerVisibleString();
            subCodeLength += additionalDescription.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{");
        sb.append("errorClass: ").append(errorClass);

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

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

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

}
