1package com.android.server.wifi.hotspot2.omadm;
2
3import java.io.IOException;
4import java.io.OutputStream;
5import java.nio.charset.StandardCharsets;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.Iterator;
9import java.util.Map;
10
11public class OMAConstructed extends OMANode {
12    private final MultiValueMap<OMANode> mChildren;
13
14    public OMAConstructed(OMAConstructed parent, String name, String context, String ... avps) {
15        this(parent, name, context, new MultiValueMap<OMANode>(), buildAttributes(avps));
16    }
17
18    protected OMAConstructed(OMAConstructed parent, String name, String context,
19                           MultiValueMap<OMANode> children, Map<String, String> avps) {
20        super(parent, name, context, avps);
21        mChildren = children;
22    }
23
24    @Override
25    public OMANode addChild(String name, String context, String value, String pathString)
26            throws IOException {
27        if (pathString == null) {
28            OMANode child = value != null ?
29                    new OMAScalar(this, name, context, value) :
30                    new OMAConstructed(this, name, context);
31            mChildren.put(name, child);
32            return child;
33        } else {
34            OMANode target = this;
35            while (target.getParent() != null)
36                target = target.getParent();
37
38            for (String element : pathString.split("/")) {
39                target = target.getChild(element);
40                if (target == null)
41                    throw new IOException("No child node '" + element + "' in " + getPathString());
42                else if (target.isLeaf())
43                    throw new IOException("Cannot add child to leaf node: " + getPathString());
44            }
45            return target.addChild(name, context, value, null);
46        }
47    }
48
49    @Override
50    public OMAConstructed reparent(OMAConstructed parent) {
51        return new OMAConstructed(parent, getName(), getContext(), mChildren, getAttributes());
52    }
53
54    public void addChild(OMANode child) {
55        mChildren.put(child.getName(), child.reparent(this));
56    }
57
58    public String getScalarValue(Iterator<String> path) throws OMAException {
59        if (!path.hasNext()) {
60            throw new OMAException("Path too short for " + getPathString());
61        }
62        String tag = path.next();
63        OMANode child = mChildren.get(tag);
64        if (child != null) {
65            return child.getScalarValue(path);
66        } else {
67            return null;
68        }
69    }
70
71    @Override
72    public OMANode getListValue(Iterator<String> path) throws OMAException {
73        if (!path.hasNext()) {
74            return null;
75        }
76        String tag = path.next();
77        OMANode child;
78        if (tag.equals("?")) {
79            child = mChildren.getSingletonValue();
80        }
81        else {
82            child = mChildren.get(tag);
83        }
84
85        if (child == null) {
86            return null;
87        }
88        else if (path.hasNext()) {
89            return child.getListValue(path);
90        } else {
91            return child;
92        }
93    }
94
95    @Override
96    public boolean isLeaf() {
97        return false;
98    }
99
100    @Override
101    public Collection<OMANode> getChildren() {
102        return Collections.unmodifiableCollection(mChildren.values());
103    }
104
105    public OMANode getChild(String name) {
106        return mChildren.get(name);
107    }
108
109    public OMANode replaceNode(OMANode oldNode, OMANode newNode) {
110        return mChildren.replace(oldNode.getName(), oldNode, newNode);
111    }
112
113    public OMANode removeNode(String key, OMANode node) {
114        if (key.equals("?")) {
115            return mChildren.remove(node);
116        }
117        else {
118            return mChildren.remove(key, node);
119        }
120    }
121
122    @Override
123    public String getValue() {
124        throw new UnsupportedOperationException();
125    }
126
127    @Override
128    public void toString(StringBuilder sb, int level) {
129        sb.append(getPathString());
130        if (getContext() != null) {
131            sb.append(" (").append(getContext()).append(')');
132        }
133        sb.append('\n');
134
135        for (OMANode node : mChildren.values()) {
136            node.toString(sb, level + 1);
137        }
138    }
139
140    @Override
141    public void marshal(OutputStream out, int level) throws IOException {
142        OMAConstants.indent(level, out);
143        OMAConstants.serializeString(getName(), out);
144        if (getContext() != null) {
145            out.write(String.format("(%s)", getContext()).getBytes(StandardCharsets.UTF_8));
146        }
147        out.write(new byte[] { '+', '\n' });
148
149        for (OMANode child : mChildren.values()) {
150            child.marshal(out, level + 1);
151        }
152        OMAConstants.indent(level, out);
153        out.write(".\n".getBytes(StandardCharsets.UTF_8));
154    }
155
156    @Override
157    public void fillPayload(StringBuilder sb) {
158        if (getContext() != null) {
159            sb.append('<').append(MOTree.RTPropTag).append(">\n");
160            sb.append('<').append(MOTree.TypeTag).append(">\n");
161            sb.append('<').append(MOTree.DDFNameTag).append(">");
162            sb.append(getContext());
163            sb.append("</").append(MOTree.DDFNameTag).append(">\n");
164            sb.append("</").append(MOTree.TypeTag).append(">\n");
165            sb.append("</").append(MOTree.RTPropTag).append(">\n");
166        }
167
168        for (OMANode child : getChildren()) {
169            child.toXml(sb);
170        }
171    }
172}
173