@situm/react-native 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +656 -0
  3. package/ReactNativeSitumPlugin.podspec +22 -0
  4. package/SECURITY-POLICY.md +9 -0
  5. package/android/.gradle/5.6.4/fileChanges/last-build.bin +0 -0
  6. package/android/.gradle/5.6.4/fileHashes/fileHashes.lock +0 -0
  7. package/android/.gradle/5.6.4/gc.properties +0 -0
  8. package/android/.idea/.name +1 -0
  9. package/android/.idea/codeStyles/Project.xml +116 -0
  10. package/android/.idea/encodings.xml +6 -0
  11. package/android/.idea/misc.xml +31 -0
  12. package/android/.idea/sonarlint/issuestore/index.pb +15 -0
  13. package/android/.project +34 -0
  14. package/android/build.gradle +45 -0
  15. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  16. package/android/gradle/wrapper/gradle-wrapper.properties +6 -0
  17. package/android/gradlew +172 -0
  18. package/android/gradlew.bat +84 -0
  19. package/android/src/main/AndroidManifest.xml +6 -0
  20. package/android/src/main/java/com/situm/plugin/PluginHelper.java +989 -0
  21. package/android/src/main/java/com/situm/plugin/SitumMapper.java +1206 -0
  22. package/android/src/main/java/com/situm/plugin/SitumPackage.java +29 -0
  23. package/android/src/main/java/com/situm/plugin/SitumPlugin.java +84 -0
  24. package/android/src/main/java/com/situm/plugin/SitumPluginImpl.java +344 -0
  25. package/android/src/main/java/com/situm/plugin/utils/ReactNativeJson.java +122 -0
  26. package/android/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  27. package/android/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  28. package/android/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  29. package/android/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  30. package/android/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  31. package/android/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  32. package/android/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  33. package/android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  34. package/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  35. package/android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  36. package/android/src/main/res/values/strings.xml +3 -0
  37. package/android/src/main/res/values/styles.xml +9 -0
  38. package/ios/Constants.h +14 -0
  39. package/ios/Constants.m +14 -0
  40. package/ios/RNSitumReactNativePlugin.xcodeproj/project.pbxproj +272 -0
  41. package/ios/SitumLocationWrapper.h +112 -0
  42. package/ios/SitumLocationWrapper.m +1132 -0
  43. package/ios/SitumPlugin.h +15 -0
  44. package/ios/SitumPlugin.m +911 -0
  45. package/lib/commonjs/index.js +25 -0
  46. package/lib/commonjs/index.js.map +1 -0
  47. package/lib/commonjs/sdk/index.js +399 -0
  48. package/lib/commonjs/sdk/index.js.map +1 -0
  49. package/lib/commonjs/sdk/nativeInterface.js +20 -0
  50. package/lib/commonjs/sdk/nativeInterface.js.map +1 -0
  51. package/lib/commonjs/sdk/types/index.d.js +6 -0
  52. package/lib/commonjs/sdk/types/index.d.js.map +1 -0
  53. package/lib/commonjs/sdk/utils.js +22 -0
  54. package/lib/commonjs/sdk/utils.js.map +1 -0
  55. package/lib/commonjs/utils/requestPermission.js +73 -0
  56. package/lib/commonjs/utils/requestPermission.js.map +1 -0
  57. package/lib/commonjs/wayfinding/components/MapView.js +220 -0
  58. package/lib/commonjs/wayfinding/components/MapView.js.map +1 -0
  59. package/lib/commonjs/wayfinding/hooks/index.js +401 -0
  60. package/lib/commonjs/wayfinding/hooks/index.js.map +1 -0
  61. package/lib/commonjs/wayfinding/index.js +45 -0
  62. package/lib/commonjs/wayfinding/index.js.map +1 -0
  63. package/lib/commonjs/wayfinding/store/index.js +237 -0
  64. package/lib/commonjs/wayfinding/store/index.js.map +1 -0
  65. package/lib/commonjs/wayfinding/store/utils.js +44 -0
  66. package/lib/commonjs/wayfinding/store/utils.js.map +1 -0
  67. package/lib/commonjs/wayfinding/styles/colors.js +18 -0
  68. package/lib/commonjs/wayfinding/styles/colors.js.map +1 -0
  69. package/lib/commonjs/wayfinding/types/index.d.js +6 -0
  70. package/lib/commonjs/wayfinding/types/index.d.js.map +1 -0
  71. package/lib/commonjs/wayfinding/utils/index.js +11 -0
  72. package/lib/commonjs/wayfinding/utils/index.js.map +1 -0
  73. package/lib/commonjs/wayfinding/utils/mapper.js +106 -0
  74. package/lib/commonjs/wayfinding/utils/mapper.js.map +1 -0
  75. package/lib/module/index.js +6 -0
  76. package/lib/module/index.js.map +1 -0
  77. package/lib/module/sdk/index.js +390 -0
  78. package/lib/module/sdk/index.js.map +1 -0
  79. package/lib/module/sdk/nativeInterface.js +18 -0
  80. package/lib/module/sdk/nativeInterface.js.map +1 -0
  81. package/lib/module/sdk/types/index.d.js +2 -0
  82. package/lib/module/sdk/types/index.d.js.map +1 -0
  83. package/lib/module/sdk/utils.js +15 -0
  84. package/lib/module/sdk/utils.js.map +1 -0
  85. package/lib/module/utils/requestPermission.js +67 -0
  86. package/lib/module/utils/requestPermission.js.map +1 -0
  87. package/lib/module/wayfinding/components/MapView.js +207 -0
  88. package/lib/module/wayfinding/components/MapView.js.map +1 -0
  89. package/lib/module/wayfinding/hooks/index.js +392 -0
  90. package/lib/module/wayfinding/hooks/index.js.map +1 -0
  91. package/lib/module/wayfinding/index.js +12 -0
  92. package/lib/module/wayfinding/index.js.map +1 -0
  93. package/lib/module/wayfinding/store/index.js +202 -0
  94. package/lib/module/wayfinding/store/index.js.map +1 -0
  95. package/lib/module/wayfinding/store/utils.js +34 -0
  96. package/lib/module/wayfinding/store/utils.js.map +1 -0
  97. package/lib/module/wayfinding/styles/colors.js +11 -0
  98. package/lib/module/wayfinding/styles/colors.js.map +1 -0
  99. package/lib/module/wayfinding/types/index.d.js +2 -0
  100. package/lib/module/wayfinding/types/index.d.js.map +1 -0
  101. package/lib/module/wayfinding/utils/index.js +4 -0
  102. package/lib/module/wayfinding/utils/index.js.map +1 -0
  103. package/lib/module/wayfinding/utils/mapper.js +100 -0
  104. package/lib/module/wayfinding/utils/mapper.js.map +1 -0
  105. package/lib/typescript/src/index.d.ts +4 -0
  106. package/lib/typescript/src/index.d.ts.map +1 -0
  107. package/lib/typescript/src/sdk/index.d.ts +269 -0
  108. package/lib/typescript/src/sdk/index.d.ts.map +1 -0
  109. package/lib/typescript/src/sdk/nativeInterface.d.ts +2 -0
  110. package/lib/typescript/src/sdk/nativeInterface.d.ts.map +1 -0
  111. package/lib/typescript/src/sdk/utils.d.ts +7 -0
  112. package/lib/typescript/src/sdk/utils.d.ts.map +1 -0
  113. package/lib/typescript/src/utils/requestPermission.d.ts +3 -0
  114. package/lib/typescript/src/utils/requestPermission.d.ts.map +1 -0
  115. package/lib/typescript/src/wayfinding/components/MapView.d.ts +36 -0
  116. package/lib/typescript/src/wayfinding/components/MapView.d.ts.map +1 -0
  117. package/lib/typescript/src/wayfinding/hooks/index.d.ts +53 -0
  118. package/lib/typescript/src/wayfinding/hooks/index.d.ts.map +1 -0
  119. package/lib/typescript/src/wayfinding/index.d.ts +5 -0
  120. package/lib/typescript/src/wayfinding/index.d.ts.map +1 -0
  121. package/lib/typescript/src/wayfinding/store/index.d.ts +103 -0
  122. package/lib/typescript/src/wayfinding/store/index.d.ts.map +1 -0
  123. package/lib/typescript/src/wayfinding/store/utils.d.ts +9 -0
  124. package/lib/typescript/src/wayfinding/store/utils.d.ts.map +1 -0
  125. package/lib/typescript/src/wayfinding/styles/colors.d.ts +8 -0
  126. package/lib/typescript/src/wayfinding/styles/colors.d.ts.map +1 -0
  127. package/lib/typescript/src/wayfinding/utils/index.d.ts +3 -0
  128. package/lib/typescript/src/wayfinding/utils/index.d.ts.map +1 -0
  129. package/lib/typescript/src/wayfinding/utils/mapper.d.ts +17 -0
  130. package/lib/typescript/src/wayfinding/utils/mapper.d.ts.map +1 -0
  131. package/package.json +130 -0
  132. package/security.txt +4 -0
  133. package/src/index.ts +6 -0
  134. package/src/sdk/index.ts +656 -0
  135. package/src/sdk/nativeInterface.ts +18 -0
  136. package/src/sdk/types/index.d.ts +718 -0
  137. package/src/sdk/utils.ts +16 -0
  138. package/src/utils/requestPermission.ts +94 -0
  139. package/src/wayfinding/components/MapView.tsx +312 -0
  140. package/src/wayfinding/hooks/index.ts +539 -0
  141. package/src/wayfinding/index.tsx +11 -0
  142. package/src/wayfinding/store/index.tsx +254 -0
  143. package/src/wayfinding/store/utils.ts +40 -0
  144. package/src/wayfinding/styles/colors.tsx +6 -0
  145. package/src/wayfinding/types/index.d.ts +56 -0
  146. package/src/wayfinding/utils/index.ts +5 -0
  147. package/src/wayfinding/utils/mapper.ts +129 -0
@@ -0,0 +1,1132 @@
1
+ #import "SitumLocationWrapper.h"
2
+ #import "Constants.h"
3
+
4
+ NSString* emptyStrCheck(NSString *str) {
5
+ if (!str || str == nil) {
6
+ return @"";
7
+ }
8
+ return str;
9
+ }
10
+
11
+ NSString* orientationTypeToString(kSITIndicationOrientation orientation) {
12
+ NSString *type = @"";
13
+ switch (orientation) {
14
+ case kSITInvalidOrientation:
15
+ type = @"INVALID_ORIENTATION";
16
+ break;
17
+ case kSITStraight:
18
+ type = @"STRAIGHT";
19
+ break;
20
+ case kSITVeerRight:
21
+ type = @"VEER_RIGHT";
22
+ break;
23
+ case kSITRight:
24
+ type = @"RIGHT";
25
+ break;
26
+ case kSITSharpRight:
27
+ type = @"SHARP_RIGHT";
28
+ break;
29
+ case kSITVeerLeft:
30
+ type = @"VEER_LEFT";
31
+ break;
32
+ case kSITLeft:
33
+ type = @"LEFT";
34
+ break;
35
+ case kSITSharpLeft:
36
+ type = @"SHARP_LEFT";
37
+ break;
38
+ case kSITBackward:
39
+ type = @"BACKWARD";
40
+ break;
41
+
42
+ default:
43
+ break;
44
+ }
45
+ return type;
46
+ }
47
+
48
+ kSITIndicationOrientation stringToOrientationType(NSString *orientation) {
49
+ kSITIndicationOrientation type = kSITInvalidOrientation;
50
+ if ([orientation isEqualToString:@"INVALID_ORIENTATION"]) {
51
+ type = kSITInvalidOrientation;
52
+ } else if ([orientation isEqualToString:@"STRAIGHT"]) {
53
+ type = kSITStraight;
54
+ } else if ([orientation isEqualToString:@"VEER_RIGHT"]) {
55
+ type = kSITVeerRight;
56
+ } else if ([orientation isEqualToString:@"RIGHT"]) {
57
+ type = kSITRight;
58
+ } else if ([orientation isEqualToString:@"SHARP_RIGHT"]) {
59
+ type = kSITSharpRight;
60
+ } else if ([orientation isEqualToString:@"VEER_LEFT"]) {
61
+ type = kSITVeerLeft;
62
+ } else if ([orientation isEqualToString:@"LEFT"]) {
63
+ type = kSITLeft;
64
+ } else if ([orientation isEqualToString:@"SHARP_LEFT"]) {
65
+ type = kSITSharpLeft;
66
+ } else if ([orientation isEqualToString:@"BACKWARD"]) {
67
+ type = kSITBackward;
68
+ }
69
+ return type;
70
+ }
71
+
72
+ // indicationType
73
+
74
+ NSString* indicationTypeToString(kSITIndicationActions action) {
75
+ NSString *type = @"";
76
+ switch (action) {
77
+ case kSITInvalidAction:
78
+ type = @"INVALID_ACTION";
79
+ break;
80
+ case kSITTurn:
81
+ type = @"TURN";
82
+ break;
83
+ case kSITGoAhead:
84
+ type = @"GO_AHEAD";
85
+ break;
86
+ case kSITChangeFloor:
87
+ type = @"CHANGE_FLOOR";
88
+ break;
89
+ case kSITEnd:
90
+ type = @"END";
91
+ break;
92
+ case kSITCalculating:
93
+ type = @"CALCULATING";
94
+ break;
95
+ default:
96
+ break;
97
+ }
98
+ return type;
99
+ }
100
+
101
+ kSITIndicationActions stringToIndicationType(NSString* action) {
102
+ kSITIndicationActions type = kSITInvalidAction;
103
+ if ([action isEqualToString:@"INVALID_ACTION"]) {
104
+ type = kSITInvalidAction;
105
+ } else if ([action isEqualToString:@"TURN"]) {
106
+ type = kSITTurn;
107
+ } else if ([action isEqualToString:@"GO_AHEAD"]) {
108
+ type = kSITGoAhead;
109
+ } else if ([action isEqualToString:@"CHANGE_FLOOR"]) {
110
+ type = kSITChangeFloor;
111
+ } else if ([action isEqualToString:@"END"]) {
112
+ type = kSITEnd;
113
+ }
114
+ return type;
115
+ }
116
+
117
+ // locationState
118
+
119
+ SITLocationState stringToLocationState(NSString* state){
120
+ SITLocationState type = kSITLocationStopped;
121
+ if ([state isEqualToString:@"STOPPED"]) {
122
+ type = kSITLocationStopped;
123
+ } else if ([state isEqualToString:@"CALCULATING"]) {
124
+ type = kSITLocationCalculating;
125
+ } else if ([state isEqualToString:@"USER_NOT_IN_BUILDING"]) {
126
+ type = kSITLocationUserNotInBuilding;
127
+ } else if ([state isEqualToString:@"STARTING"]) {
128
+ type = kSITLocationStarted;
129
+ }
130
+ return type;
131
+ }
132
+
133
+ static SitumLocationWrapper *singletonSitumLocationWrapperObj;
134
+
135
+ @implementation SitumLocationWrapper
136
+
137
+ + (SitumLocationWrapper *)shared {
138
+ static dispatch_once_t onceToken;
139
+ dispatch_once(&onceToken, ^{
140
+ singletonSitumLocationWrapperObj = [[SitumLocationWrapper alloc] init];
141
+ });
142
+ return singletonSitumLocationWrapperObj;
143
+ }
144
+
145
+ //Building
146
+
147
+ - (NSDictionary *) buildingToJsonObject:(SITBuilding *) building {
148
+
149
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
150
+ [jo setObject:emptyStrCheck(building.address) forKey:@"address"];
151
+ [jo setObject:[self boundsToJsonObject:building.bounds] forKey:@"bounds"];
152
+ [jo setObject:[self boundsToJsonObject:building.rotatedBounds] forKey:@"boundsRotated"];
153
+ [jo setObject:[self dimensionsToJsonObject:building.dimensions] forKey:@"dimensions"];
154
+ [jo setObject:[self coordinateToJsonObject:building.center] forKey:@"center"];
155
+ [jo setObject:emptyStrCheck(building.name) forKey:@"name"];
156
+ [jo setObject:emptyStrCheck(building.infoHTML) forKey:@"infoHtml"];
157
+ [jo setObject:emptyStrCheck(building.pictureThumbURL.direction) forKey:@"pictureThumbUrl"];
158
+ [jo setObject:emptyStrCheck(building.pictureURL.direction) forKey:@"pictureUrl"];
159
+ // [jo setObject:building.rotation forKey:@"rotation"];
160
+ [jo setObject:[NSNumber numberWithFloat:[building.rotation degrees]] forKey:@"rotationDegrees"];
161
+ [jo setObject:[NSNumber numberWithFloat:[building.rotation radians]] forKey:@"rotationRadians"];
162
+ [jo setObject:[NSNumber numberWithFloat:[building.rotation radians]] forKey:@"rotation"];
163
+ [jo setObject:emptyStrCheck(building.userIdentifier) forKey:@"userIdentifier"];
164
+ [jo setObject:emptyStrCheck(building.identifier) forKey:@"identifier"];
165
+ [jo setObject:emptyStrCheck(building.identifier) forKey:@"buildingIdentifier"];
166
+
167
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
168
+ [dateFormatter setDateFormat:kDateFormat];
169
+
170
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:building.createdAt])
171
+ forKey:@"createdAt"];
172
+
173
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:building.updatedAt])
174
+ forKey:@"updatedAt"];
175
+
176
+ if (building.customFields) {
177
+ [jo setObject:building.customFields forKey:@"customFields"];
178
+ }
179
+
180
+ return jo.copy;
181
+ }
182
+
183
+ - (NSArray *)floorsToJsonArray:(NSArray *)floors
184
+ {
185
+ NSMutableArray *ja = [[NSMutableArray alloc] init];
186
+ for (SITFloor *obj in floors) {
187
+ NSDictionary *floorJson = [self floorToJsonObject:obj];
188
+
189
+ [ja addObject:floorJson];
190
+ }
191
+ return ja;
192
+ }
193
+
194
+ - (NSArray *)poisToJsonArray:(NSArray *)array
195
+ {
196
+ NSMutableArray *ja = [[NSMutableArray alloc] init];
197
+ for (SITPOI *obj in array) {
198
+ NSDictionary *json = [self poiToJsonObject:obj];
199
+
200
+ [ja addObject:json];
201
+ }
202
+ return ja;
203
+ }
204
+
205
+ - (NSArray *)eventsToJsonArray:(NSArray *)array
206
+ {
207
+ NSMutableArray *ja = [[NSMutableArray alloc] init];
208
+ for (SITEvent *obj in array) {
209
+ NSDictionary *json = [self eventToJsonObject:obj];
210
+
211
+ [ja addObject:json];
212
+ }
213
+ return ja;
214
+ }
215
+
216
+ - (NSArray *)geofencesToJsonArray:(NSArray *)array
217
+ {
218
+ NSMutableArray *ja = [[NSMutableArray alloc] init];
219
+ for (SITGeofence *obj in array) {
220
+ NSDictionary *json = [self geofenceToJsonObject:obj];
221
+
222
+ [ja addObject:json];
223
+ }
224
+ return ja;
225
+ }
226
+
227
+ // Building Info
228
+ - (NSDictionary *) buildingInfoToJsonObject:(SITBuildingInfo *)buildingInfo
229
+ {
230
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
231
+
232
+ // Building
233
+ [jo setObject:[self buildingToJsonObject:buildingInfo.building] forKey:@"building"];
234
+ // Floors
235
+ [jo setObject:[self floorsToJsonArray:buildingInfo.floors] forKey:@"floors"];
236
+ // Indoor Pois
237
+ [jo setObject:[self poisToJsonArray:buildingInfo.indoorPois] forKey:@"indoorPois"];
238
+ // Outdoor Pois
239
+ [jo setObject:[self poisToJsonArray:buildingInfo.outdoorPois] forKey:@"outdoorPois"];
240
+ // Events
241
+ [jo setObject:[self eventsToJsonArray:buildingInfo.events] forKey:@"events"];
242
+ // Geofences?
243
+ [jo setObject:[self geofencesToJsonArray:buildingInfo.geofences] forKey:@"geofences"];
244
+
245
+ return jo;
246
+ }
247
+
248
+ - (SITLocationRequest *) dictToLocationRequest: (NSDictionary *) dict {
249
+ if (dict.allKeys.count == 0) { // Empty
250
+ NSLog(@"using remote configuration");
251
+ return nil; // Remote Config
252
+ }
253
+
254
+ NSString *buildingId;
255
+
256
+ if ([dict valueForKey:@"buildingIdentifier"]) {
257
+ buildingId = [NSString stringWithFormat:@"%@", [dict valueForKey:@"buildingIdentifier"]];
258
+ }
259
+
260
+ SITLocationRequest *locationRequest = [[SITLocationRequest alloc] initWithBuildingId:buildingId];
261
+
262
+ if ([dict valueForKey:@"useGlobalLocation"]) {
263
+ [locationRequest setUseGlobalLocation:[[dict objectForKey:@"useGlobalLocation"] boolValue]];
264
+ }
265
+
266
+ // TODO: Make parser from external to internal options
267
+ if ([dict valueForKey:@"outdoorLocationOptions"]) {
268
+ SITOutdoorLocationOptions *outdoorLocationOptions= [SITOutdoorLocationOptions new];
269
+
270
+ NSDictionary *options = [dict valueForKey:@"outdoorLocationOptions"];
271
+
272
+ if ([options valueForKey: @"buildingDetector"]) {
273
+ NSString *bDetector = [options valueForKey: @"buildingDetector"];
274
+
275
+ if ([bDetector isEqualToString:@"BLE"] || [bDetector isEqualToString:@"WIFI"] || [bDetector isEqualToString:@"WIFI_AND_BLE"]) { // ble, gps, others?
276
+ outdoorLocationOptions.buildingDetector = kSITBLE;
277
+ } else {
278
+ outdoorLocationOptions.buildingDetector = kSITGpsProximity;
279
+ }
280
+ }
281
+ // minimumOutdoorLocationAccuracy
282
+ if ([options valueForKey: @"minimumOutdoorLocationAccuracy"]) {
283
+ outdoorLocationOptions.minimumOutdoorLocationAccuracy = [[options valueForKey: @"minimumOutdoorLocationAccuracy"] intValue];
284
+ }
285
+
286
+ if ([options valueForKey: @"enableOutdoorPositions"]) {
287
+ outdoorLocationOptions.enableOutdoorPositions = [[options valueForKey: @"enableOutdoorPositions"] boolValue];
288
+ }
289
+
290
+ if ([options valueForKey: @"updateInterval"]) {
291
+ outdoorLocationOptions.updateInterval = [[options valueForKey: @"updateInterval"] intValue];
292
+ }
293
+
294
+ if ([options valueForKey: @"computeInterval"]) {
295
+ outdoorLocationOptions.computeInterval = [[options valueForKey: @"computeInterval"] intValue];
296
+ }
297
+
298
+ if ([options valueForKey: @"useGeofencesinBuildingSelector"]) {
299
+ outdoorLocationOptions.useGeofencesInBuildingSelector = [[options objectForKey: @"useGeofencesinBuildingSelector"] boolValue];
300
+ }
301
+
302
+ if ([options valueForKey: @"enableOutdoorPositions"]) {
303
+ outdoorLocationOptions.enableOutdoorPositions = [[options objectForKey: @"enableOutdoorPositions"] boolValue];
304
+
305
+ }
306
+
307
+ if ([options valueForKey: @"backgroundAccuracy"]) {
308
+ NSString *accuracy = [options valueForKey: @"backgroundAccuracy"];
309
+
310
+ if ([accuracy isEqualToString:@"NAVIGATION"]) {
311
+ outdoorLocationOptions.backgroundAccuracy = kSITBackgroundAccuracyNavigation;
312
+ } else if ([accuracy isEqualToString:@"HIGH"]) {
313
+ outdoorLocationOptions.backgroundAccuracy = kSITBackgroundAccuracyHigh;
314
+ }else if ([accuracy isEqualToString:@"MEDIUM"]) {
315
+ outdoorLocationOptions.backgroundAccuracy = kSITBackgroundAccuracyMedium;
316
+ }else if ([accuracy isEqualToString:@"LOW"]) {
317
+ outdoorLocationOptions.backgroundAccuracy = kSITBackgroundAccuracyLow;
318
+ }
319
+ }
320
+
321
+ locationRequest.outdoorLocationOptions = outdoorLocationOptions;
322
+ }
323
+
324
+ if ([dict objectForKey:@"useDeadReckoning"]) {
325
+ [locationRequest setUseDeadReckoning:[[dict valueForKey:@"useDeadReckoning"] boolValue]];
326
+ }
327
+
328
+ if([dict valueForKey:@"useGps"]) {
329
+ [locationRequest setUseGps:[[dict objectForKey:@"useGps"] boolValue]];
330
+ }
331
+
332
+ if([dict valueForKey:@"interval"]) {
333
+ [locationRequest setInterval:[[dict valueForKey:@"interval"] intValue]];
334
+ }
335
+
336
+ if ([dict valueForKey:@"smallestDisplacement"]) {
337
+ [locationRequest setSmallestDisplacement:[[dict valueForKey:@"smallestDisplacement"] floatValue]];
338
+ }
339
+
340
+ if([dict valueForKey:@"useBarometer"]) {
341
+ [locationRequest setUseBarometer:[[dict objectForKey:@"useBarometer"] boolValue]];
342
+ }
343
+
344
+ if ([dict valueForKey:@"realtimeUpdateInterval"]) {
345
+ NSString *updateInterval = [dict valueForKey: @"realtimeUpdateInterval"];
346
+
347
+ if ([updateInterval isEqualToString:@"REALTIME"]) {
348
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateIntervalRealtime];
349
+ } else if ([updateInterval isEqualToString:@"FAST"]) {
350
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateIntervalFast];
351
+ }else if ([updateInterval isEqualToString:@"NORMAL"]) {
352
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateIntervalNormal];
353
+ }else if ([updateInterval isEqualToString:@"SLOW"]) {
354
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateIntervalSlow];
355
+ }else if ([updateInterval isEqualToString:@"BATTERY_SAVER"]) {
356
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateIntervalBatterySaver];
357
+ }else if ([updateInterval isEqualToString:@"NEVER"]) {
358
+ [locationRequest setRealtimeUpdateInterval:kSITUpdateNever];
359
+ }
360
+ }
361
+
362
+ if ([dict valueForKey:@"useLocationsCache"]) {
363
+ locationRequest.useLocationsCache = [[dict objectForKey:@"useLocationsCache"] boolValue];
364
+ }
365
+ return locationRequest;
366
+ }
367
+
368
+ - (SITLocationRequest *) jsonObjectToLocationRequest: (NSArray *) json {
369
+ NSDictionary *buildingJO;
370
+ NSNumber *useDeadReckoning = nil;
371
+ NSNumber *useGps = nil;
372
+ NSString *buildingId;
373
+ NSString *realtimeUpdateInterval;
374
+ NSNumber *interval = nil;
375
+ NSNumber *smallestDisplacement = nil;
376
+ NSNumber *useBarometer = nil;
377
+ SITRealtimeUpdateInterval realtimeInterval = 0;
378
+
379
+
380
+
381
+ //The following if-else is necessary in order to mantain compatibility
382
+ //with the startPositioning[building] method.
383
+ //If params is an array, then it contains both a building and a locationRequest
384
+ //If params is a dictionary, then it should only contain a building
385
+
386
+ if ([json isKindOfClass:[NSArray class]]) {
387
+ buildingJO = (NSDictionary*)[json objectAtIndex:0];
388
+ if (json.count > 1) {
389
+ NSDictionary *requestJO = (NSDictionary*)[json objectAtIndex:1];
390
+ buildingId = [NSString stringWithFormat:@"%@", requestJO[@"buildingIdentifier"]];
391
+ useDeadReckoning = [requestJO objectForKey: @"useDeadReckoning"];
392
+ useGps = [requestJO objectForKey: @"useGps"];
393
+ realtimeUpdateInterval = requestJO[@"realtimeUpdateInterval"];
394
+ interval = requestJO[@"interval"];
395
+ smallestDisplacement = requestJO[@"smallestDisplacement"];
396
+ useBarometer = [requestJO objectForKey: @"useBarometer"];
397
+ }
398
+ } else {
399
+ buildingJO = (NSDictionary*)json[0];
400
+ }
401
+
402
+ if (buildingId == nil) {
403
+ buildingId = [buildingJO valueForKey:@"identifier"];
404
+ }
405
+
406
+ if (buildingId == nil) {
407
+ buildingId = [NSString stringWithFormat:@"%@", [buildingJO valueForKey:@"buildingIdentifier"]];
408
+ }
409
+
410
+ if (realtimeUpdateInterval != nil && [realtimeUpdateInterval isKindOfClass: [NSString class]]) {
411
+
412
+ if ([realtimeUpdateInterval isEqualToString:@"REALTIME"]) {
413
+ realtimeInterval = kSITUpdateIntervalRealtime;
414
+ } else if ([realtimeUpdateInterval isEqualToString:@"FAST"]) {
415
+ realtimeInterval = kSITUpdateIntervalFast;
416
+ } else if ([realtimeUpdateInterval isEqualToString:@"NORMAL"]) {
417
+ realtimeInterval = kSITUpdateIntervalNormal;
418
+ } else if ([realtimeUpdateInterval isEqualToString:@"SLOW"]) {
419
+ realtimeInterval = kSITUpdateIntervalSlow;
420
+ } else if ([realtimeUpdateInterval isEqualToString:@"BATTERY_SAVER"]) {
421
+ realtimeInterval = kSITUpdateIntervalBatterySaver;
422
+ }
423
+ }
424
+
425
+ SITLocationRequest *locationRequest = [[SITLocationRequest alloc] initWithBuildingId:buildingId];
426
+ if (useDeadReckoning != nil) {
427
+ [locationRequest setUseDeadReckoning:[useDeadReckoning boolValue]];
428
+
429
+ }
430
+ if(useGps != nil) {
431
+ [locationRequest setUseGps:[useGps boolValue]];
432
+ }
433
+
434
+ if(interval != nil) {
435
+ [locationRequest setInterval:[interval intValue]];
436
+ }
437
+
438
+ if (smallestDisplacement != nil) {
439
+ [locationRequest setSmallestDisplacement:[smallestDisplacement floatValue]];
440
+ }
441
+
442
+ if(useBarometer != nil) {
443
+ [locationRequest setUseBarometer: [useBarometer boolValue]];
444
+ }
445
+
446
+ if (realtimeInterval != 0) {
447
+ [locationRequest setUpdateInterval:realtimeInterval];
448
+ }
449
+ return locationRequest;
450
+ }
451
+
452
+ - (NSString*) locationStateToString:(SITLocationState) state {
453
+ NSString *type = @"";
454
+ switch (state) {
455
+ case kSITLocationStopped:
456
+ type = @"STOPPED";
457
+ break;
458
+ case kSITLocationCalculating:
459
+ type = @"CALCULATING";
460
+ break;
461
+ case kSITLocationUserNotInBuilding:
462
+ type = @"USER_NOT_IN_BUILDING";
463
+ break;
464
+ case kSITLocationStarted:
465
+ type = @"STARTING";
466
+ break;
467
+
468
+ default:
469
+ break;
470
+ }
471
+ return type;
472
+ }
473
+
474
+ - (NSDictionary *) locationStateToJsonObject:(SITLocationState) state {
475
+
476
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
477
+ [jo setValue: [self locationStateToString:state] forKey: @"statusName"];
478
+ NSNumber *status = [NSNumber numberWithInt:state];
479
+ [jo setValue: status forKey: @"statusOrdinal"];
480
+ return jo;
481
+ }
482
+
483
+ //deprecated method
484
+
485
+ - (NSDictionary *) buildingIndoorToJsonObject:(SITIndoorBuilding *) building __deprecated{
486
+
487
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
488
+ [jo setObject:emptyStrCheck(building.address) forKey:@"address"];
489
+ [jo setObject:[self boundsToJsonObject:building.bounds] forKey:@"bounds"];
490
+ [jo setObject:[self boundsToJsonObject:building.boundsRotated] forKey:@"boundsRotated"];
491
+ [jo setObject:[self coordinateToJsonObject:building.coordinate] forKey:@"center"];
492
+ // [jo setObject:[self dimensionsToJsonObject:building.dimensions] forKey:@"dimensions"];
493
+ [jo setObject:emptyStrCheck(building.name) forKey:@"name"];
494
+ [jo setObject:emptyStrCheck(building.picture_thumb_url) forKey:@"pictureThumbUrl"];
495
+ [jo setObject:emptyStrCheck(building.picture_url) forKey:@"pictureUrl"];
496
+ [jo setObject:building.rotation forKey:@"rotation"];
497
+ //TODO check
498
+ //[jo setObject:emptyStrCheck(building.user_identifier) forKey:@"userIdentifier"];
499
+ [jo setObject:emptyStrCheck([NSString stringWithFormat:@"%@", building.identifier]) forKey:@"identifier"];
500
+
501
+ // if (building.customFields) {
502
+ // [jo setObject:building.customFields forKey:@"customFields"];
503
+ // }
504
+
505
+ return jo.copy;
506
+ }
507
+
508
+
509
+ // Geofence
510
+ - (NSDictionary *)geofenceToJsonObject:(SITGeofence *)geofence {
511
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
512
+
513
+ // Complete implementation
514
+ [jo setObject:emptyStrCheck(geofence.identifier) forKey:@"identifier"];
515
+ [jo setObject:emptyStrCheck(geofence.buildingIdentifier) forKey:@"buildingIdentifier"];
516
+ [jo setObject:emptyStrCheck(geofence.floorIdentifier) forKey:@"floorIdentifier"];
517
+
518
+ [jo setObject:emptyStrCheck(geofence.name) forKey:@"name"];
519
+
520
+ // Polygon Points
521
+ [jo setObject:[self pointsToJsonArray:geofence.polygonPoints] forKey:@"polygonPoints"];
522
+
523
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
524
+ [dateFormatter setDateFormat:kDateFormat];
525
+
526
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:geofence.createdAt])
527
+ forKey:@"createdAt"];
528
+
529
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:geofence.updatedAt])
530
+ forKey:@"updatedAt"];
531
+
532
+ if (geofence.customFields) {
533
+ [jo setObject:geofence.customFields forKey:@"customFields"];
534
+ } else {
535
+ [jo setObject:[NSDictionary new] forKey:@"customFields"];
536
+ }
537
+ [jo setObject:emptyStrCheck(geofence.infoHtml) forKey:@"infoHtml"];
538
+
539
+
540
+
541
+ return jo;
542
+ }
543
+
544
+ //Floor
545
+
546
+ - (NSDictionary *) floorToJsonObject:(SITFloor *) floor {
547
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
548
+ //TODO review added altitude key
549
+ [jo setObject:[NSNumber numberWithDouble:floor.altitude] forKey:@"altitude"];
550
+ [jo setObject:emptyStrCheck([NSString stringWithFormat:@"%@", floor.buildingIdentifier]) forKey:@"buildingIdentifier"];
551
+ [jo setObject:[NSNumber numberWithInteger: floor.level] forKey:@"level"];
552
+ [jo setObject:[NSNumber numberWithInteger: floor.floor] forKey:@"floor"];
553
+ [jo setObject:floor.mapURL.direction forKey:@"mapUrl"];
554
+ [jo setObject:[NSNumber numberWithDouble:floor.scale] forKey:@"scale"];
555
+ [jo setObject:[NSString stringWithFormat:@"%@", floor.identifier] forKey:@"floorIdentifier"];
556
+ [jo setObject:emptyStrCheck(floor.identifier) forKey:@"identifier"];
557
+ [jo setObject:emptyStrCheck(floor.name) forKey:@"name"];
558
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
559
+ [dateFormatter setDateFormat:kDateFormat];
560
+
561
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:floor.createdAt])
562
+ forKey:@"createdAt"];
563
+
564
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:floor.updatedAt])
565
+ forKey:@"updatedAt"];
566
+
567
+ return jo.copy;
568
+ }
569
+
570
+ - (SITFloor *) jsonObjectToFloor:(NSDictionary *) nsFloor {
571
+ SITFloor *floor = [[SITFloor alloc] init];
572
+
573
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
574
+ [dateFormatter setDateFormat:kDateFormat];
575
+
576
+ floor.createdAt = [dateFormatter dateFromString:nsFloor[@"createdAt"]];
577
+
578
+ floor.updatedAt = [dateFormatter dateFromString:nsFloor[@"updatedAt"]];
579
+
580
+ floor.scale = [[nsFloor objectForKey:@"scale"] doubleValue];
581
+ floor.mapURL = [[SITURL alloc] initWithDirection:[nsFloor objectForKey:@"mapUrl"]];;
582
+ floor.level = [[nsFloor objectForKey:@"level"] intValue];
583
+ floor.floor = [[nsFloor objectForKey:@"floor"] intValue];
584
+ floor.identifier = [nsFloor objectForKey:@"floorIdentifier"];
585
+ floor.name = [nsFloor objectForKey:@"name"];
586
+ floor.buildingIdentifier = [nsFloor objectForKey:@"buildingIdentifier"];
587
+ floor.altitude = [nsFloor[@"altitude"] doubleValue];
588
+ return floor;
589
+ }
590
+
591
+ //Event
592
+
593
+ - (NSDictionary *) eventToJsonObject:(SITEvent *) event {
594
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
595
+ jo[@"identifier"] = event.identifier;
596
+ jo[@"buildingIdentifier"] = event.project_identifier;
597
+ jo[@"floorIdentifier"] = event.trigger.center.floorIdentifier;
598
+ jo[@"infoHtml"] = event.info;
599
+ jo[@"name"] = event.name;
600
+ jo[@"radius"] = event.trigger.radius;
601
+ jo[@"x"] = @(event.trigger.center.cartesianCoordinate.x);
602
+ jo[@"y"] = @(event.trigger.center.cartesianCoordinate.y);
603
+
604
+ jo[@"trigger"] = [self circleAreaToJsonObject:event.trigger];
605
+ if (event.conversion != nil) {
606
+ jo[@"conversion"] = [self circleAreaToJsonObject:event.conversion];
607
+ }
608
+
609
+ jo[@"conversionArea"] = [self conversionAreaToJsonObject:event.conversionArea];
610
+ jo[@"customFields"] = event.customFields != nil ? event.customFields : [NSDictionary new];
611
+
612
+ return jo.copy;
613
+ }
614
+
615
+ //Category
616
+
617
+ //Floor
618
+
619
+ - (NSDictionary *) poiCategoryToJsonObject:(SITPOICategory *) category {
620
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
621
+ [jo setObject:[NSString stringWithFormat:@"%@", category.identifier] forKey:@"identifier"];
622
+ [jo setObject:[NSNumber numberWithBool:category.isPublic] forKey:@"public"];
623
+ [jo setObject:[NSString stringWithFormat:@"%@", category.code] forKey:@"poiCategoryCode"];
624
+ [jo setObject:[NSString stringWithFormat:@"%@", [category.name value]] forKey:@"poiCategoryName"];
625
+
626
+ // TODO 2022-02-23: Make this moore programming friendly (make a loop through languages or something)
627
+
628
+ NSMutableDictionary *nameJO = [[NSMutableDictionary alloc]init];
629
+
630
+ [nameJO setObject:[category.name valueForLocale:[NSLocale localeWithLocaleIdentifier:@"en"]] forKey:@"en"];
631
+ [nameJO setObject:[category.name valueForLocale:[NSLocale localeWithLocaleIdentifier:@"es"]] forKey:@"es"];
632
+
633
+ [jo setObject: nameJO forKey: @"name"];
634
+
635
+ [jo setObject:category.iconURL.direction forKey:@"icon_deselected"];
636
+ [jo setObject:category.selectedIconURL.direction forKey:@"icon_selected"];
637
+ return jo.copy;
638
+ }
639
+
640
+ - (SITPOICategory *) poiCategoryFromJsonObject:(NSDictionary *) jo {
641
+ SITPOICategory *category = [[SITPOICategory alloc] init];
642
+ category.name = [[SITMultilanguageString alloc] initWithValue:[jo objectForKey:@"poiCategoryName"] defaultLocale:[NSLocale currentLocale]];
643
+ category.code = [jo objectForKey:@"poiCategoryCode"];
644
+ category.isPublic = [jo objectForKey:@"public"];
645
+ category.selectedIconURL = [[SITURL alloc] initWithDirection:[jo objectForKey:@"icon_selected"]];
646
+ if([jo objectForKey:@"icon_unselected"]) {
647
+ category.iconURL = [[SITURL alloc] initWithDirection:[jo objectForKey:@"icon_unselected"]];
648
+ } else {
649
+ category.iconURL = [[SITURL alloc] initWithDirection:[jo objectForKey:@"icon_deselected"]];
650
+ }
651
+ return category;
652
+ }
653
+
654
+ - (NSDictionary *)bitmapToJsonObject:(UIImage *)icon {
655
+ NSString *base64 = [UIImagePNGRepresentation(icon) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
656
+ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
657
+ [dict setObject:base64 forKey:@"data"];
658
+ return dict;
659
+ }
660
+
661
+ // POI
662
+
663
+ - (NSDictionary *) poiToJsonObject:(SITPOI *) poi {
664
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
665
+ [jo setObject:emptyStrCheck(poi.identifier) forKey:@"identifier"];
666
+ [jo setObject:emptyStrCheck(poi.buildingIdentifier) forKey:@"buildingIdentifier"];
667
+ [jo setObject:[self cartesianCoordinateToJsonObject:poi.position.cartesianCoordinate] forKey:@"cartesianCoordinate"];
668
+ [jo setObject:[self coordinateToJsonObject:poi.position.coordinate] forKey:@"coordinate"];
669
+ [jo setObject:emptyStrCheck(poi.position.floorIdentifier) forKey:@"floorIdentifier"];
670
+ [jo setObject:emptyStrCheck(poi.name) forKey:@"poiName"];
671
+ [jo setObject:[self pointToJsonObject:poi.position] forKey:@"position"];
672
+ [jo setObject:[NSNumber numberWithBool:poi.position.isIndoor] forKey:@"isIndoor"];
673
+ [jo setObject:[NSNumber numberWithBool:poi.position.isOutdoor] forKey:@"isOutdoor"];
674
+ [jo setObject: [self poiCategoryToJsonObject:poi.category] forKey:@"category"];
675
+
676
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
677
+ [dateFormatter setDateFormat:kDateFormat];
678
+
679
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:poi.createdAt])
680
+ forKey:@"createdAt"];
681
+
682
+ [jo setObject:emptyStrCheck([dateFormatter stringFromDate:poi.updatedAt])
683
+ forKey:@"updatedAt"];
684
+
685
+ if (poi.customFields) {
686
+ [jo setObject:poi.customFields forKey:@"customFields"];
687
+ } else {
688
+ [jo setObject:[NSDictionary new] forKey:@"customFields"];
689
+ }
690
+ [jo setObject:emptyStrCheck(poi.infoHTML) forKey:@"infoHtml"];
691
+ return jo.copy;
692
+ }
693
+
694
+ // Location
695
+
696
+ - (NSDictionary *) locationToJsonObject:(SITLocation *) location {
697
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
698
+ [jo setObject:[NSNumber numberWithFloat:location.accuracy] forKey:@"accuracy"];
699
+ [jo setObject:[self angleToJsonObject:location.bearing] forKey:@"bearing"];
700
+ [jo setObject:[self qualityStringFromQuality:location.bearingQuality] forKey:@"bearingQuality"];
701
+ [jo setObject:emptyStrCheck(location.position.buildingIdentifier) forKey:@"buildingIdentifier"];
702
+ [jo setObject:[self angleToJsonObject:location.cartesianBearing] forKey:@"cartesianBearing"];
703
+ [jo setObject:[self cartesianCoordinateToJsonObject:location.position.cartesianCoordinate] forKey:@"cartesianCoordinate"];
704
+ [jo setObject:[self coordinateToJsonObject:location.position.coordinate] forKey:@"coordinate"];
705
+ [jo setObject:emptyStrCheck(location.position.floorIdentifier) forKey:@"floorIdentifier"];
706
+ [jo setObject:[self pointToJsonObject:location.position] forKey:@"position"];
707
+ [jo setObject:emptyStrCheck(location.provider) forKey:@"provider"];
708
+ [jo setObject:[self qualityStringFromQuality:location.quality] forKey:@"quality"];
709
+ [jo setObject:[NSNumber numberWithBool:location.hasBearing] forKey:@"hasBearing"];
710
+ [jo setObject:[NSNumber numberWithDouble:location.timestamp] forKey:@"timestamp"];
711
+ [jo setObject:[NSNumber numberWithBool:location.position.isIndoor] forKey:@"isIndoor"];
712
+ [jo setObject:[NSNumber numberWithBool:location.position.isOutdoor] forKey:@"isOutdoor"];
713
+ [jo setObject:emptyStrCheck(location.deviceId) forKey:@"deviceId"];
714
+ [jo setValue:@"locationChanged" forKey:@"type"];
715
+ return jo.copy;
716
+ }
717
+
718
+ - (NSString *)qualityStringFromQuality:(kSITQualityValues)quality {
719
+ return quality == kSITHigh ? @"HIGH":@"LOW";
720
+ }
721
+
722
+ - (SITLocation *) locationJsonObjectToLocation:(NSDictionary *) jo {
723
+ NSTimeInterval timestamp = [(NSNumber*)[jo valueForKey:@"timestamp"] doubleValue];
724
+ SITPoint *position = [self pointJsonObjectToPoint:[jo objectForKey:@"position"]];
725
+
726
+ float bearing = [[[jo objectForKey:@"bearing"] valueForKey:@"degrees"] floatValue];
727
+ float cartesianBearing = [[[jo objectForKey:@"cartesianBearing"] valueForKey:@"radians"] floatValue];
728
+
729
+ kSITQualityValues quality = [(NSString*)[jo valueForKey: @"quality"] isEqualToString: @"HIGH"] ? kSITHigh : kSITLow;
730
+ kSITQualityValues bearingQuality = [(NSString*)[jo valueForKey: @"bearingQuality"] isEqualToString: @"HIGH"] ? kSITHigh : kSITLow;
731
+
732
+ float accuracy = [(NSNumber*)[jo objectForKey:@"accuracy"] floatValue];
733
+
734
+ SITLocation *location = [[SITLocation alloc] initWithTimestamp:timestamp position:position bearing:bearing cartesianBearing:cartesianBearing quality:quality accuracy:accuracy provider:[jo objectForKey:@"provider"]];
735
+ location.bearingQuality = bearingQuality;
736
+ return location;
737
+ }
738
+
739
+ - (NSDictionary *) coordinateToJsonObject:(CLLocationCoordinate2D) coordinate {
740
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
741
+ [jo setObject:[NSNumber numberWithDouble:coordinate.latitude] forKey:@"latitude"];
742
+ [jo setObject:[NSNumber numberWithDouble:coordinate.longitude] forKey:@"longitude"];
743
+ return jo.copy;
744
+ }
745
+ - (CLLocationCoordinate2D) jsonObjectToCoordinate:(NSDictionary *) json {
746
+ double latitude = [(NSNumber*)[json valueForKey:@"latitude"] doubleValue];
747
+ double longitude = [(NSNumber*)[json valueForKey:@"longitude"] doubleValue];
748
+
749
+
750
+ CLLocationCoordinate2D coordinate;
751
+ coordinate.latitude = latitude;
752
+ coordinate.longitude = longitude;
753
+ return coordinate;
754
+ }
755
+
756
+ // Coordinate
757
+
758
+ - (NSDictionary *) indoorPointToJsonObject:(SITIndoorPoint *) iPoint {
759
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
760
+
761
+ if (iPoint == nil) {
762
+ iPoint = [SITIndoorPoint new];
763
+ iPoint.x = @(0);
764
+ iPoint.y = @(0);
765
+ }
766
+ jo[@"x"] = iPoint.x;
767
+ jo[@"y"] = iPoint.y;
768
+ return jo.copy;
769
+ }
770
+
771
+ - (CLLocationCoordinate2D) coordinateJsonObjectToCoordinate:(NSDictionary *) jo {
772
+ CLLocationDegrees latitude = [(NSNumber*)[jo objectForKey:@"latitude"] doubleValue];
773
+ CLLocationDegrees longitude = [(NSNumber*)[jo objectForKey:@"longitude"] doubleValue];
774
+
775
+ CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
776
+ return coordinate;
777
+ }
778
+
779
+
780
+ // Point
781
+ - (NSArray *) pointsToJsonArray:(NSArray<SITPoint *> *)points {
782
+ NSMutableArray *pointsJO = [[NSMutableArray alloc]init];
783
+ for(SITPoint* point in points) {
784
+ [pointsJO addObject: [self pointToJsonObject: point]];
785
+ }
786
+ return pointsJO;
787
+ }
788
+
789
+ - (NSDictionary *) pointToJsonObject:(SITPoint *) point {
790
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
791
+ [jo setObject:emptyStrCheck(point.buildingIdentifier) forKey:@"buildingIdentifier"];
792
+ [jo setObject:[self cartesianCoordinateToJsonObject:point.cartesianCoordinate] forKey:@"cartesianCoordinate"];
793
+ [jo setObject:[self coordinateToJsonObject:point.coordinate] forKey:@"coordinate"];
794
+ [jo setObject:emptyStrCheck(point.floorIdentifier) forKey:@"floorIdentifier"];
795
+ [jo setObject:[NSNumber numberWithBool:point.isIndoor] forKey:@"isIndoor"];
796
+ [jo setObject:[NSNumber numberWithBool:point.isOutdoor] forKey:@"isOutdoor"];
797
+ return jo.copy;
798
+
799
+ }
800
+
801
+ - (SITPoint *) pointJsonObjectToPoint:(NSDictionary *) jo {
802
+ SITPoint *point = nil;
803
+ BOOL isOutdoor = [(NSNumber*)jo[@"isOutdoor"] boolValue];
804
+ if(isOutdoor) {
805
+ point = [[SITPoint alloc] initWithCoordinate: [self coordinateJsonObjectToCoordinate:[jo objectForKey:@"coordinate"]]
806
+ buildingIdentifier: [jo valueForKey:@"buildingIdentifier"]];
807
+ } else {
808
+ point = [[SITPoint alloc] initWithCoordinate:[self coordinateJsonObjectToCoordinate:[jo objectForKey:@"coordinate"]] buildingIdentifier:[jo valueForKey:@"buildingIdentifier"] floorIdentifier:[jo valueForKey:@"floorIdentifier"] cartesianCoordinate:[self cartesianCoordinateJsonObjectToCartesianCoordinate:[jo objectForKey:@"cartesianCoordinate"]]];
809
+ }
810
+ return point;
811
+ }
812
+
813
+ // CartesianCoordinate
814
+
815
+ - (NSDictionary *) cartesianCoordinateToJsonObject:(SITCartesianCoordinate *) cartesianCoordinate {
816
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
817
+ [jo setObject:[NSNumber numberWithDouble:cartesianCoordinate.x] forKey:@"x"];
818
+ [jo setObject:[NSNumber numberWithDouble:cartesianCoordinate.y] forKey:@"y"];
819
+ return jo.copy;
820
+
821
+ }
822
+
823
+ - (SITCartesianCoordinate *) cartesianCoordinateJsonObjectToCartesianCoordinate:(NSDictionary *) jo {
824
+ SITCartesianCoordinate *cartesianCoordinate = [[SITCartesianCoordinate alloc] initWithX:[[jo valueForKey:@"x"] doubleValue] y:[[jo valueForKey:@"y"] doubleValue]];
825
+ return cartesianCoordinate;
826
+ }
827
+
828
+ - (SITDirectionsRequest *) jsonObjectToDirectionsRequest: (NSArray *) json {
829
+ NSDictionary* buildingJO = (NSDictionary*)[json objectAtIndex:0];
830
+ NSDictionary* from = (NSDictionary*)[json objectAtIndex:1];
831
+ NSMutableDictionary* fromPoint = [from mutableCopy];
832
+ NSDictionary* to = (NSDictionary*)[json objectAtIndex:2];
833
+ NSMutableDictionary* toPoint = [to mutableCopy];
834
+
835
+ NSDictionary* options = nil;
836
+ if(json.count>3)
837
+ options = (NSDictionary*)[json objectAtIndex:3];
838
+
839
+ NSDictionary* dimensionsJO = (NSDictionary*)[buildingJO objectForKey:@"dimensions"];
840
+ NSDictionary* centerJo = (NSDictionary*)[buildingJO objectForKey:@"center"];
841
+
842
+ SITDimensions *dimensions = [self jsonObjectToDimensions:dimensionsJO];
843
+ CLLocationCoordinate2D center = [self jsonObjectToCoordinate:centerJo];
844
+
845
+ float rotation =[[buildingJO valueForKey:@"rotation"] floatValue];
846
+
847
+ SITAngle *angle = [[SITAngle alloc] initWithRadians:rotation];
848
+ SITCoordinateConverter *converter = [[SITCoordinateConverter alloc]initWithDimensions:dimensions center:center rotation:angle];
849
+
850
+ NSLog(@"building properties::: dimensions:: width: %f, height: %f; rotation: %f; angle: %@", dimensions.width, dimensions.height, rotation, angle);
851
+
852
+ CLLocationCoordinate2D fromCoordinate = [self jsonObjectToCoordinate:(NSDictionary*)[fromPoint objectForKey:@"coordinate"]];
853
+ [fromPoint setObject:[self cartesianCoordinateToJsonObject:[converter toCartesianCoordinate:fromCoordinate]] forKey:@"cartesianCoordinate"];
854
+
855
+ CLLocationCoordinate2D toCoordinate = [self jsonObjectToCoordinate:(NSDictionary*)[toPoint objectForKey:@"coordinate"]];
856
+ [toPoint setObject:[self cartesianCoordinateToJsonObject:[converter toCartesianCoordinate:toCoordinate]] forKey:@"cartesianCoordinate"];
857
+
858
+
859
+ SITPoint *startPoint = [SitumLocationWrapper.shared pointJsonObjectToPoint:fromPoint];
860
+ SITPoint *endPoint = [SitumLocationWrapper.shared pointJsonObjectToPoint:toPoint];
861
+
862
+
863
+ SITDirectionsRequest *directionsRequest = [[SITDirectionsRequest alloc] initWithOrigin: startPoint withDestination: endPoint];
864
+
865
+ NSString *accessibilityModeValue = nil;
866
+ SITAccessibilityMode accessibilityMode = kSITChooseShortest;
867
+
868
+ if(options) {
869
+ accessibilityModeValue = options[@"accessibilityMode"];
870
+ if (accessibilityModeValue != nil && ![accessibilityModeValue isEqual:[NSNull null]]) {
871
+ if ([accessibilityModeValue isEqualToString:@"ONLY_ACCESSIBLE"]) {
872
+ accessibilityMode = kSITOnlyAccessible;
873
+ } else if ([accessibilityModeValue isEqualToString:@"ONLY_NOT_ACCESSIBLE_FLOOR_CHANGES"]) {
874
+ accessibilityMode = kSITOnlyNotAccessibleFloorChanges;
875
+ }
876
+ [directionsRequest setAccessibility:accessibilityMode];
877
+ }
878
+ // TODO: add support for the remaining direction options
879
+ }
880
+
881
+ return directionsRequest;
882
+ }
883
+
884
+
885
+ // Dimensions
886
+
887
+ - (NSDictionary *) dimensionsToJsonObject:(SITDimensions *) dimensions {
888
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
889
+ [jo setObject:[NSNumber numberWithDouble:dimensions.width] forKey:@"width"];
890
+ [jo setObject:[NSNumber numberWithDouble:dimensions.height] forKey:@"height"];
891
+ return jo.copy;
892
+ }
893
+
894
+ - (SITDimensions *) jsonObjectToDimensions:(NSDictionary *) json {
895
+ double width = [(NSNumber*)[json valueForKey:@"width"] doubleValue];
896
+ double height = [(NSNumber*)[json valueForKey:@"height"] doubleValue];
897
+ SITDimensions *dimension = [[SITDimensions alloc] initWithWidth:width height:height];
898
+ return dimension;
899
+ }
900
+
901
+ // Bounds
902
+
903
+ - (NSDictionary *) boundsToJsonObject:(SITBounds) bounds {
904
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
905
+ [jo setObject:[self coordinateToJsonObject:bounds.northEast] forKey:@"northEast"];
906
+ [jo setObject:[self coordinateToJsonObject:bounds.northWest] forKey:@"northWest"];
907
+ [jo setObject:[self coordinateToJsonObject:bounds.southEast] forKey:@"southEast"];
908
+ [jo setObject:[self coordinateToJsonObject:bounds.southWest] forKey:@"southWest"];
909
+ return jo.copy;
910
+ }
911
+
912
+ - (NSDictionary *) circleAreaToJsonObject:(SITCircularArea *) ca {
913
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
914
+
915
+ jo[@"center"] = ca != nil ? [self pointToJsonObject:ca.center] : nil;
916
+ jo[@"radius"] = ca != nil ? ca.radius : nil;
917
+
918
+ return jo.copy;
919
+ }
920
+
921
+ - (NSDictionary *) conversionAreaToJsonObject:(SITRectangularArea *) ca {
922
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
923
+
924
+ if (ca == nil) {
925
+ ca = [SITRectangularArea new];
926
+ }
927
+
928
+ jo[@"topLeft"] = [self indoorPointToJsonObject:ca.topLeft];
929
+ jo[@"topRight"] = [self indoorPointToJsonObject:ca.topRight];
930
+ jo[@"bottomRight"] = [self indoorPointToJsonObject:ca.bottomRight];
931
+ jo[@"bottomLeft"] = [self indoorPointToJsonObject:ca.bottomLeft];
932
+ jo[@"floorIdentifier"] = ca.center.level_identifier != nil ? ca.center.level_identifier : @(0);
933
+
934
+ return jo.copy;
935
+ }
936
+
937
+
938
+ // Angle
939
+
940
+ - (NSDictionary *) angleToJsonObject:(SITAngle *) angle {
941
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
942
+ [jo setObject:[NSNumber numberWithDouble:angle.degrees] forKey:@"degrees"];
943
+ [jo setObject:[NSNumber numberWithDouble:angle.radians] forKey:@"radians"];
944
+ [jo setObject:[NSNumber numberWithDouble:angle.degressClockwise] forKey:@"degressClockwise"];
945
+ [jo setObject:[NSNumber numberWithDouble:angle.degressClockwise] forKey:@"degreesClockwise"];
946
+ [jo setObject:[NSNumber numberWithDouble:angle.radiansMinusPiPi] forKey:@"radiansMinusPiPi"];
947
+ return jo.copy;
948
+ }
949
+
950
+ // Route
951
+
952
+ - (NSDictionary *) routeToJsonObject:(SITRoute *) route {
953
+
954
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
955
+
956
+ NSMutableArray *stepsJsonArray = [[NSMutableArray alloc] init];
957
+ for (SITRouteStep *routeStep in route.routeSteps) {
958
+ [stepsJsonArray addObject:[self routeStepToJsonObject:routeStep]];
959
+ }
960
+
961
+ NSMutableArray *pointsJsonArray = [[NSMutableArray alloc] init];
962
+ for(SITPoint* point in route.points) {
963
+ [pointsJsonArray addObject:[self pointToJsonObject: point]];
964
+ }
965
+
966
+ NSMutableArray *indicationsJsonArray = [[NSMutableArray alloc] init];
967
+ for (SITIndication *indication in route.indications) {
968
+ [indicationsJsonArray addObject:[self indicationToJsonObject:indication]];
969
+ }
970
+
971
+ NSMutableArray* segmentsJsonArray = [NSMutableArray new];
972
+ for(SITRouteSegment* segment in route.segments) {
973
+ [segmentsJsonArray addObject: [self routeSegmentToJsonObject: segment]];
974
+ }
975
+
976
+ [jo setObject: [self pointToJsonObject:route.origin] forKey:@"from"];
977
+ [jo setObject: [self pointToJsonObject:route.destination] forKey:@"to"];
978
+ [jo setObject: stepsJsonArray.copy forKey:@"steps"];
979
+ [jo setObject: pointsJsonArray.copy forKey:@"points"];
980
+ [jo setObject: indicationsJsonArray.copy forKey:@"indications"];
981
+ [jo setObject: segmentsJsonArray.copy forKey: @"segments"];
982
+
983
+ if (route.routeSteps.count == 0) return jo; // No steps on the route
984
+
985
+
986
+ [jo setObject:stepsJsonArray.copy forKey:@"edges"];
987
+ [jo setObject:stepsJsonArray.firstObject forKey:@"firstStep"];
988
+ [jo setObject:stepsJsonArray.lastObject forKey:@"lastStep"];
989
+ [jo setObject:pointsJsonArray forKey:@"nodes"];
990
+
991
+ return jo.copy;
992
+ }
993
+
994
+ // RouteSegment
995
+
996
+ - (NSDictionary*) routeSegmentToJsonObject: (SITRouteSegment*) segment {
997
+
998
+ NSMutableDictionary* jo = [NSMutableDictionary new];
999
+ [jo setObject: segment.floorIdentifier forKey: @"floorIdentifier"];
1000
+ NSMutableArray* pointsJO = [NSMutableArray new];
1001
+ for(SITPoint* point in segment.points) {
1002
+ [pointsJO addObject: [self pointToJsonObject: point]];
1003
+ }
1004
+ [jo setObject: pointsJO forKey: @"points"];
1005
+
1006
+ return [jo copy];
1007
+ }
1008
+
1009
+ //RouteStep
1010
+
1011
+ - (NSDictionary *) routeStepToJsonObject:(SITRouteStep *) routeStep {
1012
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
1013
+ [jo setObject:[NSNumber numberWithDouble:routeStep.stepDistance] forKey:@"distance"];
1014
+ [jo setObject:[NSNumber numberWithDouble:routeStep.distanceToGoal] forKey:@"distanceToGoal"];
1015
+ [jo setObject:[self pointToJsonObject:routeStep.from] forKey:@"from"];
1016
+ [jo setObject:[NSNumber numberWithInteger:routeStep.nextStepIndex] forKey:@"nextStepIndex"];
1017
+ [jo setObject:[self pointToJsonObject:routeStep.to] forKey:@"to"];
1018
+ [jo setObject:[self pointToJsonObject:routeStep.to] forKey:@"TO"];
1019
+ [jo setObject:[NSNumber numberWithInteger:routeStep.index] forKey:@"id"];
1020
+ [jo setObject:[NSNumber numberWithBool:routeStep.isFirst] forKey:@"isFirst"];
1021
+ [jo setObject:[NSNumber numberWithBool:routeStep.isLast] forKey:@"isLast"];
1022
+ return jo.copy;
1023
+ }
1024
+
1025
+ - (SITRouteStep *) routeStepJsonObjectToRouteStep:(NSDictionary *) jo {
1026
+ SITPoint *fromPoint = (SITPoint*)[jo objectForKey:@"from"];
1027
+ SITPoint *toPoint = (SITPoint*)[jo objectForKey:@"to"];
1028
+
1029
+ SITRouteStep *routeStep = [[SITRouteStep alloc] initWithIndex:[(NSNumber*)[jo valueForKey:@"id"] integerValue] from:fromPoint to:toPoint isFirst:[(NSNumber*)[jo valueForKey:@"isFirst"] boolValue] isLast:[(NSNumber*)[jo valueForKey:@"isLast"] boolValue] nextStepIndex:[(NSNumber*)[jo valueForKey:@"nextStepIndex"] integerValue] stepDistance:[(NSNumber*)[jo valueForKey:@"distance"] doubleValue] distanceToGoal:[(NSNumber*)[jo valueForKey:@"distanceToGoal"] doubleValue]];
1030
+
1031
+ return routeStep;
1032
+ }
1033
+
1034
+ // Indication
1035
+
1036
+ - (NSDictionary *) indicationToJsonObject:(SITIndication *) indication {
1037
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
1038
+ [jo setObject:[NSNumber numberWithDouble:indication.horizontalDistance] forKey:@"distance"];
1039
+ [jo setObject:[NSNumber numberWithFloat:indication.verticalDistance] forKey:@"distanceToNextLevel"];
1040
+ [jo setObject:indicationTypeToString(indication.action) forKey:@"indicationType"];
1041
+ [jo setObject:[NSNumber numberWithFloat:indication.orientationChange] forKey:@"orientation"];
1042
+ [jo setObject:orientationTypeToString(indication.orientation) forKey:@"orientationType"];
1043
+ [jo setObject:[NSNumber numberWithInteger:indication.destinationStepIndex] forKey:@"stepIdxDestination"];
1044
+ [jo setObject:[NSNumber numberWithInteger:indication.originStepIndex] forKey:@"stepIdxOrigin"];
1045
+ [jo setObject:[NSNumber numberWithBool:indication.needLevelChange] forKey:@"neededLevelChange"];
1046
+ [jo setObject:([indication humanReadableMessage]) != nil ? [indication humanReadableMessage] : @"" forKey:@"humanReadableMessage"];
1047
+ if (indication.nextLevel == nil) {
1048
+ NSLog(@"Next level is nil");
1049
+ } else {
1050
+ [jo setObject:indication.nextLevel forKey:@"nextLevel"];
1051
+ }
1052
+ return jo.copy;
1053
+ }
1054
+
1055
+ - (SITIndication *) indicationJsonObjectToIndication:(NSDictionary *) jo {
1056
+ NSInteger stepIdxOrigin = [(NSNumber*)[jo valueForKey:@"stepIdxOrigin"] integerValue];
1057
+ NSInteger stepIdxDestination = [(NSNumber*)[jo valueForKey:@"stepIdxDestination"] integerValue];
1058
+ float horizontalDistance = [(NSNumber*)[jo valueForKey:@"distance"] floatValue];
1059
+ float orientationChange = [(NSNumber*)[jo valueForKey:@"orientation"] floatValue];
1060
+ float verticalDistance = [(NSNumber*)[jo valueForKey:@"distanceToNextLevel"] floatValue];
1061
+ NSNumber* nextLevel = (NSNumber*)[jo valueForKey:@"nextLevel"];
1062
+ kSITIndicationActions action = stringToIndicationType([jo valueForKey:@"indicationType"]);
1063
+ kSITIndicationOrientation orientation = stringToOrientationType([jo valueForKey:@"orientationType"]);
1064
+
1065
+ SITIndication *indication = [[SITIndication alloc] initWithOriginStepIndex:stepIdxOrigin destinationStepIndex:stepIdxDestination action:action horizontalDistance:horizontalDistance orientation:orientation orientationChange:orientationChange verticalDistance:verticalDistance nextLevel:nextLevel];
1066
+
1067
+ return indication;
1068
+ }
1069
+
1070
+ // NavigationProgress
1071
+
1072
+ - (NSDictionary *) navigationProgressToJsonObject:(SITNavigationProgress *) navigationProgress {
1073
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
1074
+
1075
+ NSMutableArray *pointsJsonArray = [[NSMutableArray alloc] init];
1076
+ for(SITPoint* point in navigationProgress.points) {
1077
+ [pointsJsonArray addObject:[self pointToJsonObject: point]];
1078
+ }
1079
+
1080
+ NSMutableArray* segmentsJsonArray = [NSMutableArray new];
1081
+ for(SITRouteSegment* segment in navigationProgress.segments) {
1082
+ [segmentsJsonArray addObject: [self routeSegmentToJsonObject: segment]];
1083
+ }
1084
+
1085
+ [jo setObject: pointsJsonArray forKey: @"points"];
1086
+ [jo setObject: segmentsJsonArray forKey: @"segments"];
1087
+ [jo setObject:[self pointToJsonObject:navigationProgress.closestPointToRoute] forKey:@"closestPointInRoute"];
1088
+ [jo setObject:[NSNumber numberWithFloat:navigationProgress.distanceToClosestPointInRoute] forKey:@"distanceToClosestPointInRoute"];
1089
+ [jo setObject:[self indicationToJsonObject:navigationProgress.currentIndication] forKey:@"currentIndication"];
1090
+ [jo setObject:[self indicationToJsonObject:navigationProgress.nextIndication] forKey:@"nextIndication"];
1091
+ [jo setObject:[NSNumber numberWithInteger:navigationProgress.currentStepIndex] forKey:@"currentStepIndex"];
1092
+ [jo setObject:[NSNumber numberWithFloat:navigationProgress.distanceToGoal] forKey:@"distanceToGoal"];
1093
+ [jo setObject:[NSNumber numberWithFloat:navigationProgress.distanceToEndStep] forKey:@"distanceToEndStep"];
1094
+ [jo setObject:[NSNumber numberWithFloat:navigationProgress.timeToEndStep] forKey:@"timeToEndStep"];
1095
+ [jo setObject:[NSNumber numberWithFloat:navigationProgress.timeToGoal] forKey:@"timeToGoal"];
1096
+ [jo setObject:[self routeStepToJsonObject:navigationProgress.routeStep] forKey:@"routeStep"];
1097
+ [jo setObject:[self locationToJsonObject:navigationProgress.closestLocationInRoute] forKey:@"closestLocationInRoute"];
1098
+ return jo.copy;
1099
+ }
1100
+
1101
+ // check nil string
1102
+
1103
+ // Realtime
1104
+ - (SITRealTimeRequest *)realtimeRequestFromJson:(NSDictionary *)jo
1105
+ {
1106
+ SITRealTimeRequest *request = [[SITRealTimeRequest alloc] init];
1107
+
1108
+ NSDictionary *buildingJO = [jo valueForKey:@"building"];
1109
+
1110
+
1111
+ request.buildingIdentifier = [buildingJO valueForKey:@"identifier"];
1112
+ request.updateInterval = [[jo valueForKey:@"pollTime"] integerValue];
1113
+
1114
+ return request;
1115
+ }
1116
+
1117
+ - (NSDictionary *)jsonFromRealtimeData:(SITRealTimeData *)realtimeData
1118
+ {
1119
+ NSMutableDictionary *jo = [[NSMutableDictionary alloc] init];
1120
+
1121
+ NSMutableArray *locations = [[NSMutableArray alloc]init];
1122
+
1123
+ for (SITLocation *location in realtimeData.locations) {
1124
+ [locations addObject:[self locationToJsonObject:location]];
1125
+ }
1126
+
1127
+ [jo setObject:locations forKey:@"locations"];
1128
+
1129
+ return jo;
1130
+ }
1131
+
1132
+ @end