All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.parameterarchive.AggrrayBuilder Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.parameterarchive;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.yamcs.parameter.AggregateValue;
import org.yamcs.parameter.ArrayValue;
import org.yamcs.parameter.Value;
import org.yamcs.utils.AggregateUtil;
import org.yamcs.utils.IntArray;
import org.yamcs.xtce.PathElement;
import org.yamcs.xtce.util.AggregateMemberNames;

import org.yamcs.protobuf.Yamcs.Value.Type;

/**
 * builds aggregate or array values out of members extracted from the parameter archive.
 *
 */
public class AggrrayBuilder {

    Map builders = new HashMap<>();

    ValueBuilder rootBuilder;
    String fqn;

    AggrrayBuilder(ParameterId... pids) {
        for (ParameterId pid : pids) {
            addParameterId(pid);
        }
    }

    private void addParameterId(ParameterId pid) {
        PathElement[] path = AggregateUtil.parseReference(pid.getParamFqn());

        AggregateValueBuilder builder = processRoot(pid, path[0], path.length == 1);

        if (builder == null) {
            assert (path.length == 1);
            // special case: parameter is an array of basic elements
            // they are already processed in the processRoot
            return;
        }

        PathElement pe0 = path[0];
        if (pe0.getIndex() == null) {
            builder = (AggregateValueBuilder) rootBuilder;
        } else {
            builder = createOrVerifyArrayElement((ArrayValueBuilder) rootBuilder, IntArray.wrap(pe0.getIndex()));
        }

        for (int i = 1; i < path.length - 1; i++) {
            builder = addAndCheckAggrPathElement(builder, path[i]);
        }

        // last one is special: of basic type or array of basic type
        BasicValueBuilder bvb = getBasicValueBuilder(pid);

        PathElement pe = path[path.length - 1];
        IntArray idx = pe.getIndex() == null ? null : IntArray.wrap(pe.getIndex());
        if (idx == null) {
            builder.addMember(pe.getName(), bvb);
        } else {
            ArrayValueBuilder arrb = createOrVerifyArrayMember(builder, pe.getName());
            arrb.addElement(idx, bvb);
        }
    }

    private BasicValueBuilder getBasicValueBuilder(ParameterId pid) {
        BasicValueBuilder bvb = new BasicValueBuilder();
        builders.put(pid.getPid(), bvb);
        return bvb;
    }

    // creates the necessary root structure for path[0] and returns
    // the aggregate builder where the sub-elements have to be added
    // if the root is an array, returns null
    private AggregateValueBuilder processRoot(ParameterId pid, PathElement pe0, boolean basicArray) {
        // verify the qualified name
        if (fqn == null) {
            fqn = pe0.getName();
        } else {
            if (!fqn.equals(pe0.getName())) {
                throw new ParameterArchiveException("Invalid parameter id found for aggregate or array: fqn is '"
                        + pe0.getName() + " while expecting from the first parameter '" + fqn + "'");
            }
        }

        IntArray idx = pe0.getIndex() == null ? null : IntArray.wrap(pe0.getIndex());
        if (idx == null) { // root is an aggregate
            if (rootBuilder == null) {
                rootBuilder = new AggregateValueBuilder();
            } else {
                if (!(rootBuilder instanceof AggregateValueBuilder)) {
                    throw new ParameterArchiveException("parameter is not an aggregate");
                }
            }
            return (AggregateValueBuilder) rootBuilder;
        } else { // root is an array
            if (rootBuilder == null) {
                rootBuilder = new ArrayValueBuilder();
            } else {
                if (!(rootBuilder instanceof ArrayValueBuilder)) {
                    throw new ParameterArchiveException("parameter is not an array");
                }
            }
            if (basicArray) {// special case, elements of the array are basic
                BasicValueBuilder bvb = getBasicValueBuilder(pid);
                ((ArrayValueBuilder) rootBuilder).addElement(idx, bvb);

                return null;
            } else {
                return createOrVerifyArrayElement((ArrayValueBuilder) rootBuilder, idx);
            }
        }
    }

    private AggregateValueBuilder addAndCheckAggrPathElement(AggregateValueBuilder aggb, PathElement pe) {
        if (pe.getIndex() == null) {
            return createOrVerifyAggregateMember(aggb, pe.getName());
        } else {
            ArrayValueBuilder arrb = createOrVerifyArrayMember(aggb, pe.getName());
            return createOrVerifyArrayElement(arrb, IntArray.wrap(pe.getIndex()));
        }
    }

    // creates and returns the element idx verifying also that it is an aggregate
    private AggregateValueBuilder createOrVerifyArrayElement(ArrayValueBuilder arrb, IntArray idx) {
        ValueBuilder builder = arrb.getElement(idx);
        if (builder == null) {
            AggregateValueBuilder aggb = new AggregateValueBuilder();
            arrb.addElement(idx, aggb);
            return aggb;
        } else {
            if (builder instanceof AggregateValueBuilder) {
                return (AggregateValueBuilder) builder;
            } else {
                throw new ParameterArchiveException(
                        "Expected " + idx + " element index to be an aggregate but it is " + builder.getClass());
            }
        }
    }

