Merge branch 'master' into easysetup
[platform/upstream/iotivity.git] / resource / src / OCRepresentation.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 /**
22  * @file
23  *
24  * This file contains the implementation of classes and its members related
25  * to OCRepresentation.
26  */
27
28
29 #include <OCRepresentation.h>
30
31 #include <boost/lexical_cast.hpp>
32 #include <algorithm>
33 #include "ocpayload.h"
34 #include "ocrandom.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37
38 namespace OC
39 {
40     static const char COAP[] = "coap://";
41     static const char COAPS[] = "coaps://";
42     static const char COAP_TCP[] = "coap+tcp://";
43
44     void MessageContainer::setPayload(const OCPayload* rep)
45     {
46         if (rep == nullptr)
47         {
48             return;
49         }
50
51         switch(rep->type)
52         {
53             case PAYLOAD_TYPE_REPRESENTATION:
54                 setPayload(reinterpret_cast<const OCRepPayload*>(rep));
55                 break;
56             case PAYLOAD_TYPE_DEVICE:
57                 setPayload(reinterpret_cast<const OCDevicePayload*>(rep));
58                 break;
59             case PAYLOAD_TYPE_PLATFORM:
60                 setPayload(reinterpret_cast<const OCPlatformPayload*>(rep));
61                 break;
62             default:
63                 throw OC::OCException("Invalid Payload type in setPayload");
64                 break;
65         }
66     }
67
68     void MessageContainer::setPayload(const OCDevicePayload* payload)
69     {
70         if (payload == nullptr)
71         {
72             return;
73         }
74
75         OCRepresentation rep;
76         char uuidString[UUID_STRING_SIZE];
77         if (payload->sid && RAND_UUID_OK == OCConvertUuidToString(payload->sid, uuidString))
78         {
79             rep[OC_RSRVD_DEVICE_ID] = std::string(uuidString);
80         }
81         else
82         {
83             rep[OC_RSRVD_DEVICE_ID] = std::string();
84         }
85         rep[OC_RSRVD_DEVICE_NAME] = payload->deviceName ?
86             std::string(payload->deviceName) :
87             std::string();
88         rep[OC_RSRVD_SPEC_VERSION] = payload->specVersion ?
89             std::string(payload->specVersion) :
90             std::string();
91         rep[OC_RSRVD_DATA_MODEL_VERSION] = payload->dataModelVersion ?
92             std::string(payload->dataModelVersion) :
93             std::string();
94         m_reps.push_back(std::move(rep));
95     }
96
97     void MessageContainer::setPayload(const OCPlatformPayload* payload)
98     {
99         if (payload == nullptr)
100         {
101             return;
102         }
103
104         OCRepresentation rep;
105         rep[OC_RSRVD_PLATFORM_ID] = payload->info.platformID ?
106             std::string(payload->info.platformID) :
107             std::string();
108         rep[OC_RSRVD_MFG_NAME] = payload->info.manufacturerName ?
109             std::string(payload->info.manufacturerName) :
110             std::string();
111         rep[OC_RSRVD_MFG_URL] = payload->info.manufacturerUrl ?
112             std::string(payload->info.manufacturerUrl) :
113             std::string();
114         rep[OC_RSRVD_MODEL_NUM] = payload->info.modelNumber ?
115             std::string(payload->info.modelNumber) :
116             std::string();
117         rep[OC_RSRVD_MFG_DATE] = payload->info.dateOfManufacture ?
118             std::string(payload->info.dateOfManufacture) :
119             std::string();
120         rep[OC_RSRVD_PLATFORM_VERSION] = payload->info.platformVersion ?
121             std::string(payload->info.platformVersion) :
122             std::string();
123         rep[OC_RSRVD_OS_VERSION] = payload->info.operatingSystemVersion ?
124             std::string(payload->info.operatingSystemVersion) :
125             std::string();
126         rep[OC_RSRVD_HARDWARE_VERSION] = payload->info.hardwareVersion ?
127             std::string(payload->info.hardwareVersion) :
128             std::string();
129         rep[OC_RSRVD_FIRMWARE_VERSION] = payload->info.firmwareVersion ?
130             std::string(payload->info.firmwareVersion) :
131             std::string();
132         rep[OC_RSRVD_SUPPORT_URL] = payload->info.supportUrl ?
133             std::string(payload->info.supportUrl) :
134             std::string();
135         rep[OC_RSRVD_SYSTEM_TIME] = payload->info.systemTime ?
136             std::string(payload->info.systemTime) :
137             std::string();
138
139         m_reps.push_back(std::move(rep));
140     }
141
142     void MessageContainer::setPayload(const OCRepPayload* payload)
143     {
144         const OCRepPayload* pl = payload;
145         while(pl)
146         {
147             OCRepresentation cur;
148             cur.setPayload(pl);
149
150             pl = pl->next;
151             this->addRepresentation(cur);
152         }
153     }
154
155     OCRepPayload* MessageContainer::getPayload() const
156     {
157         OCRepPayload* root = nullptr;
158         for(const auto& r : representations())
159         {
160             if (!root)
161             {
162                 root = r.getPayload();
163             }
164             else
165             {
166                 OCRepPayloadAppend(root, r.getPayload());
167             }
168         }
169
170         return root;
171     }
172
173     const std::vector<OCRepresentation>& MessageContainer::representations() const
174     {
175         return m_reps;
176     }
177
178     void MessageContainer::addRepresentation(const OCRepresentation& rep)
179     {
180         m_reps.push_back(rep);
181     }
182 }
183
184 namespace OC
185 {
186     struct get_payload_array: boost::static_visitor<>
187     {
188         template<typename T>
189         void operator()(T& /*arr*/)
190         {
191             throw std::logic_error("Invalid calc_dimensions_visitor type");
192         }
193
194         template<typename T>
195         void operator()(std::vector<T>& arr)
196         {
197             root_size_calc<T>();
198             dimensions[0] = arr.size();
199             dimensions[1] = 0;
200             dimensions[2] = 0;
201             dimTotal = calcDimTotal(dimensions);
202
203             array = (void*)OICMalloc(dimTotal * root_size);
204
205             for(size_t i = 0; i < dimensions[0]; ++i)
206             {
207                 copy_to_array(arr[i], array, i);
208             }
209
210         }
211         template<typename T>
212         void operator()(std::vector<std::vector<T>>& arr)
213         {
214             root_size_calc<T>();
215             dimensions[0] = arr.size();
216             dimensions[1] = 0;
217             dimensions[2] = 0;
218             for(size_t i = 0; i < arr.size(); ++i)
219             {
220                 dimensions[1] = std::max(dimensions[1], arr[i].size());
221             }
222             dimTotal = calcDimTotal(dimensions);
223             array = (void*)OICCalloc(1, dimTotal * root_size);
224
225             for(size_t i = 0; i < dimensions[0]; ++i)
226             {
227                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
228                 {
229                     copy_to_array(arr[i][j], array, i*dimensions[1] + j);
230                 }
231             }
232         }
233         template<typename T>
234         void operator()(std::vector<std::vector<std::vector<T>>>& arr)
235         {
236             root_size_calc<T>();
237             dimensions[0] = arr.size();
238             dimensions[1] = 0;
239             dimensions[2] = 0;
240             for(size_t i = 0; i < arr.size(); ++i)
241             {
242                 dimensions[1] = std::max(dimensions[1], arr[i].size());
243
244                 for(size_t j = 0; j < arr[i].size(); ++j)
245                 {
246                     dimensions[2] = std::max(dimensions[2], arr[i][j].size());
247                 }
248             }
249
250             dimTotal = calcDimTotal(dimensions);
251             array = (void*)OICCalloc(1, dimTotal * root_size);
252
253             for(size_t i = 0; i < dimensions[0]; ++i)
254             {
255                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
256                 {
257                     for(size_t k = 0; k < dimensions[2] && k < arr[i][j].size(); ++k)
258                     {
259                         copy_to_array(arr[i][j][k], array,
260                                 dimensions[2] * j +
261                                 dimensions[2] * dimensions[1] * i +
262                                 k);
263                     }
264                 }
265             }
266         }
267
268         template<typename T>
269         void root_size_calc()
270         {
271             root_size = sizeof(T);
272         }
273
274         template<typename T>
275         void copy_to_array(T item, void* array, size_t pos)
276         {
277             ((T*)array)[pos] = item;
278         }
279
280         size_t dimensions[MAX_REP_ARRAY_DEPTH];
281         size_t root_size;
282         size_t dimTotal;
283         void* array;
284     };
285
286     template<>
287     void get_payload_array::root_size_calc<int>()
288     {
289         root_size = sizeof(int64_t);
290     }
291
292     template<>
293     void get_payload_array::root_size_calc<std::string>()
294     {
295         root_size = sizeof(char*);
296     }
297
298     template<>
299     void get_payload_array::root_size_calc<OC::OCRepresentation>()
300     {
301         root_size = sizeof(OCRepPayload*);
302     }
303
304     template<>
305     void get_payload_array::copy_to_array(int item, void* array, size_t pos)
306     {
307         ((int64_t*)array)[pos] = item;
308     }
309
310     template<>
311     void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
312     {
313         ((bool*)array)[pos] = static_cast<bool>(br);
314     }
315
316     template<>
317     void get_payload_array::copy_to_array(std::string item, void* array, size_t pos)
318     {
319         ((char**)array)[pos] = OICStrdup(item.c_str());
320     }
321
322     template<>
323     void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos)
324     {
325         ((char**)array)[pos] = OICStrdup(item.c_str());
326     }
327
328     template<>
329     void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
330     {
331         ((char**)array)[pos] = OICStrdup(item.c_str());
332     }
333
334     template<>
335     void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
336     {
337         ((OCRepPayload**)array)[pos] = item.getPayload();
338     }
339
340     void OCRepresentation::getPayloadArray(OCRepPayload* payload,
341                     const OCRepresentation::AttributeItem& item) const
342     {
343         get_payload_array vis{};
344         boost::apply_visitor(vis, m_values[item.attrname()]);
345
346
347         switch(item.base_type())
348         {
349             case AttributeType::Integer:
350                 OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(),
351                         (int64_t*)vis.array,
352                         vis.dimensions);
353                 break;
354             case AttributeType::Double:
355                 OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(),
356                         (double*)vis.array,
357                         vis.dimensions);
358                 break;
359             case AttributeType::Boolean:
360                 OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(),
361                         (bool*)vis.array,
362                         vis.dimensions);
363                 break;
364             case AttributeType::String:
365                 OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(),
366                         (char**)vis.array,
367                         vis.dimensions);
368                 break;
369             case AttributeType::OCRepresentation:
370                 OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(),
371                         (OCRepPayload**)vis.array, vis.dimensions);
372                 break;
373             default:
374                 throw std::logic_error(std::string("GetPayloadArray: Not Implemented") +
375                         std::to_string((int)item.base_type()));
376         }
377     }
378
379     OCRepPayload* OCRepresentation::getPayload() const
380     {
381         OCRepPayload* root = OCRepPayloadCreate();
382         if (!root)
383         {
384             throw std::bad_alloc();
385         }
386
387         OCRepPayloadSetUri(root, getUri().c_str());
388
389         for(const std::string& type : getResourceTypes())
390         {
391             OCRepPayloadAddResourceType(root, type.c_str());
392         }
393
394         for(const std::string& iface : getResourceInterfaces())
395         {
396             OCRepPayloadAddInterface(root, iface.c_str());
397         }
398
399         for(auto& val : *this)
400         {
401             switch(val.type())
402             {
403                 case AttributeType::Null:
404                     OCRepPayloadSetNull(root, val.attrname().c_str());
405                     break;
406                 case AttributeType::Integer:
407                     OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast<int>(val));
408                     break;
409                 case AttributeType::Double:
410                     OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
411                             val.getValue<double>());
412                     break;
413                 case AttributeType::Boolean:
414                     OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
415                     break;
416                 case AttributeType::String:
417                     OCRepPayloadSetPropString(root, val.attrname().c_str(),
418                             static_cast<std::string>(val).c_str());
419                     break;
420                 case AttributeType::OCRepresentation:
421                     OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
422                             static_cast<OCRepresentation>(val).getPayload());
423                     break;
424                 case AttributeType::Vector:
425                     getPayloadArray(root, val);
426                     break;
427                 default:
428                     throw std::logic_error(std::string("Getpayload: Not Implemented") +
429                             std::to_string((int)val.type()));
430                     break;
431             }
432         }
433
434         return root;
435     }
436
437     size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
438     {
439         if (dimensions[0] == 0)
440         {
441             throw std::logic_error("invalid calcArrayDepth");
442         }
443         else if (dimensions[1] == 0)
444         {
445             return 1;
446         }
447         else if (dimensions[2] == 0)
448         {
449             return 2;
450         }
451         else
452         {
453             return 3;
454         }
455     }
456
457     template<typename T>
458     T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl)
459     {
460         throw std::logic_error("payload_array_helper_copy: unsupported type");
461     }
462     template<>
463     int OCRepresentation::payload_array_helper_copy<int>(size_t index, const OCRepPayloadValue* pl)
464     {
465         return pl->arr.iArray[index];
466     }
467     template<>
468     double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
469     {
470         return pl->arr.dArray[index];
471     }
472     template<>
473     bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
474     {
475         return pl->arr.bArray[index];
476     }
477     template<>
478     std::string OCRepresentation::payload_array_helper_copy<std::string>(
479             size_t index, const OCRepPayloadValue* pl)
480     {
481         if (pl->arr.strArray[index])
482         {
483             return std::string(pl->arr.strArray[index]);
484         }
485         else
486         {
487             return std::string{};
488         }
489     }
490     template<>
491     OCRepresentation OCRepresentation::payload_array_helper_copy<OCRepresentation>(
492             size_t index, const OCRepPayloadValue* pl)
493     {
494         OCRepresentation r;
495         if (pl->arr.objArray[index])
496         {
497             r.setPayload(pl->arr.objArray[index]);
498         }
499         return r;
500     }
501
502     template<typename T>
503     void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth)
504     {
505         if (depth == 1)
506         {
507             std::vector<T> val(pl->arr.dimensions[0]);
508
509             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
510             {
511                 val[i] = payload_array_helper_copy<T>(i, pl);
512             }
513             this->setValue(std::string(pl->name), val);
514         }
515         else if (depth == 2)
516         {
517             std::vector<std::vector<T>> val(pl->arr.dimensions[0]);
518             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
519             {
520                 val[i].resize(pl->arr.dimensions[1]);
521                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
522                 {
523                     val[i][j] = payload_array_helper_copy<T>(
524                             i * pl->arr.dimensions[1] + j, pl);
525                 }
526             }
527             this->setValue(std::string(pl->name), val);
528         }
529         else if (depth == 3)
530         {
531             std::vector<std::vector<std::vector<T>>> val(pl->arr.dimensions[0]);
532             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
533             {
534                 val[i].resize(pl->arr.dimensions[1]);
535                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
536                 {
537                     val[i][j].resize(pl->arr.dimensions[2]);
538                     for(size_t k = 0; k < pl->arr.dimensions[2]; ++k)
539                     {
540                         val[i][j][k] = payload_array_helper_copy<T>(
541                                 pl->arr.dimensions[2] * j +
542                                 pl->arr.dimensions[2] * pl->arr.dimensions[1] * i +
543                                 k,
544                                 pl);
545                     }
546                 }
547             }
548             this->setValue(std::string(pl->name), val);
549         }
550         else
551         {
552             throw std::logic_error("Invalid depth in payload_array_helper");
553         }
554     }
555
556     void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
557     {
558
559         switch(pl->arr.type)
560         {
561             case OCREP_PROP_INT:
562                 payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
563                 break;
564             case OCREP_PROP_DOUBLE:
565                 payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
566                 break;
567             case OCREP_PROP_BOOL:
568                 payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
569                 break;
570             case OCREP_PROP_STRING:
571                 payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
572                 break;
573             case OCREP_PROP_OBJECT:
574                 payload_array_helper<OCRepresentation>(pl, calcArrayDepth(pl->arr.dimensions));
575                 break;
576             default:
577                 throw std::logic_error("setPayload array invalid type");
578                 break;
579         }
580     }
581
582     void OCRepresentation::setPayload(const OCRepPayload* pl)
583     {
584         setUri(pl->uri);
585
586         OCStringLL* ll = pl->types;
587         while(ll)
588         {
589             addResourceType(ll->value);
590             ll = ll->next;
591         }
592
593         ll = pl->interfaces;
594         while(ll)
595         {
596             addResourceInterface(ll->value);
597             ll = ll->next;
598         }
599
600         OCRepPayloadValue* val = pl->values;
601
602         while(val)
603         {
604             switch(val->type)
605             {
606                 case OCREP_PROP_NULL:
607                     setNULL(val->name);
608                     break;
609                 case OCREP_PROP_INT:
610                     setValue<int>(val->name, val->i);
611                     break;
612                 case OCREP_PROP_DOUBLE:
613                     setValue<double>(val->name, val->d);
614                     break;
615                 case OCREP_PROP_BOOL:
616                     setValue<bool>(val->name, val->b);
617                     break;
618                 case OCREP_PROP_STRING:
619                     setValue<std::string>(val->name, val->str);
620                     break;
621                 case OCREP_PROP_OBJECT:
622                     {
623                         OCRepresentation cur;
624                         cur.setPayload(val->obj);
625                         setValue<OCRepresentation>(val->name, cur);
626                     }
627                     break;
628                 case OCREP_PROP_ARRAY:
629                     setPayloadArray(val);
630                     break;
631                 default:
632                     throw std::logic_error(std::string("Not Implemented!") +
633                             std::to_string((int)val->type));
634                     break;
635             }
636             val = val->next;
637         }
638     }
639
640     void OCRepresentation::addChild(const OCRepresentation& rep)
641     {
642         m_children.push_back(rep);
643     }
644
645     void OCRepresentation::clearChildren()
646     {
647         m_children.clear();
648     }
649
650     const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
651     {
652         return m_children;
653     }
654
655     void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
656     {
657         m_children = children;
658     }
659
660     void OCRepresentation::setDevAddr(const OCDevAddr m_devAddr)
661     {
662         std::ostringstream ss;
663         if (m_devAddr.flags & OC_SECURE)
664         {
665             ss << COAPS;
666         }
667         else if (m_devAddr.adapter & OC_ADAPTER_TCP)
668         {
669             ss << COAP_TCP;
670         }
671         else
672         {
673             ss << COAP;
674         }
675         if (m_devAddr.flags & OC_IP_USE_V6)
676         {
677             ss << '[' << m_devAddr.addr << ']';
678         }
679         else
680         {
681             ss << m_devAddr.addr;
682         }
683         if (m_devAddr.port)
684         {
685             ss << ':' << m_devAddr.port;
686         }
687         m_host = ss.str();
688     }
689
690     const std::string OCRepresentation::getHost() const
691     {
692         return m_host;
693     }
694
695     void OCRepresentation::setUri(const char* uri)
696     {
697         m_uri = uri ? uri : "";
698     }
699
700     void OCRepresentation::setUri(const std::string& uri)
701     {
702         m_uri = uri;
703     }
704
705     std::string OCRepresentation::getUri() const
706     {
707         return m_uri;
708     }
709
710     const std::vector<std::string>& OCRepresentation::getResourceTypes() const
711     {
712         return m_resourceTypes;
713     }
714
715     void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
716     {
717         m_resourceTypes = resourceTypes;
718     }
719
720     void OCRepresentation::addResourceType(const std::string& str)
721     {
722         m_resourceTypes.push_back(str);
723     }
724
725     const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
726     {
727         return m_interfaces;
728     }
729
730     void OCRepresentation::addResourceInterface(const std::string& str)
731     {
732         m_interfaces.push_back(str);
733     }
734
735     void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
736     {
737         m_interfaces = resourceInterfaces;
738     }
739
740     bool OCRepresentation::hasAttribute(const std::string& str) const
741     {
742         return m_values.find(str) != m_values.end();
743     }
744
745     bool OCRepresentation::emptyData() const
746     {
747         // This logic is meant to determine whether based on the JSON serialization rules
748         // if this object will result in empty JSON.  URI is only serialized if there is valid
749         // data, ResourceType and Interfaces are only serialized if we are a nothing, a
750         // child of a default or link item.
751         // Our values array is only printed in the if we are the child of a Batch resource,
752         // the parent in a 'default' situation, or not in a child/parent relationship.
753         if (!m_uri.empty())
754         {
755             return false;
756         }
757         else if ((m_interfaceType == InterfaceType::None
758                         || m_interfaceType==InterfaceType::DefaultChild
759                         || m_interfaceType==InterfaceType::LinkChild)
760                     && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
761         {
762             return false;
763         }
764         else if ((m_interfaceType == InterfaceType::None
765                         || m_interfaceType == InterfaceType::BatchChild
766                         || m_interfaceType == InterfaceType::DefaultParent)
767                     && m_values.size()>0)
768         {
769             return false;
770         }
771
772         if (m_children.size() > 0)
773         {
774             return false;
775         }
776
777         return true;
778     }
779
780     int OCRepresentation::numberOfAttributes() const
781     {
782         return m_values.size();
783     }
784
785     bool OCRepresentation::erase(const std::string& str)
786     {
787         return m_values.erase(str);
788     }
789
790     void OCRepresentation::setNULL(const std::string& str)
791     {
792         m_values[str] = OC::NullType();
793     }
794
795     bool OCRepresentation::isNULL(const std::string& str) const
796     {
797         auto x = m_values.find(str);
798
799         if (m_values.end() != x)
800         {
801             return x->second.which() == AttributeValueNullIndex;
802         }
803         else
804         {
805             throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
806         }
807     }
808 }
809
810 namespace OC
811 {
812     std::ostream& operator <<(std::ostream& os, const AttributeType at)
813     {
814         switch(at)
815         {
816             case AttributeType::Null:
817                 os << "Null";
818                 break;
819             case AttributeType::Integer:
820                 os << "Integer";
821                 break;
822             case AttributeType::Double:
823                 os << "Double";
824                 break;
825             case AttributeType::Boolean:
826                 os << "Boolean";
827                 break;
828             case AttributeType::String:
829                 os << "String";
830                 break;
831             case AttributeType::OCRepresentation:
832                 os << "OCRepresentation";
833                 break;
834             case AttributeType::Vector:
835                 os << "Vector";
836                 break;
837         }
838         return os;
839     }
840 }
841
842 // STL Container For OCRepresentation
843 namespace OC
844 {
845     OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
846             std::map<std::string, AttributeValue>& vals):
847             m_attrName(name), m_values(vals){}
848
849     OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
850     {
851         OCRepresentation::AttributeItem attr{key, m_values};
852         return std::move(attr);
853     }
854
855     const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
856     {
857         OCRepresentation::AttributeItem attr{key, m_values};
858         return std::move(attr);
859     }
860
861     const std::string& OCRepresentation::AttributeItem::attrname() const
862     {
863         return m_attrName;
864     }
865
866     template<typename T, typename = void>
867     struct type_info
868     {
869         // contains the actual type
870         typedef T type;
871         // contains the inner most vector-type
872         typedef T base_type;
873         // contains the AttributeType for this item
874         constexpr static AttributeType enum_type =
875             AttributeTypeConvert<T>::type;
876         // contains the AttributeType for this base-type
877         constexpr static AttributeType enum_base_type =
878             AttributeTypeConvert<T>::type;
879         // depth of the vector
880         constexpr static size_t depth = 0;
881     };
882
883     template<typename T>
884     struct type_info<T, typename std::enable_if<is_vector<T>::value>::type>
885     {
886         typedef T type;
887         typedef typename type_info<typename T::value_type>::base_type base_type;
888         constexpr static AttributeType enum_type = AttributeType::Vector;
889         constexpr static AttributeType enum_base_type =
890             type_info<typename T::value_type>::enum_base_type;
891         constexpr static size_t depth = 1 +
892             type_info<typename T::value_type>::depth;
893     };
894
895     struct type_introspection_visitor : boost::static_visitor<>
896     {
897         AttributeType type;
898         AttributeType base_type;
899         size_t depth;
900
901         type_introspection_visitor() : boost::static_visitor<>(),
902             type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
903
904         template <typename T>
905         void operator()(T const& /*item*/)
906         {
907             type = type_info<T>::enum_type;
908             base_type = type_info<T>::enum_base_type;
909             depth = type_info<T>::depth;
910         }
911     };
912
913     AttributeType OCRepresentation::AttributeItem::type() const
914     {
915         type_introspection_visitor vis;
916         boost::apply_visitor(vis, m_values[m_attrName]);
917         return vis.type;
918     }
919
920     AttributeType OCRepresentation::AttributeItem::base_type() const
921     {
922         type_introspection_visitor vis;
923         boost::apply_visitor(vis, m_values[m_attrName]);
924         return vis.base_type;
925     }
926
927     size_t OCRepresentation::AttributeItem::depth() const
928     {
929         type_introspection_visitor vis;
930         boost::apply_visitor(vis, m_values[m_attrName]);
931         return vis.depth;
932     }
933
934     OCRepresentation::iterator OCRepresentation::begin()
935     {
936         return OCRepresentation::iterator(m_values.begin(), m_values);
937     }
938
939     OCRepresentation::const_iterator OCRepresentation::begin() const
940     {
941          return OCRepresentation::const_iterator(m_values.begin(), m_values);
942     }
943
944     OCRepresentation::const_iterator OCRepresentation::cbegin() const
945     {
946         return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
947     }
948
949     OCRepresentation::iterator OCRepresentation::end()
950     {
951         return OCRepresentation::iterator(m_values.end(), m_values);
952     }
953
954     OCRepresentation::const_iterator OCRepresentation::end() const
955     {
956         return OCRepresentation::const_iterator(m_values.end(), m_values);
957     }
958
959     OCRepresentation::const_iterator OCRepresentation::cend() const
960     {
961         return OCRepresentation::const_iterator(m_values.cend(), m_values);
962     }
963
964     size_t OCRepresentation::size() const
965     {
966         return m_values.size();
967     }
968
969     bool OCRepresentation::empty() const
970     {
971         return m_values.empty();
972     }
973
974     bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
975     {
976         return m_iterator == rhs.m_iterator;
977     }
978
979     bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
980     {
981         return m_iterator != rhs.m_iterator;
982     }
983
984     bool OCRepresentation::const_iterator::operator==(
985             const OCRepresentation::const_iterator& rhs) const
986     {
987         return m_iterator == rhs.m_iterator;
988     }
989
990     bool OCRepresentation::const_iterator::operator!=(
991             const OCRepresentation::const_iterator& rhs) const
992     {
993         return m_iterator != rhs.m_iterator;
994     }
995
996     OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
997     {
998         return m_item;
999     }
1000
1001     OCRepresentation::const_iterator::const_reference
1002         OCRepresentation::const_iterator::operator*() const
1003     {
1004         return m_item;
1005     }
1006
1007     OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
1008     {
1009         return &m_item;
1010     }
1011
1012     OCRepresentation::const_iterator::const_pointer
1013         OCRepresentation::const_iterator::operator->() const
1014     {
1015         return &m_item;
1016     }
1017
1018     OCRepresentation::iterator& OCRepresentation::iterator::operator++()
1019     {
1020         m_iterator++;
1021         if (m_iterator != m_item.m_values.end())
1022         {
1023             m_item.m_attrName = m_iterator->first;
1024         }
1025         else
1026         {
1027             m_item.m_attrName = "";
1028         }
1029         return *this;
1030     }
1031
1032     OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
1033     {
1034         m_iterator++;
1035         if (m_iterator != m_item.m_values.end())
1036         {
1037             m_item.m_attrName = m_iterator->first;
1038         }
1039         else
1040         {
1041             m_item.m_attrName = "";
1042         }
1043         return *this;
1044     }
1045
1046     OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
1047     {
1048         OCRepresentation::iterator itr(*this);
1049         ++(*this);
1050         return itr;
1051     }
1052
1053     OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
1054     {
1055         OCRepresentation::const_iterator itr(*this);
1056         ++(*this);
1057         return itr;
1058     }
1059
1060     struct to_string_visitor : boost::static_visitor<>
1061     {
1062         std::string str;
1063         template <typename T>
1064         void operator()(T const& item)
1065         {
1066             str = boost::lexical_cast<std::string>(item);
1067         }
1068
1069         template <typename T>
1070         void operator()(std::vector<T> const& item)
1071         {
1072             to_string_visitor vis;
1073             std::ostringstream stream;
1074             stream << "[";
1075
1076             for(const auto& i : item)
1077             {
1078                 vis(i);
1079                 stream << vis.str  << " ";
1080             }
1081             stream << "]";
1082             str = stream.str();
1083         }
1084     };
1085
1086     template<>
1087     void to_string_visitor::operator()(bool const& item)
1088     {
1089         str = item ? "true" : "false";
1090     }
1091
1092     template<>
1093     void to_string_visitor::operator()(std::string const& item)
1094     {
1095         str = item;
1096     }
1097
1098     template<>
1099     void to_string_visitor::operator()(NullType const& /*item*/)
1100     {
1101         str = "(null)";
1102     }
1103
1104     template<>
1105     void to_string_visitor::operator()(OCRepresentation const& /*item*/)
1106     {
1107         str = "OC::OCRepresentation";
1108     }
1109
1110     std::string OCRepresentation::getValueToString(const std::string& key) const
1111     {
1112         auto x = m_values.find(key);
1113         if (x != m_values.end())
1114         {
1115             to_string_visitor vis;
1116             boost::apply_visitor(vis, x->second);
1117             return std::move(vis.str);
1118         }
1119
1120         return "";
1121     }
1122
1123     std::string OCRepresentation::AttributeItem::getValueToString() const
1124     {
1125         to_string_visitor vis;
1126         boost::apply_visitor(vis, m_values[m_attrName]);
1127         return std::move(vis.str);
1128     }
1129
1130     std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
1131     {
1132         os << ai.getValueToString();
1133         return os;
1134     }
1135 }