1 /*
2  * hunt-proton: AMQP Protocol library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.proton.codec.impl.MapElement;
13 
14 import hunt.proton.codec.impl.AbstractElement;
15 import hunt.proton.codec.impl.Element;
16 import hunt.proton.codec.impl.ArrayElement;
17 import hunt.proton.codec.Data;
18 import hunt.collection.Map;
19 import hunt.io.ByteBuffer;
20 import std.conv;
21 import hunt.collection.HashMap;
22 
23 class MapElement : AbstractElement!(Map!(Object,Object))
24 {
25     private IElement _first;
26 
27     this(IElement parent, IElement prev)
28     {
29         super(parent, prev);
30     }
31 
32 
33     public int count()
34     {
35         int count = 0;
36         IElement elt = _first;
37         while(elt !is null)
38         {
39             count++;
40             elt = elt.next();
41         }
42         return count;
43     }
44 
45     public int size()
46     {
47         int count = 0;
48         int size = 0;
49         IElement elt = _first;
50         while(elt !is null)
51         {
52             count++;
53             size += elt.size();
54             elt = elt.next();
55         }
56         if(isElementOfArray())
57         {
58             ArrayElement parent = cast(ArrayElement) parent();
59 
60             if(parent.constructorType() == ArrayElement.SMALL)
61             {
62                 if(count > 255 || size > 254)
63                 {
64                     parent.setConstructorType(ArrayElement.ConstructorType.LARGE);
65                     size += 8;
66                 }
67                 else
68                 {
69                     size += 2;
70                 }
71             }
72             else
73             {
74                 size += 8;
75             }
76         }
77         else
78         {
79             if(count <= 255 && size <= 254)
80             {
81                 size += 3;
82             }
83             else
84             {
85                 size+=9;
86             }
87         }
88 
89         return size;
90     }
91 
92     public Object getValue()
93     {
94         Map!(Object,Object) map = new HashMap!(Object,Object);
95         IElement elt = _first;
96         while(elt !is null)
97         {
98             Object key = cast(Object)elt.getValue();
99             Object value;
100             elt = elt.next();
101             if(elt !is null)
102             {
103                 value = elt.getValue();
104                 elt =  elt.next();
105             }
106             else
107             {
108                 value = null;
109             }
110             map.put(key,value);
111         }
112 
113         return cast(Object)map;
114     }
115 
116     public Data.DataType getDataType()
117     {
118         return Data.DataType.MAP;
119     }
120 
121     public int encode(ByteBuffer b)
122     {
123         int encodedSize = size();
124 
125         int count = 0;
126         int size = 0;
127         IElement elt = _first;
128         while(elt !is null)
129         {
130             count++;
131             size += elt.size();
132             elt =  elt.next();
133         }
134 
135         if(encodedSize > b.remaining())
136         {
137             return 0;
138         }
139         else
140         {
141             if(isElementOfArray())
142             {
143                 switch((cast(ArrayElement)parent()).constructorType())
144                 {
145                     case ArrayElement.ConstructorType.SMALL:
146                         b.put(cast(byte)(size+1));
147                         b.put(cast(byte)count);
148                         break;
149                     case ArrayElement.ConstructorType.LARGE:
150                         b.putInt((size+4));
151                         b.putInt(count);
152                         break;
153                     default:
154                         break;
155                 }
156             }
157             else
158             {
159                 if(size <= 254 && count <=255)
160                 {
161                     b.put(cast(byte)0xc1);
162                     b.put(cast(byte)(size+1));
163                     b.put(cast(byte)count);
164                 }
165                 else
166                 {
167                     b.put(cast(byte)0xd1);
168                     b.putInt((size+4));
169                     b.putInt(count);
170                 }
171 
172             }
173 
174             elt = _first;
175             while(elt !is null)
176             {
177                 elt.encode(b);
178                 elt =  elt.next();
179             }
180 
181             return encodedSize;
182         }
183     }
184 
185     public bool canEnter()
186     {
187         return true;
188     }
189 
190     public IElement child()
191     {
192         return _first;
193     }
194 
195     public void setChild(IElement elt)
196     {
197         _first = elt;
198     }
199 
200     public IElement checkChild(IElement element)
201     {
202         return element;
203     }
204 
205     public IElement addChild(IElement element)
206     {
207         _first = element;
208         return element;
209     }
210 
211     override
212     string startSymbol() {
213         return "{";
214     }
215 
216     override
217     string stopSymbol() {
218         return "}";
219     }
220 
221 }