    ArrayValueBuilder createOrVerifyArrayMember(AggregateValueBuilder aggb, String member) {
        ValueBuilder builder = aggb.getMember(member);
        if (builder == null) {
            ArrayValueBuilder arrb = new ArrayValueBuilder();
            aggb.addMember(member, arrb);
            return arrb;
        } else {
            if (builder instanceof ArrayValueBuilder) {
                return (ArrayValueBuilder) builder;
            } else {
                throw new ParameterArchiveException(
                        "Expected '" + member + "' to be an array but it is " + builder.getClass());
            }
        }
    }

    AggregateValueBuilder createOrVerifyAggregateMember(AggregateValueBuilder aggb, String member) {
        ValueBuilder builder = aggb.getMember(member);
        if (builder == null) {
            AggregateValueBuilder arrb = new AggregateValueBuilder();
            aggb.addMember(member, arrb);
            return arrb;
        } else {
            if (builder instanceof AggregateValueBuilder) {
                return (AggregateValueBuilder) builder;
            } else {
                throw new ParameterArchiveException(
                        "Expected '" + member + "' to be an aggregate but it is " + builder.getClass());
            }
        }
    }

    public void setValue(ParameterId pid, Value v) {
        BasicValueBuilder bvb = builders.get(pid.getPid());
        if (bvb == null) {
            throw new IllegalArgumentException("Unknown parameter " + pid);
        }
        bvb.setValue(v);
    }

    public Value build() {
        return rootBuilder.build();
    }

    public void clear() {
        rootBuilder.clear();
    }

    interface ValueBuilder {
        Value build();

        void clear();
    }

    class BasicValueBuilder implements ValueBuilder {
        Value v;

        @Override
        public Value build() {
            return v;
        }

        public void setValue(Value v) {
            this.v = v;
        }

        @Override
        public void clear() {
            this.v = null;
        }

    }

    class ArrayValueBuilder implements ValueBuilder {
        Map elements = new LinkedHashMap<>();
        int[] dim = null;
        int numDim = -1;

        public void addElement(IntArray idx, ValueBuilder b) {
            if (numDim == -1) {
                numDim = idx.size();
            } else if (numDim != idx.size()) {
                throw new ParameterArchiveException("Invalid number of dimensions for index '" + idx
                        + "'; expected " + numDim);
            }
            if (elements.containsKey(idx)) {
                throw new ParameterArchiveException("Duplicate member '" + idx + "'");
            }
            elements.put(idx, b);
        }

        public ValueBuilder getElement(IntArray idx) {
            return elements.get(idx);
        }

        @Override
        public ArrayValue build() {
            if (dim == null) {
                dim = new int[numDim];
            }

            Map values = new HashMap<>();
            Type valueType = null;
            
            for (Map.Entry me : elements.entrySet()) {
                Value v = me.getValue().build();
                if (v != null) {
                    values.put(me.getKey(), v);
                    valueType = v.getType();
                }
            }
            
            for (int i = 0; i < numDim; i++) {
                int k = i;
                dim[i] = values.keySet().stream().mapToInt(a -> a.get(k)).max().getAsInt() + 1;
            }

            ArrayValue av = new ArrayValue(dim, valueType);
            for (var me : values.entrySet()) {
                av.setElementValue(me.getKey().array(), me.getValue());
            }
            return av;
        }

        @Override
        public void clear() {
            this.dim = null;
            for (ValueBuilder vb : elements.values()) {
                vb.clear();
            }
        }
    }

    class AggregateValueBuilder implements ValueBuilder {
        Map members = new LinkedHashMap<>();
        AggregateMemberNames names;

        public void addMember(String name, ValueBuilder b) {
            if (members.containsKey(name)) {
                throw new ParameterArchiveException("Duplicate member '" + name + "'");
            }
            members.put(name, b);
        }

        public ValueBuilder getMember(String name) {
            return members.get(name);
        }

        @Override
        public AggregateValue build() {
            if (names == null) {
                names = AggregateMemberNames.get(members.keySet().toArray(new String[0]));
            }
            AggregateValue av = new AggregateValue(names);
            for (Map.Entry me : members.entrySet()) {
                Value v = me.getValue().build();
                if (v == null) {
                    throw new ParameterArchiveException("No value for member '" + me.getKey() + "'");
                }
                av.setMemberValue(me.getKey(), me.getValue().build());
            }
            return av;
        }

        @Override
        public void clear() {
            for (ValueBuilder vb : members.values()) {
                vb.clear();
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy