removed wrong contact points & added two authors
[platform/core/location/lbs-server.git] / lbs-server / src / lbs_server.c
1 /*
2  * lbs-server
3  *
4  * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <time.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <glib-object.h>
25
26 #include <vconf.h>
27 #include "setting.h"
28 #include <lbs_dbus_server.h>
29
30 #include "gps_plugin_data_types.h"
31 #include "lbs_server.h"
32
33 #include "nps_plugin_module.h"
34 #include "nps_plugin_intf.h"
35
36 #include "server.h"
37 #include "last_position.h"
38 #include "debug_util.h"
39 #include "dump_log.h"
40
41 #include "location-types.h"
42 #include "fused.h"
43
44 #define MOCK_LOCATION_CLEAR_VALUE 999
45 #define MOCK_RUNNING_OFF        LBS_SERVER_METHOD_SIZE
46 #define MAX_INTERVAL            120
47 #define MAX_BATCH_INTERVAL      255
48 #define MAX_BATCH_PERIOD        60000
49
50 typedef struct {
51         /* gps variables */
52         pos_data_t position;
53         batch_data_t batch;
54         sv_data_t satellite;
55         nmea_data_t nmea;
56         gboolean sv_used;
57         gboolean nmea_used;
58
59         gboolean is_gps_running;
60         gint gps_client_count;
61
62         /* nps variables */
63         NpsManagerHandle nps_handle;
64         unsigned long period;
65         NpsManagerPositionExt pos;
66         NpsManagerLastPositionExt last_pos;
67         Plugin_LocationInfo location;
68
69         gboolean is_nps_running;
70         gint nps_client_count;
71         unsigned char *token;
72
73         /* shared variables */
74         GMainLoop *loop;
75         GMutex mutex;
76         GCond cond;
77         LbsStatus status;
78
79         /* dynamic interval update */
80         GHashTable *dynamic_interval_table;
81         guint *optimized_interval;
82         guint temp_minimum_interval;
83         gboolean is_needed_changing_interval;
84 #ifndef TIZEN_DEVICE
85         GHashTable *batch_interval_table;
86         guint *optimized_batch_array;
87 #endif
88
89         lbs_server_dbus_h lbs_dbus_server;
90
91         /* mock variables */
92         gint is_mock_running;
93         gint mock_timer;
94         NpsManagerPositionExt mock_pos;
95         GVariant *mock_accuracy;
96
97         /* fused variables */
98         gint fused_high_count;
99         gint fused_balanced_count;
100         gboolean is_fused_running;
101         gint current_location_source;
102 } lbs_server_s;
103
104 typedef struct {
105         lbs_server_s *lbs_server;
106         int method;
107 } dynamic_interval_updator_user_data;
108
109 #ifndef TIZEN_DEVICE
110 typedef enum {
111         LBS_BATCH_INTERVAL = 0,
112         LBS_BATCH_PERIOD,
113         LBS_BATCH_SIZE,
114 } lbs_batch_interval;
115 #endif
116
117 typedef enum {
118         LOCATION_SOURCE_NONE = 0,
119         LOCATION_SOURCE_GPS,
120         LOCATION_SOURCE_WPS,
121         LOCATION_SOURCE_BOTH,
122 } lbs_current_location_source;
123
124 typedef enum {
125         _LBS_CLIENT_ADD = 0,
126         _LBS_CLIENT_REMOVE,
127         _LBS_CLIENT_REMOVE_ALL,
128 } lbs_client_count;
129
130 static gboolean gps_remove_all_clients(lbs_server_s *lbs_server);
131 static NpsManagerPositionExt g_mock_position;
132 static void set_mock_location_cb(gint method, gdouble latitude, gdouble longitude, gdouble altitude, gdouble speed, gdouble direction, gdouble accuracy, gpointer userdata);
133 static void mock_start_tracking(lbs_server_s *lbs_server);
134 static void mock_stop_tracking(lbs_server_s *lbs_server);
135 static void client_count_updater(lbs_server_s *lbs_server, lbs_server_method_e method, lbs_client_count type, gint fused_mode);
136
137
138 static void __setting_gps_cb(keynode_t *key, gpointer user_data)
139 {
140         LOG_GPS(DBG_LOW, "__setting_gps_cb");
141         lbs_server_s *lbs_server = (lbs_server_s *)user_data;
142         int onoff = 0;
143         gboolean ret = FALSE;
144
145         setting_get_int(VCONFKEY_LOCATION_ENABLED, &onoff);
146
147         if (onoff == 0) {
148                 ret = gps_remove_all_clients(lbs_server);
149
150                 if (ret == FALSE)
151                         LOG_GPS(DBG_LOW, "already removed.");
152         }
153 }
154
155 static void __setting_mock_cb(keynode_t *key, gpointer user_data)
156 {
157         LOG_GPS(DBG_LOW, "__setting_mock_cb");
158         lbs_server_s *lbs_server = (lbs_server_s *)user_data;
159         int onoff = 0;
160
161         setting_get_int(VCONFKEY_LOCATION_MOCK_ENABLED, &onoff);
162
163         if (onoff == 0) {
164                 mock_stop_tracking(lbs_server);
165                 setting_ignore_key_changed(VCONFKEY_LOCATION_MOCK_ENABLED, __setting_mock_cb);
166         }
167 }
168
169 static void nps_set_last_position(NpsManagerPositionExt pos)
170 {
171         LOG_NPS(DBG_LOW, "nps_set_last_position[%d]", pos.timestamp);
172
173         char location[128] = {0,};
174         snprintf(location, sizeof(location), "%.6lf;%.6lf;%.2lf;%.2lf;%.2lf;%.2lf;", pos.latitude, pos.longitude, pos.altitude, pos.speed, pos.direction, pos.hor_accuracy);
175
176         setting_set_int(VCONFKEY_LOCATION_NV_LAST_WPS_TIMESTAMP, pos.timestamp);
177         setting_set_string(VCONFKEY_LOCATION_NV_LAST_WPS_LOCATION, location);
178 }
179
180 static void nps_set_position(lbs_server_s *lbs_server, NpsManagerPositionExt pos)
181 {
182         LOG_NPS(DBG_LOW, "set position timestamp : %d", pos.timestamp);
183         lbs_server->last_pos.timestamp = pos.timestamp;
184         setting_set_int(VCONFKEY_LOCATION_LAST_WPS_TIMESTAMP, lbs_server->last_pos.timestamp);
185
186         if ((lbs_server->last_pos.latitude != pos.latitude) || (lbs_server->last_pos.longitude != pos.longitude)) {
187                 lbs_server->last_pos.latitude = pos.latitude;
188                 lbs_server->last_pos.longitude = pos.longitude;
189                 lbs_server->last_pos.altitude = pos.altitude;
190                 lbs_server->last_pos.hor_accuracy = pos.hor_accuracy;
191                 lbs_server->last_pos.speed = pos.speed;
192                 lbs_server->last_pos.direction = pos.direction;
193
194                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_LATITUDE, lbs_server->last_pos.latitude);
195                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_LONGITUDE, lbs_server->last_pos.longitude);
196                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_ALTITUDE, lbs_server->last_pos.altitude);
197                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_SPEED, lbs_server->last_pos.speed);
198                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_DIRECTION, lbs_server->last_pos.direction);
199                 setting_set_double(VCONFKEY_LOCATION_LAST_WPS_HOR_ACCURACY, lbs_server->last_pos.hor_accuracy);
200         }
201
202         int last_timestamp = 0;
203         setting_get_int(VCONFKEY_LOCATION_NV_LAST_WPS_TIMESTAMP, &last_timestamp);
204
205         LOG_NPS(DBG_LOW, "last_time stamp: %d, pos.timestamp: %d, UPDATE_INTERVAL: %d ", last_timestamp, pos.timestamp, UPDATE_INTERVAL);
206         if ((pos.timestamp - last_timestamp) > UPDATE_INTERVAL)
207                 nps_set_last_position(pos);
208 }
209
210 static void nps_set_status(lbs_server_s *lbs_server, LbsStatus status)
211 {
212         if (!lbs_server) {
213                 LOG_NPS(DBG_ERR, "lbs_server is NULL!!");
214                 return;
215         }
216         LOG_NPS(DBG_LOW, "Previous status: %d, Current status: %d", lbs_server->status, status);
217         if (lbs_server->status == status) {
218                 LOG_NPS(DBG_WARN, "Don't update NPS status");
219                 return;
220         }
221
222         lbs_server->status = status;
223
224         if (lbs_server->status == LBS_STATUS_AVAILABLE)
225                 setting_set_int(VCONFKEY_LOCATION_WPS_STATE, POSITION_CONNECTED);
226         else if (lbs_server->status == LBS_STATUS_ACQUIRING)
227                 setting_set_int(VCONFKEY_LOCATION_WPS_STATE, POSITION_SEARCHING);
228         else
229                 setting_set_int(VCONFKEY_LOCATION_WPS_STATE, POSITION_OFF);
230
231         if (status != LBS_STATUS_AVAILABLE)
232                 lbs_server->pos.fields = LBS_POSITION_FIELDS_NONE;
233
234         lbs_server_emit_status_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_NPS, status);
235 }
236
237 static void nps_update_position(lbs_server_s *lbs_server, NpsManagerPositionExt pos)
238 {
239         if (!lbs_server) {
240                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
241                 return;
242         }
243
244         if (lbs_server->is_mock_running != MOCK_RUNNING_OFF)
245                 return ;
246
247         GVariant *accuracy = NULL;
248
249         lbs_server->pos.fields = pos.fields;
250         lbs_server->pos.timestamp = pos.timestamp;
251         lbs_server->pos.latitude = pos.latitude;
252         lbs_server->pos.longitude = pos.longitude;
253         lbs_server->pos.altitude = pos.altitude;
254         lbs_server->pos.hor_accuracy = pos.hor_accuracy;
255         lbs_server->pos.ver_accuracy = pos.ver_accuracy;
256
257         accuracy = g_variant_ref_sink(g_variant_new("(idd)", lbs_server->pos.acc_level, lbs_server->pos.hor_accuracy, lbs_server->pos.ver_accuracy));
258
259         LOG_NPS(DBG_LOW, "time:%d", lbs_server->pos.timestamp);
260
261 #ifdef TIZEN_DEVICE
262         send_wps_position_to_fused_engine(pos.timestamp, pos.latitude, pos.longitude, pos.hor_accuracy, pos.ver_accuracy);
263 #endif
264
265         lbs_server_emit_position_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_NPS,
266                                         lbs_server->pos.fields, lbs_server->pos.timestamp, lbs_server->pos.latitude,
267                                         lbs_server->pos.longitude, lbs_server->pos.altitude, lbs_server->pos.speed,
268                                         lbs_server->pos.direction, 0.0, accuracy);
269
270         g_variant_unref(accuracy);
271 }
272
273 static gboolean nps_report_callback(gpointer user_data)
274 {
275         LOG_NPS(DBG_LOW, "ENTER >>>");
276         lbs_server_s *lbs_server = (lbs_server_s *)user_data;
277         if (!lbs_server) {
278                 LOG_NPS(DBG_ERR, "lbs_server is NULL!!");
279                 return FALSE;
280         }
281
282         double  vertical_accuracy = -1.0; /* vertical accuracy's invalid value is -1 */
283         time_t timestamp;
284         Plugin_LocationInfo location;
285
286         g_mutex_lock(&lbs_server->mutex);
287         memset(&location, 0x00, sizeof(Plugin_LocationInfo));
288         memcpy(&location, &lbs_server->location, sizeof(Plugin_LocationInfo));
289         g_mutex_unlock(&lbs_server->mutex);
290
291         time(&timestamp);
292         if (timestamp == lbs_server->last_pos.timestamp)
293                 return FALSE;
294
295         nps_set_status(lbs_server, LBS_STATUS_AVAILABLE);
296
297         NpsManagerPositionExt pos;
298         memset(&pos, 0x00, sizeof(NpsManagerPositionExt));
299
300         pos.timestamp = timestamp;
301
302         if (location.latitude) {
303                 pos.fields |= LBS_POSITION_EXT_FIELDS_LATITUDE;
304                 pos.latitude = location.latitude;
305         }
306
307         if (location.longitude) {
308                 pos.fields |= LBS_POSITION_EXT_FIELDS_LONGITUDE;
309                 pos.longitude = location.longitude;
310         }
311
312         if (location.altitude) {
313                 pos.fields |= LBS_POSITION_EXT_FIELDS_ALTITUDE;
314                 pos.altitude = location.altitude;
315         }
316
317         if (location.speed >= 0) {
318                 pos.fields |= LBS_POSITION_EXT_FIELDS_SPEED;
319                 pos.speed = location.speed;
320         }
321         if (location.bearing >= 0) {
322                 pos.fields |= LBS_POSITION_EXT_FIELDS_DIRECTION;
323                 pos.direction = location.bearing;
324         }
325
326         pos.acc_level = LBS_ACCURACY_LEVEL_STREET;
327         pos.hor_accuracy = location.hpe;
328         pos.ver_accuracy = vertical_accuracy;
329
330         nps_update_position(lbs_server, pos);
331
332         nps_set_position(lbs_server, pos);
333
334         return FALSE;
335 }
336
337 static void __nps_callback(void *arg, const Plugin_LocationInfo *location, const void *reserved)
338 {
339         LOG_NPS(DBG_LOW, "ENTER >>>");
340         lbs_server_s *lbs_server = (lbs_server_s *)arg;
341         if (!lbs_server) {
342                 LOG_NPS(DBG_ERR, "lbs_server is NULL!!");
343                 return;
344         }
345
346         if (!location) {
347                 LOG_NPS(DBG_LOW, "NULL is returned from plugin...");
348                 nps_set_status(lbs_server, LBS_STATUS_ACQUIRING);
349                 return;
350         }
351
352         g_mutex_lock(&lbs_server->mutex);
353         memcpy(&lbs_server->location, location, sizeof(Plugin_LocationInfo));
354         g_mutex_unlock(&lbs_server->mutex);
355
356         g_main_context_invoke(NULL, nps_report_callback, arg);
357 }
358
359 static void _nps_token_callback(void *arg, const unsigned char *token, unsigned tokenSize)
360 {
361         LOG_NPS(DBG_LOW, "ENTER >>>");
362         lbs_server_s *lbs_server = (lbs_server_s *)arg;
363         if (NULL == lbs_server) {
364                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
365                 return;
366         }
367
368         if (token == NULL) {
369                 LOG_NPS(DBG_ERR, "*** no token to save\n");
370         } else {
371                 /* save the token in persistent storage */
372                 g_mutex_lock(&lbs_server->mutex);
373                 lbs_server->token = g_new0(unsigned char, tokenSize);
374
375                 if (lbs_server->token)
376                         memcpy(lbs_server->token, token, tokenSize);
377
378                 g_mutex_unlock(&lbs_server->mutex);
379         }
380         LOG_NPS(DBG_LOW, "_nps_token_callback ended");
381 }
382
383 #if 0 /* Not needed */
384 static void _network_enabled_cb(keynode_t *key, void *user_data)
385 {
386         LOG_GPS(DBG_LOW, "ENTER >>>");
387         int enabled = 0;
388
389         setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED, &enabled);
390
391         /* This is vestige of nps-server
392         lbs_server_s *lbs_server = (lbs_server_s *)user_data;
393
394         if (enabled == 0) {
395                 if (lbs_server->loop != NULL) {
396                         g_main_loop_quit(lbs_server->loop);
397                 }
398         }
399         */
400 }
401 #endif
402
403 static gboolean nps_offline_location(lbs_server_s *lbs_server)
404 {
405         LOG_NPS(DBG_LOW, "ENTER >>>");
406         if (lbs_server == NULL) {
407                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
408                 return FALSE;
409         }
410         char key[NPS_UNIQUE_ID_LEN] = { 0, };
411
412         if (setting_get_unique_id(key)) {
413                 LOG_NPS(DBG_LOW, "key = %s", key);
414                 get_nps_plugin_module()->getOfflineToken((unsigned char *)key, NPS_UNIQUE_ID_LEN,
415                                 _nps_token_callback, lbs_server);
416                 if (lbs_server->token != NULL) {
417                         LOG_NPS(DBG_LOW, "Token = %s", lbs_server->token);
418                         int ret = get_nps_plugin_module()->offlineLocation((unsigned char *)key,
419                                         NPS_UNIQUE_ID_LEN, lbs_server->token, 0,
420                                         __nps_callback, lbs_server);
421                         if (ret) {
422                                 if (lbs_server->is_nps_running) {
423                                         LOG_NPS(DBG_LOW, "offlineLocation() called nps_callback successfully.");
424                                         return TRUE;
425                                 }
426                         }
427                 } else {
428                         LOG_NPS(DBG_ERR, "getOfflineToken(): Token is NULL");
429                 }
430         } else {
431                 LOG_NPS(DBG_ERR, "lbs_get_unique_id() failed.");
432         }
433         return TRUE;
434 }
435
436 static void __nps_cancel_callback(void *arg)
437 {
438         LOG_NPS(DBG_LOW, "__nps_cancel_callback");
439         lbs_server_s *lbs_server = (lbs_server_s *) arg;
440         if (!lbs_server) {
441                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
442                 return;
443         }
444
445         g_mutex_lock(&lbs_server->mutex);
446         lbs_server->is_nps_running = FALSE;
447         g_cond_signal(&lbs_server->cond);
448         g_mutex_unlock(&lbs_server->mutex);
449 }
450
451 static gboolean location_source_selector(lbs_server_s *lbs_server, gint fused_mode);
452 static void plugin_status_controller(lbs_server_s *lbs_server);
453
454 static void start_tracking(lbs_server_s *lbs_server, lbs_server_method_e method, gint fused_mode)
455 {
456         LOG_GPS(DBG_LOW, ">>> start_tracking");
457
458         switch (method) {
459         case LBS_SERVER_METHOD_GPS:
460                 client_count_updater(lbs_server, LBS_SERVER_METHOD_GPS, _LBS_CLIENT_ADD, fused_mode);
461
462                 if (lbs_server->is_mock_running != MOCK_RUNNING_OFF && lbs_server->is_gps_running == FALSE && lbs_server->is_nps_running == FALSE)
463                         mock_start_tracking(lbs_server);
464
465                 if (location_source_selector(lbs_server, fused_mode) == TRUE) {
466                         plugin_status_controller(lbs_server);
467                 }
468                 break;
469
470         case LBS_SERVER_METHOD_NPS:
471                 client_count_updater(lbs_server, LBS_SERVER_METHOD_NPS, _LBS_CLIENT_ADD, fused_mode);
472
473                 if (lbs_server->is_mock_running != MOCK_RUNNING_OFF && lbs_server->is_gps_running == FALSE && lbs_server->is_nps_running == FALSE)
474                         mock_start_tracking(lbs_server);
475
476                 if (location_source_selector(lbs_server, fused_mode) == TRUE) {
477                         plugin_status_controller(lbs_server);
478                 }
479
480                 if (nps_is_dummy_plugin_module() != TRUE)
481                         nps_offline_location(lbs_server);
482
483                 LOG_NPS(DBG_ERR, "Failed to start NPS");
484                 nps_set_status(lbs_server, LBS_STATUS_ERROR);
485                 break;
486
487         case LBS_SERVER_METHOD_PASSIVE:
488                 break;
489
490         default:
491                 LOG_GPS(DBG_LOW, "start_tracking Invalid");
492                 break;
493         }
494
495 }
496
497 static gboolean nps_plugin_stop(lbs_server_s *lbs_server)
498 {
499         LOG_FUNC;
500         if (!lbs_server) {
501                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
502                 return FALSE;
503         }
504
505         int ret = get_nps_plugin_module()->stop(lbs_server->nps_handle, __nps_cancel_callback, lbs_server);
506         if (ret) {
507                 g_mutex_lock(&lbs_server->mutex);
508
509                 while (lbs_server->is_nps_running)
510                         g_cond_wait(&lbs_server->cond, &lbs_server->mutex);
511
512                 lbs_server->is_nps_running = FALSE;
513                 g_mutex_unlock(&lbs_server->mutex);
514         }
515         /* This is vestige of nps-server
516         else {
517                 if (lbs_server->loop != NULL) {
518                         LOG_NPS(DBG_ERR, "module->stop() is failed. nps is cloesed.");
519                         g_main_loop_quit(lbs_server->loop);
520                         return FALSE;
521                 }
522         }
523         */
524
525         nps_set_status(lbs_server, LBS_STATUS_UNAVAILABLE);
526
527         return TRUE;
528 }
529
530 static void stop_tracking(lbs_server_s *lbs_server, lbs_server_method_e method, gint fused_mode)
531 {
532         LOG_FUNC;
533         switch (method) {
534         case LBS_SERVER_METHOD_GPS:
535                 LOG_GPS(DBG_LOW, "stop_tracking GPS [client: %d]", lbs_server->gps_client_count);
536
537                 if (lbs_server->is_mock_running == MOCK_RUNNING_OFF)
538                         gps_set_last_position(&lbs_server->position);
539
540                 client_count_updater(lbs_server, LBS_SERVER_METHOD_GPS, _LBS_CLIENT_REMOVE, fused_mode);
541
542                 if (location_source_selector(lbs_server, fused_mode) == TRUE) {
543                         plugin_status_controller(lbs_server);
544                 }
545
546                 if (lbs_server->is_gps_running == FALSE) {
547                         lbs_server->status = LBS_STATUS_UNAVAILABLE;
548                         lbs_server_emit_status_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_GPS, LBS_STATUS_UNAVAILABLE);
549                 }
550
551                 break;
552         case LBS_SERVER_METHOD_NPS:
553                 LOG_NPS(DBG_LOW, "_stop_tracking NPS");
554
555                 client_count_updater(lbs_server, LBS_SERVER_METHOD_NPS, _LBS_CLIENT_REMOVE, fused_mode);
556
557                 if (location_source_selector(lbs_server, fused_mode) == TRUE) {
558                         plugin_status_controller(lbs_server);
559                 }
560                 break;
561
562         case LBS_SERVER_METHOD_PASSIVE:
563                 break;
564
565         default:
566                 LOG_GPS(DBG_LOW, "stop_tracking Invalid");
567                 break;
568         }
569 }
570
571 static gboolean _set_current_location_source(lbs_server_s *lbs_server, gint mode)
572 {
573         if (lbs_server->current_location_source != mode) {
574                 LOG_GPS(DBG_LOW, "location source changed[%d]", mode);
575                 lbs_server->current_location_source = mode;
576                 return TRUE;
577         }
578         return FALSE;
579 }
580
581 static gboolean location_source_selector(lbs_server_s *lbs_server, gint fused_mode)
582 {
583         LOG_FUSED_FUNC;
584         if (lbs_server == NULL) {
585                 LOG_GPS(DBG_LOW, "lbs_server is null");
586                 return FALSE;
587         }
588
589         /* set fused running status */
590         if (fused_mode == LOCATION_FUSED_HIGH || fused_mode == LOCATION_FUSED_BALANCED) {
591                 if (lbs_server->fused_high_count == 0 && lbs_server->fused_balanced_count == 0) {
592                         LOG_GPS(DBG_LOW, "-- Checking to stop fused mode");
593                         if (lbs_server->is_fused_running) {
594                                 g_mutex_lock(&lbs_server->mutex);
595                                 lbs_server->is_fused_running = FALSE;
596                                 g_mutex_unlock(&lbs_server->mutex);
597
598                                 location_fused_stop();
599                         }
600                 } else {
601                         LOG_GPS(DBG_LOW, "-- Checking to start fused mode");
602                         if (lbs_server->is_fused_running == FALSE) {
603                                 g_mutex_lock(&lbs_server->mutex);
604                                 lbs_server->is_fused_running = TRUE;
605                                 g_mutex_unlock(&lbs_server->mutex);
606
607                                 location_fused_start();
608                         }
609                 }
610
611 #if 0
612                 /* set fused_optimized_mode */
613                 if (lbs_server->fused_high_count == 0 || lbs_server->fused_balanced_count == 0)
614                         lbs_server->fused_optimized_mode = LOCATION_FUSED_NONE;
615                 else if (lbs_server->fused_high_count > 0)
616                         lbs_server->fused_optimized_mode = LOCATION_FUSED_HIGH;
617                 else if (lbs_server->fused_high_count == 0 && lbs_server->fused_balanced_count > 0)
618                         lbs_server->fused_optimized_mode = LOCATION_FUSED_BALANCED;
619                 else
620                         lbs_server->fused_optimized_mode = LOCATION_FUSED_NONE;
621
622                 LOG_GPS(DBG_LOW, "---- fused_optimized_mode [high: %d, balanced: %d, mode: %d]",
623                         lbs_server->fused_high_count, lbs_server->fused_balanced_count, lbs_server->fused_optimized_mode);
624 #endif
625         }
626
627         /* Define all condition to select optimized location source
628                 gps, high ==>     1(gps0, high0) 2(gps3, high0) 3(gps3, high1) 4(gps3, high3)
629                 wps, balance ==>  A(wps0, bal0)  B(wps3, bal0)  C(wps3, bal1)  D(wps3, bal3)
630
631                 LOCATION_SOURCE_GPS  : 2A, 2D, 3A, 3D, 4A, 4D
632                 LOCATION_SOURCE_WPS  : 1B, 1C, 1D
633                 LOCATION_SOURCE_BOTH : 2B, 2C, 3B, 2C, 4B, 4C
634                 LOCATION_SOURCE_NONE : 1A
635         */
636
637         gint pure_wps_count = lbs_server->nps_client_count - lbs_server->fused_balanced_count;
638
639         if (lbs_server->gps_client_count > 0) {         /* case 2, 3, 4 */
640
641                 if (lbs_server->nps_client_count > 0) {
642                         if (pure_wps_count > 0) {                       /* 2B, 2C, 3B, 3C, 4B, 4C */
643                                 if (_set_current_location_source(lbs_server, LOCATION_SOURCE_BOTH) == TRUE) return TRUE;
644                         } else {                                                        /* 2D, 3D, 4D */
645                                 if (_set_current_location_source(lbs_server, LOCATION_SOURCE_GPS) == TRUE) return TRUE;
646                         }
647                 } else {                                                                /* 2A, 3A, 4A */
648                         if (_set_current_location_source(lbs_server, LOCATION_SOURCE_GPS) == TRUE) return TRUE;
649                 }
650
651         } else {                                                                        /* case 1*/
652                 if (lbs_server->nps_client_count > 0) { /* 1B, 1C, 1D */
653                         if (_set_current_location_source(lbs_server, LOCATION_SOURCE_WPS) == TRUE) return TRUE;
654                 } else {                                                                /* 1A */
655                         if (_set_current_location_source(lbs_server, LOCATION_SOURCE_NONE) == TRUE) return TRUE;
656                 }
657         }
658
659         return FALSE;
660 }
661
662
663 static gboolean gps_plugin_start(lbs_server_s *lbs_server)
664 {
665         LOG_FUNC;
666         if (!lbs_server) {
667                 LOG_GPS(DBG_ERR, "lbs-server is NULL!!");
668                 return FALSE;
669         }
670
671         lbs_server->status = LBS_STATUS_ACQUIRING;
672
673         if (request_start_session((int)(lbs_server->optimized_interval[LBS_SERVER_METHOD_GPS])) == TRUE) {
674                 g_mutex_lock(&lbs_server->mutex);
675                 lbs_server->is_gps_running = TRUE;
676                 g_mutex_unlock(&lbs_server->mutex);
677
678                 lbs_server->is_needed_changing_interval = FALSE;
679                 setting_notify_key_changed(VCONFKEY_LOCATION_ENABLED, __setting_gps_cb, lbs_server);
680         } else {
681                 LOG_GPS(DBG_ERR, "Failed to request_start_session");
682         }
683         return TRUE;
684 }
685
686 static gboolean gps_plugin_stop(lbs_server_s *lbs_server)
687 {
688         LOG_FUNC;
689         if (!lbs_server) {
690                 LOG_GPS(DBG_ERR, "lbs-server is NULL!!");
691                 return FALSE;
692         }
693
694         if (request_stop_session() == TRUE) {
695                 lbs_server->is_gps_running = FALSE;
696                 lbs_server->sv_used = FALSE;
697                 setting_ignore_key_changed(VCONFKEY_LOCATION_ENABLED, __setting_gps_cb);
698         }
699         return TRUE;
700 }
701
702 static gboolean nps_plugin_start(lbs_server_s *lbs_server)
703 {
704         LOG_FUNC;
705         if (!lbs_server) {
706                 LOG_NPS(DBG_ERR, "lbs-server is NULL!!");
707                 return FALSE;
708         }
709
710         LOG_NPS(DBG_LOW, "_nps_plugin_start LBS_SERVER_METHOD_NPS");
711         nps_set_status(lbs_server, LBS_STATUS_ACQUIRING);
712
713         void *handle_str = NULL;
714         int ret = get_nps_plugin_module()->start(lbs_server->period, __nps_callback, lbs_server, &(handle_str));
715         LOG_NPS(DBG_LOW, "after get_nps_plugin_module()->location");
716
717         if (ret) {
718                 LOG_NPS(DBG_LOW, "get_nps_plugin_module()->start()  success, ret[%d]", ret);
719                 lbs_server->nps_handle = handle_str;
720                 g_mutex_lock(&lbs_server->mutex);
721                 lbs_server->is_nps_running = TRUE;
722                 g_mutex_unlock(&lbs_server->mutex);
723
724                 /* calling key_changed API was comment out.
725                 vconf_ignore_key_changed(VCONFKEY_LOCATION_NETWORK_ENABLED, _network_enabled_cb);
726                 */
727                 return TRUE;
728         }
729
730         return FALSE;
731 }
732
733 static void plugin_status_controller(lbs_server_s *lbs_server)
734 {
735         LOG_FUNC;
736         if (lbs_server->current_location_source == LOCATION_SOURCE_GPS) {
737                 LOG_FUSED(DBG_LOW, ">>>  --- LOCATION_SOURCE_GPS");
738                 if (lbs_server->is_gps_running == FALSE) {
739                         gps_plugin_start(lbs_server);
740                 }
741                 if (lbs_server->is_nps_running) {
742                         LOG_FUSED(DBG_LOW, ">>> WPS stopped from Location source controller !!!");
743                         nps_plugin_stop(lbs_server);
744                 }
745         } else if (lbs_server->current_location_source == LOCATION_SOURCE_WPS) {
746                 LOG_FUSED(DBG_LOW, ">>>  --- LOCATION_SOURCE_WPS");
747                 if (lbs_server->is_gps_running) {
748                         LOG_FUSED(DBG_LOW, ">>> GPS stopped from Location source controller !!!");
749                         gps_plugin_stop(lbs_server);
750                 }
751                 if (lbs_server->is_nps_running == FALSE) {
752                         LOG_FUSED(DBG_LOW, ">>> WPS started from Location source controller !!!");
753                         nps_plugin_start(lbs_server);
754                 }
755         } else if (lbs_server->current_location_source == LOCATION_SOURCE_BOTH) {
756                 LOG_FUSED(DBG_LOW, ">>>  --- LOCATION_SOURCE_BOTH");
757                 if (lbs_server->is_gps_running == FALSE) {
758                         LOG_FUSED(DBG_LOW, ">>> GPS stopped from Location source controller !!!");
759                         gps_plugin_start(lbs_server);
760                 }
761                 if (lbs_server->is_nps_running == FALSE) {
762                         LOG_FUSED(DBG_LOW, ">>> WPS started from Location source controller !!!");
763                         nps_plugin_start(lbs_server);
764                 }
765         } else if (lbs_server->current_location_source == LOCATION_SOURCE_NONE) {
766                 LOG_FUSED(DBG_LOW, ">>>  --- LOCATION_SOURCE_NONE");
767                 if (lbs_server->is_gps_running) {
768                         LOG_FUSED(DBG_LOW, ">>> GPS stopped from Location source controller !!!");
769                         gps_plugin_stop(lbs_server);
770                 }
771                 if (lbs_server->is_nps_running) {
772                         LOG_FUSED(DBG_LOW, ">>> WPS stopped from Location source controller !!!");
773                         nps_plugin_stop(lbs_server);
774                 }
775         }
776 }
777
778 /*
779 *  manipulate the dynamic_interval_table.
780 */
781
782 static void find_min_interval_foreach_cb(gpointer key, gpointer value, gpointer userdata)
783 {
784         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
785         guint interval = GPOINTER_TO_UINT(key);
786         LOG_GPS(DBG_LOW, "list : interval [%u], count [%u]", interval, GPOINTER_TO_UINT(value));
787         if (lbs_server->temp_minimum_interval > interval)
788                 lbs_server->temp_minimum_interval = interval;
789 }
790
791 static void update_dynamic_interval_table_foreach_cb(gpointer key, gpointer value, gpointer userdata)
792 {
793         GHashTable *interval_table = (GHashTable *) value;
794         dynamic_interval_updator_user_data *updator_ud = (dynamic_interval_updator_user_data *)userdata;
795         lbs_server_s *lbs_server = updator_ud->lbs_server;
796
797         g_hash_table_foreach(interval_table, (GHFunc) find_min_interval_foreach_cb, (gpointer) lbs_server);
798         LOG_GPS(DBG_LOW, "foreach_cb, client:[%s] temp_min[%u], hash_size[%u]", (char *)key, lbs_server->temp_minimum_interval, g_hash_table_size(interval_table));
799 }
800
801 static void __add_interval_table(GHashTable *interval_table, guint interval)
802 {
803         gpointer *value = (gpointer *) g_hash_table_lookup(interval_table, GUINT_TO_POINTER(interval));
804         if (value) {
805                 guint count = GPOINTER_TO_UINT(value);
806                 g_hash_table_insert(interval_table, GUINT_TO_POINTER(interval), GUINT_TO_POINTER(count + 1));
807         } else {
808                 g_hash_table_insert(interval_table, GUINT_TO_POINTER(interval), GUINT_TO_POINTER(1));
809         }
810 }
811
812 static void __remove_interval_table(GHashTable *interval_table, guint interval)
813 {
814         gpointer *value = (gpointer *) g_hash_table_lookup(interval_table, GUINT_TO_POINTER(interval));
815         if (value) {
816                 guint count = GPOINTER_TO_UINT(value);
817                 if (count == 1) {
818                         if (g_hash_table_remove(interval_table, GUINT_TO_POINTER(interval)) != TRUE)
819                                 LOG_GPS(DBG_LOW, "Remove interval[%u] failed from g_hash_table", interval);
820                 } else {
821                         g_hash_table_insert(interval_table, GUINT_TO_POINTER(interval), GUINT_TO_POINTER(count - 1));
822                 }
823         } else {
824                 LOG_GPS(DBG_LOW, "Remove interval : lookup result is null");
825         }
826 }
827
828 static void __update_interval_table(GHashTable *interval_table, guint interval, guint prev_interval)
829 {
830         LOG_GPS(DBG_LOW, "Update interval [%u -> %u]", prev_interval, interval);
831         __remove_interval_table(interval_table, prev_interval);
832         __add_interval_table(interval_table, interval);
833 }
834
835 static gboolean update_pos_tracking_interval(lbs_server_interval_manipulation_type type, const gchar *client, int method, guint interval, guint prev_interval, gpointer userdata)
836 {
837         LOG_GPS(DBG_LOW, ">>> update_pos_tracking_interval");
838         if (userdata == NULL) return FALSE;
839         if (client == NULL) {
840                 LOG_GPS(DBG_ERR, "client is NULL");
841                 return FALSE;
842         }
843
844         if (method != LBS_SERVER_METHOD_GPS)
845                 return FALSE;
846
847         gboolean ret_val = FALSE;
848         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
849
850         /* manipulate logic for dynamic-interval hash table */
851         switch (type) {
852                 case LBS_SERVER_INTERVAL_ADD: {
853                         gchar *client_cpy = NULL;
854                         client_cpy = g_strdup(client);
855
856                         GHashTable *interval_table = (GHashTable *) g_hash_table_lookup(lbs_server->dynamic_interval_table, client_cpy);
857                         LOG_GPS(DBG_LOW, "ADD, interval[%u], client[%s], interval_table(%p)", interval, client, interval_table);
858                         if (interval_table) {
859                                 __add_interval_table(interval_table, interval);
860                                 g_free(client_cpy);
861                         } else {
862                                 LOG_GPS(DBG_LOW, "create gps hash_table to add first key[%s]", client);
863                                 interval_table = g_hash_table_new(g_direct_hash, g_direct_equal);
864                                 g_hash_table_insert(interval_table, GUINT_TO_POINTER(interval), GUINT_TO_POINTER(1));
865                                 g_hash_table_insert(lbs_server->dynamic_interval_table, (gpointer) client_cpy, (gpointer) interval_table);
866                         }
867
868                         LOG_GPS(DBG_LOW, "ADD, done");
869                         break;
870                 }
871
872                 case LBS_SERVER_INTERVAL_REMOVE: {
873                         GHashTable *interval_table = (GHashTable *) g_hash_table_lookup(lbs_server->dynamic_interval_table, client);
874                         LOG_GPS(DBG_LOW, "REMOVE, interval[%u, %u] , client[%s], interval_table(%p)", interval, prev_interval, client, interval_table);
875                         if (interval_table) {
876                                 if ((interval == 0) && (prev_interval == 0)) {
877                                         LOG_GPS(DBG_INFO, "client[%s] removed by force.", client);
878                                         g_hash_table_remove_all(interval_table);
879                                         g_hash_table_destroy(interval_table);
880                                         if (g_hash_table_contains(lbs_server->dynamic_interval_table, client)) {
881                                                 if (g_hash_table_remove(lbs_server->dynamic_interval_table, client) != TRUE)
882                                                         LOG_GPS(DBG_LOW, "g_hash_table_remove is failed.");
883                                         }
884                                         break;
885                                 } else {
886                                         __remove_interval_table(interval_table, interval);
887                                 }
888                         } else {
889                                 LOG_GPS(DBG_INFO, "Client[%s] Method[%d] is already removed from interval-table", client, method);
890                                 break;
891                         }
892
893                         if (g_hash_table_size(interval_table) == 0) {
894                                 LOG_GPS(DBG_LOW, "Remove client[%s] from dynamic_interval_table", client);
895                                 g_hash_table_destroy(interval_table);
896                                 if (g_hash_table_contains(lbs_server->dynamic_interval_table, client)) {
897                                         if (g_hash_table_remove(lbs_server->dynamic_interval_table, client) != TRUE)
898                                                 LOG_GPS(DBG_LOW, "g_hash_table_remove is failed.");
899                                 }
900                         }
901
902                         LOG_GPS(DBG_LOW, "REMOVE, done.");
903
904                         break;
905                 }
906
907                 case LBS_SERVER_INTERVAL_UPDATE: {
908                         GHashTable *interval_table = (GHashTable *) g_hash_table_lookup(lbs_server->dynamic_interval_table, client);
909                         LOG_GPS(DBG_LOW, "UPDATE, interval[%u -> %u], client[%s], interval_table(%p)", prev_interval, interval, client, interval_table);
910                         if (interval_table) {
911                                 __update_interval_table(interval_table, interval, prev_interval);
912                         } else {
913                                 LOG_GPS(DBG_LOW, "Client[%s] is not exist in interval-table", client);
914                                 break;
915                         }
916                         LOG_GPS(DBG_LOW, "UPDATE, done.");
917                         break;
918                 }
919
920                 default: {
921                         LOG_GPS(DBG_ERR, "unhandled interval-update type");
922                         return FALSE;
923                 }
924         }
925
926         /* update logic for optimized-interval value */
927         if (g_hash_table_size(lbs_server->dynamic_interval_table) == 0) {
928                 LOG_GPS(DBG_LOW, "dynamic_interval_table size is zero. It will be updated all value as 0");
929                 lbs_server->is_needed_changing_interval = FALSE;
930                 int i = 0;
931                 for (i = 0; i < LBS_SERVER_METHOD_SIZE; i++)
932                         lbs_server->optimized_interval[i] = 0;
933
934                 ret_val = FALSE;
935         } else {
936                 LOG_GPS(DBG_LOW, "update dynamic_interval_table");
937                 dynamic_interval_updator_user_data updator_user_data;
938                 updator_user_data.lbs_server = lbs_server;
939                 updator_user_data.method = method;
940
941                 lbs_server->temp_minimum_interval = MAX_INTERVAL;
942                 g_hash_table_foreach(lbs_server->dynamic_interval_table, (GHFunc) update_dynamic_interval_table_foreach_cb, (gpointer) &updator_user_data);
943
944                 if (lbs_server->optimized_interval[method] != lbs_server->temp_minimum_interval) {
945                         LOG_GPS(DBG_INFO, "Changing method[GPS]'s optimized_interval value %u -> [ %u ]",
946                                         lbs_server->optimized_interval[method], lbs_server->temp_minimum_interval);
947                         lbs_server->optimized_interval[method] = lbs_server->temp_minimum_interval;
948
949                         /* need to send message to provider device */
950                         LOG_GPS(DBG_LOW, "--> set needed_changing_interval");
951                         lbs_server->is_needed_changing_interval = TRUE;
952                 }
953
954                 if (lbs_server->is_needed_changing_interval)
955                         ret_val = TRUE;
956                 else
957                         ret_val = FALSE;
958         }
959         return ret_val;
960 }
961
962 static void request_change_pos_update_interval(int method, gpointer userdata)
963 {
964         LOG_GPS(DBG_LOW, "ENTER >>>");
965         if (!userdata) return;
966
967         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
968         switch (method) {
969         case LBS_SERVER_METHOD_GPS:
970                 request_change_pos_update_interval_standalone_gps(lbs_server->optimized_interval[method]);
971                 break;
972         default:
973                 break;
974         }
975 }
976
977 static void get_nmea(int *timestamp, gchar **nmea_data, gpointer userdata)
978 {
979         LOG_GPS(DBG_LOW, "ENTER >>>");
980         if (!userdata) return;
981
982         get_nmea_from_server(timestamp, nmea_data);
983
984         LOG_GPS(DBG_LOW, "timestmap: %d, nmea_data: %s", *timestamp, *nmea_data);
985 }
986
987 #ifndef TIZEN_DEVICE
988 static gboolean update_batch_tracking_interval(lbs_server_interval_manipulation_type type, const gchar *client, guint interval, guint period, gpointer userdata);
989 static void start_batch_tracking(lbs_server_s *lbs_server, int batch_interval, int batch_period);
990 static void stop_batch_tracking(lbs_server_s *lbs_server, int batch_interval, int batch_period);
991 #endif
992
993 static void set_options(GVariant *options, const gchar *client, gpointer userdata)
994 {
995         LOG_GPS(DBG_LOW, "ENTER >>>");
996         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
997
998         GVariantIter iter;
999         gchar *key = NULL;
1000         GVariant *value = NULL;
1001         gboolean ret = FALSE;
1002 #ifndef _TIZEN_PUBLIC_
1003         char *msg_header = NULL;
1004         char *msg_body = NULL;
1005         int size = 0;
1006 #endif
1007         gsize length = 0;
1008         char *option = NULL;
1009         char *app_id = NULL;
1010         guint interval = 0;
1011         guint prev_interval = 0;
1012         gint fused_mode = 0;
1013
1014         lbs_server_method_e method = 0;
1015
1016         g_variant_iter_init(&iter, options);
1017         ret = g_variant_iter_next(&iter, "{&sv}", &key, &value);
1018         if (ret == FALSE) {
1019                 LOG_GPS(DBG_ERR, "Invalid GVariant");
1020                 return;
1021         }
1022         if (!g_strcmp0(key, "CMD")) {
1023                 LOG_GPS(DBG_LOW, "set_options [%s]", g_variant_get_string(value, &length));
1024                 if (!g_strcmp0(g_variant_get_string(value, &length), "START")) {
1025
1026                         while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
1027                                 if (!g_strcmp0(key, "METHOD"))
1028                                         method = g_variant_get_int32(value);
1029                                 else if (!g_strcmp0(key, "INTERVAL"))
1030                                         interval = g_variant_get_uint32(value);
1031                                 else if (!g_strcmp0(key, "APP_ID"))
1032                                         app_id = g_variant_dup_string(value, &length);
1033                                 else if (!g_strcmp0(key, "FUSED_MODE"))
1034                                         fused_mode = g_variant_get_int32(value);
1035                         }
1036                         LOG_GPS(DBG_LOW, "METHOD [%d], INTERVAL [%u], APP_ID [%s]", method, interval, app_id);
1037
1038                         if (client) {
1039                                 LOG_GPS(DBG_LOW, "update_pos_tracking_interval -> START");
1040                                 update_pos_tracking_interval(LBS_SERVER_INTERVAL_ADD, client, method, interval, 0, lbs_server);
1041                         }
1042
1043                         if (app_id) {
1044                                 if (LBS_SERVER_METHOD_GPS == method)
1045                                         gps_dump_log("START GPS", app_id);
1046
1047                                 free(app_id);
1048                         }
1049
1050                         start_tracking(lbs_server, method, fused_mode);
1051
1052                         if (lbs_server->is_needed_changing_interval) {
1053                                 lbs_server->is_needed_changing_interval = FALSE;
1054                                 request_change_pos_update_interval(method, (gpointer)lbs_server);
1055                         }
1056                 }
1057                 else if (!g_strcmp0(g_variant_get_string(value, &length), "STOP")) {
1058                         while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
1059                                 if (!g_strcmp0(key, "METHOD"))
1060                                         method = g_variant_get_int32(value);
1061                                 else if (!g_strcmp0(key, "INTERVAL"))
1062                                         interval = g_variant_get_uint32(value);
1063                                 else if (!g_strcmp0(key, "APP_ID"))
1064                                         app_id = g_variant_dup_string(value, &length);
1065                                 else if (!g_strcmp0(key, "FUSED_MODE"))
1066                                         fused_mode = g_variant_get_int32(value);
1067                         }
1068                         LOG_GPS(DBG_LOW, "METHOD [%d], INTERVAL [%u], APP_ID [%s]", method, interval, app_id);
1069
1070                         if (client) {
1071                                 LOG_GPS(DBG_LOW, "update_pos_tracking_interval -> STOP");
1072                                 update_pos_tracking_interval(LBS_SERVER_INTERVAL_REMOVE, client, method, interval, 0, lbs_server);
1073                         }
1074
1075                         if (app_id) {
1076                                 if (LBS_SERVER_METHOD_GPS == method)
1077                                         gps_dump_log("STOP GPS", app_id);
1078
1079                                 free(app_id);
1080                         }
1081
1082                         stop_tracking(lbs_server, method, fused_mode);
1083
1084                         if (lbs_server->is_needed_changing_interval) {
1085                                 lbs_server->is_needed_changing_interval = FALSE;
1086                                 request_change_pos_update_interval(method, (gpointer)lbs_server);
1087                         }
1088                 }
1089 #ifndef TIZEN_DEVICE
1090                 else if (!g_strcmp0(g_variant_get_string(value, &length), "START_BATCH")) {
1091
1092                         gint b_interval = 0, b_period = 0;
1093                         while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
1094
1095                                 if (!g_strcmp0(key, "BATCH_INTERVAL"))
1096                                         b_interval = g_variant_get_int32(value);
1097                                 else if (!g_strcmp0(key, "BATCH_PERIOD"))
1098                                         b_period = g_variant_get_int32(value);
1099                         }
1100                         LOG_GPS(DBG_LOW, "BATCH_INTERVAL [%d], BATCH_PERIOD [%d]", b_interval, b_period);
1101
1102                         if (client)
1103                                 update_batch_tracking_interval(LBS_SERVER_INTERVAL_ADD, client, b_interval, b_period, lbs_server);
1104
1105                         start_batch_tracking(lbs_server, lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL],
1106                                                                                         lbs_server->optimized_batch_array[LBS_BATCH_PERIOD]);
1107
1108                 } else if (!g_strcmp0(g_variant_get_string(value, &length), "STOP_BATCH")) {
1109
1110                         if (client)
1111                                 update_batch_tracking_interval(LBS_SERVER_INTERVAL_REMOVE, client, 0, 0, lbs_server);
1112
1113                         stop_batch_tracking(lbs_server, lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL],
1114                                                                                         lbs_server->optimized_batch_array[LBS_BATCH_PERIOD]);
1115
1116                 }
1117 #endif
1118 #ifndef _TIZEN_PUBLIC_
1119                 else if (!g_strcmp0(g_variant_get_string(value, &length), "SUPLNI")) {
1120                         while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
1121                                 if (!g_strcmp0(key, "HEADER")) {
1122                                         msg_header = g_variant_dup_string(value, &length);
1123                                 } else if (!g_strcmp0(key, "BODY")) {
1124                                         size = (int) g_variant_get_size(value);
1125                                         msg_body = (char *) g_malloc0(sizeof(char) * size);
1126                                         memcpy(msg_body, g_variant_get_data(value), size);
1127                                 } else if (!g_strcmp0(key, "SIZE")) {
1128                                         size = (int) g_variant_get_int32(value);
1129                                 }
1130                         }
1131                         request_supl_ni_session(msg_header, msg_body, size);
1132                         if (msg_header) g_free(msg_header);
1133                         if (msg_body) g_free(msg_body);
1134                 }
1135 #endif
1136                 else if (!g_strcmp0(g_variant_get_string(value, &length), "SET:OPT")) {
1137                         LOG_GPS(DBG_LOW, "SET:OPT is called");
1138                         gboolean is_update_interval = FALSE, is_update_interval_method = FALSE;
1139
1140                         while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
1141
1142                                 if (!g_strcmp0(key, "OPTION")) {
1143                                         option = g_variant_dup_string(value, &length);
1144                                         LOG_GPS(DBG_ERR, "option [%s]", option);
1145
1146                                         if (!g_strcmp0(option, "DELGPS")) {
1147                                                 if (request_delete_gps_data() != TRUE)
1148                                                         LOG_GPS(DBG_ERR, "Fail to request_delete_gps_data");
1149                                         } else if (!g_strcmp0(option, "USE_SV")) {
1150                                                 g_mutex_lock(&lbs_server->mutex);
1151                                                 if (lbs_server->sv_used == FALSE)
1152                                                         lbs_server->sv_used = TRUE;
1153                                                 g_mutex_unlock(&lbs_server->mutex);
1154                                         } else if (!g_strcmp0(option, "USE_NMEA")) {
1155                                                 if (lbs_server->nmea_used == FALSE)
1156                                                         lbs_server->nmea_used = TRUE;
1157                                         } else if (!g_strcmp0(option, "UNUSE_NMEA")) {
1158                                                 if (lbs_server->nmea_used == TRUE)
1159                                                         lbs_server->nmea_used = FALSE;
1160                                         }
1161                                         g_free(option);
1162                                 } else if (!g_strcmp0(key, "METHOD")) {
1163                                         method = g_variant_get_int32(value);
1164                                         LOG_GPS(DBG_LOW, "METHOD [%d]", method);
1165                                         is_update_interval_method = TRUE;
1166                                 } else if (!g_strcmp0(key, "INTERVAL_UPDATE")) {
1167                                         interval = g_variant_get_uint32(value);
1168                                 } else if (!g_strcmp0(key, "PREV_INTERVAL")) {
1169                                         prev_interval = g_variant_get_uint32(value);
1170                                 } else if (!g_strcmp0(key, "FUSED_MODE")) {
1171                                         fused_mode = g_variant_get_int32(value);
1172                                 }
1173                         }
1174
1175                         LOG_GPS(DBG_LOW, "PREV_INTERVAL [%u] --> INTERVAL_UPDATE [%u], min [%u] ", prev_interval, interval, lbs_server->temp_minimum_interval);
1176                         if ((interval != prev_interval) && (prev_interval > 0))
1177                                 is_update_interval = TRUE;
1178
1179                         if (is_update_interval && is_update_interval_method && client) {
1180                                 LOG_GPS(DBG_LOW, "update_pos_tracking_interval -> SET:OPT");
1181                                 update_pos_tracking_interval(LBS_SERVER_INTERVAL_UPDATE, client, method, interval, prev_interval, lbs_server);
1182                                 if (lbs_server->is_needed_changing_interval) {
1183                                         lbs_server->is_needed_changing_interval = FALSE;
1184                                         request_change_pos_update_interval(method, (gpointer)lbs_server);
1185                                 }
1186                         }
1187                 }
1188         }
1189 }
1190
1191 static gboolean gps_remove_all_clients(lbs_server_s *lbs_server)
1192 {
1193         LOG_GPS(DBG_LOW, "remove_all_clients[%d] GPS", lbs_server->gps_client_count);
1194         if (lbs_server->is_mock_running == LBS_SERVER_METHOD_GPS) {
1195                 mock_stop_tracking(lbs_server);
1196                 setting_ignore_key_changed(VCONFKEY_LOCATION_MOCK_ENABLED, __setting_mock_cb);
1197         }
1198
1199         if (lbs_server->gps_client_count <= 0) {
1200                 lbs_server->gps_client_count = 0;
1201                 return FALSE;
1202         }
1203
1204         lbs_server->gps_client_count = 0;
1205         stop_tracking(lbs_server, LBS_SERVER_METHOD_GPS, LOCATION_FUSED_NONE);
1206
1207         return TRUE;
1208 }
1209
1210 static void shutdown(gpointer userdata, gboolean *shutdown_arr)
1211 {
1212         LOG_GPS(DBG_LOW, "shutdown callback gps:%d nps:%d", shutdown_arr[LBS_SERVER_METHOD_GPS], shutdown_arr[LBS_SERVER_METHOD_NPS]);
1213         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
1214
1215         if (shutdown_arr[LBS_SERVER_METHOD_GPS]) {
1216                 LOG_GPS(DBG_LOW, "-> shutdown GPS");
1217                 if (lbs_server->is_gps_running) {
1218                         if (gps_remove_all_clients(lbs_server))
1219                                 LOG_GPS(DBG_ERR, "<<<< Abnormal shutdown >>>>");
1220                 }
1221         }
1222
1223         if (shutdown_arr[LBS_SERVER_METHOD_NPS]) {
1224                 LOG_NPS(DBG_LOW, "-> shutdown NPS");
1225                 if (lbs_server->is_nps_running) {
1226                         LOG_NPS(DBG_ERR, "lbs_server is running. nps_plugin_stop");
1227                         nps_plugin_stop(lbs_server);
1228                 }
1229         }
1230
1231 #if 0 /* Not needed */
1232         int enabled = 0;
1233         setting_get_int(VCONFKEY_LOCATION_NETWORK_ENABLED, &enabled);
1234         if (enabled == 0) {
1235                 if (lbs_server->loop != NULL)
1236                         g_main_loop_quit(lbs_server->loop);
1237         } else {
1238                 if (vconf_notify_key_changed(VCONFKEY_LOCATION_NETWORK_ENABLED, _network_enabled_cb, lbs_server))
1239                         LOG_NPS(DBG_ERR, "fail to notify VCONFKEY_LOCATION_NETWORK_ENABLED");
1240         }
1241 #endif
1242 }
1243
1244 #ifdef TIZEN_DEVICE
1245 static void fused_update_position_cb(fl_location *location, gpointer user_data)
1246 {
1247         LOG_FUSED_FUNC;
1248         if (location == NULL || user_data == NULL) {
1249                 LOG_FUSED(LOG_ERROR, "parameter is NULL");
1250                 return;
1251         }
1252         lbs_server_s *lbs_server = (lbs_server_s *)(user_data);
1253         LbsPositionExtFields fields = (LBS_POSITION_EXT_FIELDS_LATITUDE | LBS_POSITION_EXT_FIELDS_LONGITUDE
1254                         | LBS_POSITION_EXT_FIELDS_ALTITUDE | LBS_POSITION_EXT_FIELDS_SPEED | LBS_POSITION_EXT_FIELDS_DIRECTION | LBS_POSITION_EXT_FIELDS_CLIMB);
1255
1256         GVariant *accuracy = g_variant_new("(idd)", LBS_ACCURACY_LEVEL_DETAILED,
1257                                                                         location->accuracy.horizontal_accuracy, // TODO: or from location->sigma.of_horizontal_pos
1258                                                                         location->accuracy.vertical_accuracy);  // TODO: or from location->sigma.of_altitude
1259
1260         lbs_server_emit_position_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_FUSED,
1261                                 fields, location->pos.timestamp,
1262                                 location->pos.latitude, location->pos.longitude, location->pos.altitude,
1263                                 location->vel.speed, location->vel.direction, location->vel.climb, accuracy);
1264 }
1265 #endif
1266
1267 static void gps_update_position_cb(pos_data_t *pos, gps_error_t error, void *user_data)
1268 {
1269         GVariant *accuracy = NULL;
1270         LbsPositionExtFields fields;
1271
1272         lbs_server_s *lbs_server = (lbs_server_s *)(user_data);
1273
1274         if (lbs_server->is_mock_running != MOCK_RUNNING_OFF)
1275                 return ;
1276
1277         memcpy(&lbs_server->position, pos, sizeof(pos_data_t));
1278
1279         if (lbs_server->status != LBS_STATUS_AVAILABLE) {
1280                 lbs_server_emit_status_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_GPS, LBS_STATUS_AVAILABLE);
1281                 lbs_server->status = LBS_STATUS_AVAILABLE;
1282         }
1283
1284         fields = (LBS_POSITION_EXT_FIELDS_LATITUDE | LBS_POSITION_EXT_FIELDS_LONGITUDE | LBS_POSITION_EXT_FIELDS_ALTITUDE | LBS_POSITION_EXT_FIELDS_SPEED | LBS_POSITION_EXT_FIELDS_DIRECTION);
1285
1286         accuracy = g_variant_new("(idd)", LBS_ACCURACY_LEVEL_DETAILED, pos->hor_accuracy, pos->ver_accuracy);
1287         if (accuracy == NULL)
1288                 LOG_GPS(DBG_LOW, "accuracy is NULL");
1289
1290         gps_set_position(pos);
1291
1292 #ifdef TIZEN_DEVICE
1293         send_gps_position_to_fused_engine(pos->timestamp, pos->latitude, pos->longitude, pos->altitude,
1294                         pos->speed, pos->bearing, pos->hor_accuracy, pos->ver_accuracy);
1295 #endif
1296
1297         lbs_server_emit_position_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_GPS, fields, pos->timestamp,
1298                                         pos->latitude, pos->longitude, pos->altitude, pos->speed, pos->bearing, 0.0, accuracy);
1299 }
1300
1301 static void gps_update_batch_cb(batch_data_t *batch, void *user_data)
1302 {
1303         lbs_server_s *lbs_server = (lbs_server_s *)(user_data);
1304         memcpy(&lbs_server->batch, batch, sizeof(batch_data_t));
1305
1306         if (lbs_server->status != LBS_STATUS_AVAILABLE) {
1307                 lbs_server_emit_status_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_GPS, LBS_STATUS_AVAILABLE);
1308                 lbs_server->status = LBS_STATUS_AVAILABLE;
1309         }
1310
1311         lbs_server_emit_batch_changed(lbs_server->lbs_dbus_server, batch->num_of_location);
1312 }
1313
1314 static void gps_update_satellite_cb(sv_data_t *sv, void *user_data)
1315 {
1316         lbs_server_s *lbs_server = (lbs_server_s *)(user_data);
1317         if (lbs_server->sv_used == FALSE)
1318                 return;
1319
1320         int index;
1321         int timestamp = 0;
1322         int satellite_used = 0;
1323         GVariant *used_prn = NULL;
1324         GVariant *satellite_info = NULL;
1325         GVariantBuilder *used_prn_builder = NULL;
1326         GVariantBuilder *satellite_info_builder = NULL;
1327
1328         memcpy(&lbs_server->satellite, sv, sizeof(sv_data_t));
1329         timestamp = sv->timestamp;
1330
1331         used_prn_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
1332         for (index = 0; index < sv->num_of_sat; ++index) {
1333                 if (sv->sat[index].used) {
1334                         g_variant_builder_add(used_prn_builder, "i", sv->sat[index].prn);
1335                         ++satellite_used;
1336                 }
1337         }
1338         used_prn = g_variant_builder_end(used_prn_builder);
1339
1340         satellite_info_builder = g_variant_builder_new(G_VARIANT_TYPE("a(iiii)"));
1341         for (index = 0; index < sv->num_of_sat; ++index) {
1342                 g_variant_builder_add(satellite_info_builder, "(iiii)", sv->sat[index].prn,
1343                                                         sv->sat[index].elevation, sv->sat[index].azimuth, sv->sat[index].snr);
1344         }
1345         satellite_info = g_variant_builder_end(satellite_info_builder);
1346
1347         lbs_server_emit_satellite_changed(lbs_server->lbs_dbus_server, timestamp, satellite_used,
1348                                         sv->num_of_sat, used_prn, satellite_info);
1349 }
1350
1351 static void gps_update_nmea_cb(nmea_data_t *nmea, void *user_data)
1352 {
1353         lbs_server_s *lbs_server = (lbs_server_s *)(user_data);
1354
1355         if (lbs_server->nmea.data) {
1356                 g_free(lbs_server->nmea.data);
1357                 lbs_server->nmea.len = 0;
1358                 lbs_server->nmea.data = NULL;
1359         }
1360         lbs_server->nmea.timestamp = lbs_server->position.timestamp;
1361         lbs_server->nmea.data = g_malloc(nmea->len + 1);
1362         g_return_if_fail(lbs_server->nmea.data);
1363
1364         g_memmove(lbs_server->nmea.data, nmea->data, nmea->len);
1365         lbs_server->nmea.data[nmea->len] = '\0';
1366         lbs_server->nmea.len = nmea->len;
1367
1368         if (lbs_server->nmea_used == FALSE)
1369                 return;
1370
1371         /* LOG_GPS(DBG_LOW, "[%d] %s", lbs_server->nmea.timestamp, lbs_server->nmea.data); */
1372         lbs_server_emit_nmea_changed(lbs_server->lbs_dbus_server, lbs_server->nmea.timestamp, lbs_server->nmea.data);
1373 }
1374
1375 int gps_update_geofence_transition(int geofence_id, geofence_zone_state_t transition, double latitude, double longitude, double altitude, double speed, double bearing, double hor_accuracy, void *data)
1376 {
1377         lbs_server_s *lbs_server = (lbs_server_s *)data;
1378         lbs_server_emit_gps_geofence_changed(lbs_server->lbs_dbus_server, geofence_id, transition, latitude, longitude, altitude, speed, bearing, hor_accuracy);
1379         return 0;
1380 }
1381
1382 int gps_update_geofence_service_status(int status, void *data)
1383 {
1384         lbs_server_s *lbs_server = (lbs_server_s *)data;
1385         lbs_server_emit_gps_geofence_status_changed(lbs_server->lbs_dbus_server, status);
1386         return 0;
1387 }
1388
1389 static void add_fence(gint fence_id, gdouble latitude, gdouble longitude, gint radius, gint last_state, gint monitor_states, gint notification_responsiveness, gint unknown_timer, gpointer userdata)
1390 {
1391         request_add_geofence(fence_id, latitude, longitude, radius, last_state, monitor_states, notification_responsiveness, unknown_timer);
1392 }
1393
1394 static void remove_fence(gint fence_id, gpointer userdata)
1395 {
1396         request_delete_geofence(fence_id);
1397 }
1398
1399 static void pause_fence(gint fence_id, gpointer userdata)
1400 {
1401         request_pause_geofence(fence_id);
1402 }
1403
1404 static void resume_fence(gint fence_id, gint monitor_states, gpointer userdata)
1405 {
1406         request_resume_geofence(fence_id, monitor_states);
1407 }
1408
1409 static void nps_init(lbs_server_s *lbs_server);
1410
1411 static void lbs_server_init(lbs_server_s *lbs_server)
1412 {
1413         LOG_GPS(DBG_LOW, "lbs_server_init");
1414
1415         lbs_server->status = LBS_STATUS_UNAVAILABLE;
1416         g_mutex_init(&lbs_server->mutex);
1417
1418         memset(&lbs_server->position, 0x00, sizeof(pos_data_t));
1419         memset(&lbs_server->satellite, 0x00, sizeof(sv_data_t));
1420         memset(&lbs_server->nmea, 0x00, sizeof(nmea_data_t));
1421
1422         lbs_server->is_gps_running = FALSE;
1423         lbs_server->is_fused_running = FALSE;
1424         lbs_server->sv_used = FALSE;
1425         lbs_server->nmea_used = FALSE;
1426         lbs_server->gps_client_count = 0;
1427         lbs_server->fused_high_count = 0;
1428         lbs_server->fused_balanced_count = 0;
1429         lbs_server->current_location_source = LOCATION_SOURCE_NONE;
1430
1431         nps_init(lbs_server);
1432
1433         /* create resource for dynamic-interval */
1434         lbs_server->dynamic_interval_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1435         lbs_server->optimized_interval = (guint *)g_malloc0(LBS_SERVER_METHOD_SIZE * sizeof(guint));
1436         lbs_server->is_needed_changing_interval = FALSE;
1437
1438         /* Mock Location init */
1439         lbs_server->is_mock_running = MOCK_RUNNING_OFF;
1440         lbs_server->mock_timer = 0;
1441         lbs_server->mock_accuracy = NULL;
1442
1443 #ifndef TIZEN_DEVICE
1444         lbs_server->batch_interval_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1445         lbs_server->optimized_batch_array = (guint *)g_malloc0(LBS_BATCH_SIZE * sizeof(guint));
1446         lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL] = MAX_BATCH_INTERVAL;
1447         lbs_server->optimized_batch_array[LBS_BATCH_PERIOD] = MAX_BATCH_PERIOD;
1448 #endif
1449
1450 #ifdef TIZEN_DEVICE
1451         location_fused_init(fused_update_position_cb, lbs_server);
1452 #endif
1453 }
1454
1455 static void nps_get_last_position(lbs_server_s *lbs_server)
1456 {
1457         int timestamp = 0;
1458         char location[128] = {0,};
1459         char *last_location[MAX_NPS_LOC_ITEM] = {0,};
1460         char *last = NULL;
1461         char *str = NULL;
1462         int index = 0;
1463
1464         setting_get_int(VCONFKEY_LOCATION_NV_LAST_WPS_TIMESTAMP, &timestamp);
1465         str = setting_get_string(VCONFKEY_LOCATION_NV_LAST_WPS_LOCATION);
1466         if (str == NULL)
1467                 return;
1468
1469         snprintf(location, sizeof(location), "%s", str);
1470         free(str);
1471
1472         last_location[index] = (char *)strtok_r(location, ";", &last);
1473         lbs_server->last_pos.timestamp = timestamp;
1474
1475         while (last_location[index] != NULL) {
1476                 switch (index) {
1477                 case 0:
1478                         lbs_server->last_pos.latitude = strtod(last_location[index], NULL);
1479                         break;
1480                 case 1:
1481                         lbs_server->last_pos.longitude = strtod(last_location[index], NULL);
1482                         break;
1483                 case 2:
1484                         lbs_server->last_pos.altitude = strtod(last_location[index], NULL);
1485                         break;
1486                 case 3:
1487                         lbs_server->last_pos.speed = strtod(last_location[index], NULL);
1488                         break;
1489                 case 4:
1490                         lbs_server->last_pos.direction = strtod(last_location[index], NULL);
1491                         break;
1492                 case 5:
1493                         lbs_server->last_pos.hor_accuracy = strtod(last_location[index], NULL);
1494                         break;
1495                 default:
1496                         break;
1497                 }
1498                 if (++index == MAX_NPS_LOC_ITEM) break;
1499                 last_location[index] = (char *)strtok_r(NULL, ";", &last);
1500         }
1501         LOG_NPS(DBG_LOW, "[%d] %lf, %lf", lbs_server->last_pos.timestamp, lbs_server->last_pos.latitude, lbs_server->last_pos.longitude);
1502 }
1503
1504 static void nps_init(lbs_server_s *lbs_server)
1505 {
1506         LOG_NPS(DBG_LOW, "nps_init");
1507
1508         lbs_server->nps_handle = NULL;
1509         lbs_server->period = 5000;
1510         nps_set_status(lbs_server, LBS_STATUS_UNAVAILABLE);
1511
1512         lbs_server->pos.fields = LBS_POSITION_EXT_FIELDS_NONE;
1513         lbs_server->pos.timestamp = 0;
1514         lbs_server->pos.latitude = 0.0;
1515         lbs_server->pos.longitude = 0.0;
1516         lbs_server->pos.altitude = 0.0;
1517         lbs_server->pos.acc_level = LBS_POSITION_EXT_FIELDS_NONE;
1518         lbs_server->pos.hor_accuracy = -1.0;
1519         lbs_server->pos.ver_accuracy = -1.0;
1520
1521         lbs_server->last_pos.timestamp = 0;
1522         lbs_server->last_pos.latitude = 0.0;
1523         lbs_server->last_pos.longitude = 0.0;
1524         lbs_server->last_pos.altitude = 0.0;
1525         lbs_server->last_pos.hor_accuracy = 0.0;
1526         lbs_server->last_pos.speed = 0.0;
1527         lbs_server->last_pos.direction = 0.0;
1528
1529 #if !GLIB_CHECK_VERSION(2, 31, 0)
1530         GMutex *mutex_temp = g_mutex_new();
1531         lbs_server->mutex = *mutex_temp;
1532         GCond *cond_temp = g_cond_new();
1533         lbs_server->cond = *cond_temp;
1534 #endif
1535
1536         g_mutex_init(&lbs_server->mutex);
1537         g_cond_init(&lbs_server->cond);
1538
1539         lbs_server->is_nps_running = FALSE;
1540         lbs_server->nps_client_count = 0;
1541
1542         if (!get_nps_plugin_module()->load()) {
1543                 LOG_NPS(DBG_ERR, "lbs_server plugin load() failed.");
1544                 return ;
1545         }
1546
1547         nps_get_last_position(lbs_server);
1548 }
1549
1550 static void nps_deinit(lbs_server_s *lbs_server)
1551 {
1552         LOG_NPS(DBG_LOW, "nps_deinit");
1553         if (get_nps_plugin_module()->unload()) {
1554                 if (lbs_server->is_nps_running) {
1555                         g_mutex_lock(&lbs_server->mutex);
1556                         lbs_server->is_nps_running = FALSE;
1557                         g_cond_signal(&lbs_server->cond);
1558                         g_mutex_unlock(&lbs_server->mutex);
1559                 }
1560
1561                 if (lbs_server->token) {
1562                         g_mutex_lock(&lbs_server->mutex);
1563                         g_free(lbs_server->token);
1564                         g_mutex_unlock(&lbs_server->mutex);
1565                 }
1566         } else {
1567                 LOG_NPS(DBG_ERR, "unload() failed.");
1568         }
1569
1570         lbs_server->nps_handle = NULL;
1571         lbs_server->is_nps_running = FALSE;
1572         lbs_server->nps_client_count = 0;
1573
1574 #if !GLIB_CHECK_VERSION(2, 31, 0)
1575         g_cond_free(&lbs_server->cond);
1576         g_mutex_free(&lbs_server->mutex);
1577 #endif
1578
1579         g_cond_clear(&lbs_server->cond);
1580         g_mutex_clear(&lbs_server->mutex);
1581
1582         nps_set_status(lbs_server, LBS_STATUS_UNAVAILABLE);
1583 }
1584
1585 static void _glib_log(const gchar *log_domain, GLogLevelFlags log_level,
1586                                         const gchar *msg, gpointer user_data)
1587 {
1588         LOG_NPS(DBG_ERR, "GLIB[%d] : %s", log_level, msg);
1589 }
1590
1591 int main(int argc, char **argv)
1592 {
1593         lbs_server_s *lbs_server = NULL;
1594         struct gps_callbacks g_update_cb;
1595         int ret = 0;
1596         g_update_cb.pos_cb = gps_update_position_cb;
1597         g_update_cb.batch_cb = gps_update_batch_cb;
1598         g_update_cb.sv_cb = gps_update_satellite_cb;
1599         g_update_cb.nmea_cb = gps_update_nmea_cb;
1600
1601 #if !GLIB_CHECK_VERSION(2, 31, 0)
1602         if (!g_thread_supported())
1603                 g_thread_init(NULL);
1604 #endif
1605
1606 #if !GLIB_CHECK_VERSION(2, 35, 0)
1607         g_type_init();
1608 #endif
1609
1610         ret = initialize_server(argc, argv);
1611         if (ret != 0) {
1612                 LOG_GPS(DBG_ERR, "initialize_server failed");
1613                 return 1;
1614         }
1615
1616         lbs_server = g_new0(lbs_server_s, 1);
1617         if (!lbs_server) {
1618                 LOG_GPS(DBG_ERR, "Failed to create lbs_server_s create");
1619                 return 1;
1620         }
1621         lbs_server_init(lbs_server);
1622         gps_init_log();
1623
1624         register_update_callbacks(&g_update_cb, lbs_server);
1625
1626         g_log_set_default_handler(_glib_log, lbs_server);
1627
1628         /* create lbs-dbus server */
1629         lbs_server_dbus_cb_t *lbs_server_dbus_cb = g_new0(lbs_server_dbus_cb_t, 1);
1630         if (!lbs_server_dbus_cb) {
1631                 LOG_GPS(DBG_ERR, "Failed to create lbs_server_dbus_cb");
1632                 return 1;
1633         }
1634
1635         lbs_server_dbus_cb->set_options_cb = set_options;
1636         lbs_server_dbus_cb->shutdown_cb = shutdown;
1637         lbs_server_dbus_cb->update_interval_cb = update_pos_tracking_interval;
1638         lbs_server_dbus_cb->request_change_interval_cb = request_change_pos_update_interval;
1639         lbs_server_dbus_cb->get_nmea_cb = get_nmea;
1640         lbs_server_dbus_cb->add_hw_fence_cb = add_fence;
1641         lbs_server_dbus_cb->delete_hw_fence_cb = remove_fence;
1642         lbs_server_dbus_cb->pause_hw_fence_cb = pause_fence;
1643         lbs_server_dbus_cb->resume_hw_fence_cb = resume_fence;
1644         lbs_server_dbus_cb->set_mock_location_cb = set_mock_location_cb;
1645
1646         ret = lbs_server_create(SERVICE_NAME, SERVICE_PATH, "lbs-server", "lbs-server",
1647                                                                 &(lbs_server->lbs_dbus_server), lbs_server_dbus_cb, (gpointer)lbs_server);
1648
1649         if (ret != LBS_SERVER_ERROR_NONE) {
1650                 LOG_GPS(DBG_ERR, "lbs_server_create failed");
1651                 return 1;
1652         }
1653
1654         LOG_GPS(DBG_LOW, "lbs_server_create called");
1655
1656         lbs_server->loop = g_main_loop_new(NULL, TRUE);
1657         g_main_loop_run(lbs_server->loop);
1658
1659         LOG_GPS(DBG_LOW, "lbs_server deamon Stop....");
1660
1661 #ifdef TIZEN_DEVICE
1662         location_fused_deinit();
1663 #endif
1664
1665         gps_deinit_log();
1666
1667         /* destroy resource for dynamic-interval */
1668         g_free(lbs_server->optimized_interval);
1669         g_hash_table_destroy(lbs_server->dynamic_interval_table);
1670 #ifndef TIZEN_DEVICE
1671         g_free(lbs_server->optimized_batch_array);
1672         g_hash_table_destroy(lbs_server->batch_interval_table);
1673 #endif
1674         /* free dbus callback */
1675         g_free(lbs_server_dbus_cb);
1676
1677         /* destroy lbs-dbus server */
1678         lbs_server_destroy(lbs_server->lbs_dbus_server);
1679         LOG_GPS(DBG_LOW, "lbs_server_destroy called");
1680
1681         g_main_loop_unref(lbs_server->loop);
1682
1683         nps_deinit(lbs_server);
1684         g_free(lbs_server);
1685
1686         deinitialize_server();
1687
1688         return 0;
1689 }
1690
1691
1692 /* Tizen 3.0 */
1693
1694 static void set_mock_location_cb(gint method, gdouble latitude, gdouble longitude, gdouble altitude,
1695         gdouble speed, gdouble direction, gdouble accuracy, gpointer userdata)
1696 {
1697         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
1698
1699         if (!lbs_server) {
1700                 LOG_MOCK(DBG_ERR, "lbs-server is NULL!!");
1701                 return;
1702         }
1703         LOG_SEC("[set_mock_location]  lat = %lf, lng = %lf", latitude, longitude);
1704         memset(&g_mock_position, 0x00, sizeof(NpsManagerPositionExt));
1705         if (latitude == MOCK_LOCATION_CLEAR_VALUE) {
1706                 if (lbs_server->is_mock_running != MOCK_RUNNING_OFF) {
1707                         g_mutex_lock(&lbs_server->mutex);
1708                         lbs_server->is_mock_running = MOCK_RUNNING_OFF;
1709                         g_mutex_unlock(&lbs_server->mutex);
1710
1711                         mock_stop_tracking(lbs_server);
1712                         setting_ignore_key_changed(VCONFKEY_LOCATION_MOCK_ENABLED, __setting_mock_cb);
1713                         g_mock_position.timestamp = 0;
1714                 }
1715                 return ;
1716         }
1717
1718         time_t timestamp;
1719         time(&timestamp);
1720         g_mock_position.fields |= LBS_POSITION_EXT_FIELDS_DIRTY;
1721         g_mock_position.timestamp = timestamp;
1722         g_mock_position.latitude = latitude;
1723         g_mock_position.longitude = longitude;
1724         g_mock_position.altitude = altitude;
1725         g_mock_position.speed = speed;
1726         g_mock_position.direction = direction;
1727         g_mock_position.acc_level = LBS_ACCURACY_LEVEL_DETAILED;
1728         g_mock_position.hor_accuracy = accuracy;
1729         g_mock_position.ver_accuracy = -1;
1730
1731         if (lbs_server->is_mock_running == MOCK_RUNNING_OFF) {
1732                 g_mutex_lock(&lbs_server->mutex);
1733                 lbs_server->is_mock_running = method;
1734                 g_mutex_unlock(&lbs_server->mutex);
1735         }
1736
1737         if (lbs_server->is_gps_running || lbs_server->is_nps_running)
1738                 mock_start_tracking(lbs_server);
1739
1740         gps_set_last_mock(timestamp, latitude, longitude, altitude, speed, direction, accuracy);
1741 }
1742
1743 int __copy_mock_location(lbs_server_s *lbs_server)
1744 {
1745         if (!lbs_server) {
1746                 LOG_MOCK(DBG_ERR, "lbs_server is NULL!!");
1747                 return FALSE;
1748         }
1749
1750         memset(&lbs_server->mock_pos, 0x00, sizeof(NpsManagerPositionExt));
1751         memcpy(&lbs_server->mock_pos, &g_mock_position, sizeof(NpsManagerPositionExt));
1752         g_mock_position.fields = LBS_POSITION_EXT_FIELDS_NONE;
1753         LOG_SEC("[%d] lat = %lf, lng = %lf", lbs_server->mock_pos.timestamp, lbs_server->mock_pos.latitude, lbs_server->mock_pos.longitude);
1754
1755         if (lbs_server->mock_pos.latitude >= -90 && lbs_server->mock_pos.latitude <= 90)
1756                 lbs_server->mock_pos.fields |= LBS_POSITION_EXT_FIELDS_LATITUDE;
1757
1758         if (lbs_server->mock_pos.longitude >= -180 && lbs_server->mock_pos.longitude <= 180)
1759                 lbs_server->mock_pos.fields |= LBS_POSITION_EXT_FIELDS_LONGITUDE;
1760
1761         lbs_server->mock_pos.fields |= LBS_POSITION_EXT_FIELDS_ALTITUDE;
1762
1763         if (lbs_server->mock_pos.speed >= 0)
1764                 lbs_server->mock_pos.fields |= LBS_POSITION_EXT_FIELDS_SPEED;
1765
1766         if (lbs_server->mock_pos.direction >= 0 && lbs_server->mock_pos.direction <= 360)
1767                 lbs_server->mock_pos.fields |= LBS_POSITION_EXT_FIELDS_DIRECTION;
1768
1769         lbs_server->mock_accuracy = g_variant_ref_sink(g_variant_new("(idd)", LBS_ACCURACY_LEVEL_DETAILED, lbs_server->mock_pos.hor_accuracy, -1));
1770
1771         return TRUE;
1772 }
1773
1774 static gboolean __mock_position_update_cb(gpointer userdata)
1775 {
1776         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
1777
1778         if (!lbs_server) {
1779                 LOG_MOCK(DBG_ERR, "lbs-server is NULL!!");
1780                 return FALSE;
1781         }
1782
1783         if (g_mock_position.timestamp) {
1784                 if (g_mock_position.fields & LBS_POSITION_EXT_FIELDS_DIRTY)
1785                         __copy_mock_location(lbs_server);
1786
1787                 time_t timestamp;
1788                 time(&timestamp);
1789
1790                 LOG_SEC("[%d] lat = %lf, lng = %lf", lbs_server->mock_pos.timestamp, lbs_server->mock_pos.latitude, lbs_server->mock_pos.longitude);
1791
1792                 lbs_server->mock_pos.timestamp = timestamp;
1793                 lbs_server_emit_position_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_MOCK,
1794                                 lbs_server->mock_pos.fields, lbs_server->mock_pos.timestamp,
1795                                 lbs_server->mock_pos.latitude,  lbs_server->mock_pos.longitude, lbs_server->mock_pos.altitude,
1796                                 lbs_server->mock_pos.speed, lbs_server->mock_pos.direction, 0.0, lbs_server->mock_accuracy);
1797         }
1798
1799         return TRUE;
1800 }
1801
1802 static void mock_start_tracking(lbs_server_s *lbs_server)
1803 {
1804         LOG_MOCK(DBG_LOW, "ENTER >>> mock_start_tracking");
1805         if (!lbs_server) {
1806                 LOG_MOCK(DBG_ERR, "lbs_server is NULL!!");
1807                 return ;
1808         }
1809
1810         __copy_mock_location(lbs_server);
1811
1812         if (!lbs_server->mock_timer) {
1813                 lbs_server->mock_timer = g_timeout_add_seconds(1, __mock_position_update_cb, lbs_server);
1814                 setting_notify_key_changed(VCONFKEY_LOCATION_MOCK_ENABLED, __setting_mock_cb, lbs_server);
1815         }
1816 }
1817
1818 static void mock_stop_tracking(lbs_server_s *lbs_server)
1819 {
1820         LOG_MOCK(DBG_LOW, ">>> mock_stop_tracking");
1821         if (!lbs_server) {
1822                 LOG_MOCK(DBG_ERR, "lbs-server is NULL!!");
1823                 return ;
1824         }
1825
1826         if (lbs_server->mock_timer)
1827                 g_source_remove(lbs_server->mock_timer);
1828
1829         lbs_server->mock_timer = 0;
1830         if (lbs_server->mock_accuracy)
1831                 g_variant_unref(lbs_server->mock_accuracy);
1832
1833         if (lbs_server->is_mock_running != MOCK_RUNNING_OFF) {
1834                 g_mutex_lock(&lbs_server->mutex);
1835                 lbs_server->is_mock_running = MOCK_RUNNING_OFF;
1836                 g_mutex_unlock(&lbs_server->mutex);
1837         }
1838 }
1839
1840 static void client_count_updater(lbs_server_s *lbs_server, lbs_server_method_e method, lbs_client_count type, gint fused_mode)
1841 {
1842         if (lbs_server == NULL) return;
1843
1844         switch (method) {
1845                 case LBS_SERVER_METHOD_GPS: {
1846                         g_mutex_lock(&lbs_server->mutex);
1847                         if (type == _LBS_CLIENT_ADD)
1848                                 lbs_server->gps_client_count++;
1849                         else if (type == _LBS_CLIENT_REMOVE)
1850                                 lbs_server->gps_client_count--;
1851                         else if (type == _LBS_CLIENT_REMOVE_ALL)
1852                                 lbs_server->gps_client_count = 0;
1853
1854                         g_mutex_unlock(&lbs_server->mutex);
1855                         break;
1856                 }
1857                 case LBS_SERVER_METHOD_NPS: {
1858                         g_mutex_lock(&lbs_server->mutex);
1859                         if (type == _LBS_CLIENT_ADD)
1860                                 lbs_server->nps_client_count++;
1861                         else if (type == _LBS_CLIENT_REMOVE)
1862                                 lbs_server->nps_client_count--;
1863                         else if (type == _LBS_CLIENT_REMOVE_ALL)
1864                                 lbs_server->nps_client_count = 0;
1865
1866                         g_mutex_unlock(&lbs_server->mutex);
1867                         break;
1868                 }
1869                 default: {
1870                         LOG_GPS(DBG_ERR, "Invalid method");
1871                         return;
1872                 }
1873         }
1874
1875         if (type == _LBS_CLIENT_ADD) {
1876                 if (fused_mode == LOCATION_FUSED_HIGH)
1877                         lbs_server->fused_high_count++;
1878                 else if (fused_mode == LOCATION_FUSED_BALANCED)
1879                         lbs_server->fused_balanced_count++;
1880         } else if (type == _LBS_CLIENT_REMOVE) {
1881                 if (fused_mode == LOCATION_FUSED_HIGH)
1882                         lbs_server->fused_high_count--;
1883                 else if (fused_mode == LOCATION_FUSED_BALANCED)
1884                         lbs_server->fused_balanced_count--;
1885         } else if (type == _LBS_CLIENT_REMOVE_ALL) {
1886                 lbs_server->fused_high_count = 0;
1887                 lbs_server->fused_balanced_count = 0;
1888         }
1889
1890         if (lbs_server->fused_high_count < 0) {
1891                 LOG_GPS(DBG_ERR, "---- fused_high count is negative value");
1892                 lbs_server->fused_high_count = 0;
1893         }
1894
1895         if (lbs_server->fused_balanced_count < 0) {
1896                 LOG_GPS(DBG_ERR, "---- fused_balanced count is negative value");
1897                 lbs_server->fused_balanced_count = 0;
1898         }
1899 }
1900
1901
1902 #ifndef TIZEN_DEVICE
1903 static void start_batch_tracking(lbs_server_s *lbs_server, int batch_interval, int batch_period)
1904 {
1905         LOG_GPS(DBG_LOW, "start batch tracking");
1906         client_count_updater(lbs_server, LBS_SERVER_METHOD_GPS, _LBS_CLIENT_ADD, LOCATION_FUSED_NONE);
1907
1908         if (lbs_server->is_gps_running == FALSE) {
1909                 LOG_GPS(DBG_LOW, "Batch: start tracking GPS");
1910                 lbs_server->status = LBS_STATUS_ACQUIRING;
1911         }
1912
1913         if (request_start_batch_session(batch_interval, batch_period) == TRUE) {
1914                 g_mutex_lock(&lbs_server->mutex);
1915                 lbs_server->is_gps_running = TRUE;
1916                 g_mutex_unlock(&lbs_server->mutex);
1917
1918                 setting_notify_key_changed(VCONFKEY_LOCATION_ENABLED, __setting_gps_cb, lbs_server);
1919         } else {
1920                 LOG_GPS(DBG_ERR, "Batch: Fail to request_start_batch_session");
1921         }
1922 }
1923
1924 static void stop_batch_tracking(lbs_server_s *lbs_server, int batch_interval, int batch_period)
1925 {
1926         LOG_GPS(DBG_LOW, "Batch: stop_tracking GPS");
1927         client_count_updater(lbs_server, LBS_SERVER_METHOD_GPS, _LBS_CLIENT_REMOVE, LOCATION_FUSED_NONE);
1928
1929         if (lbs_server->is_gps_running == FALSE) {
1930                 LOG_GPS(DBG_LOW, "Batch: gps- is already stopped");
1931                 return;
1932         }
1933
1934         int session_status = 1;         /* Keep current status */
1935         if (lbs_server->gps_client_count <= 0) {
1936                 g_mutex_lock(&lbs_server->mutex);
1937                 lbs_server->gps_client_count = 0;
1938                 g_mutex_unlock(&lbs_server->mutex);
1939                 session_status = 0;             /* stop */
1940         }
1941
1942         /* TRUE: All clients stopped, FALSE: Some clients are running with GPS or BATCH */
1943         if (request_stop_batch_session(batch_interval, batch_period, session_status) == TRUE) {
1944                 g_mutex_lock(&lbs_server->mutex);
1945                 lbs_server->is_gps_running = FALSE;
1946                 lbs_server->sv_used = FALSE;
1947                 g_mutex_unlock(&lbs_server->mutex);
1948
1949                 setting_ignore_key_changed(VCONFKEY_LOCATION_ENABLED, __setting_gps_cb);
1950         }
1951
1952         lbs_server->status = LBS_STATUS_UNAVAILABLE;
1953         lbs_server_emit_status_changed(lbs_server->lbs_dbus_server, LBS_SERVER_METHOD_GPS, LBS_STATUS_UNAVAILABLE);
1954 }
1955
1956 static void update_batch_interval_table_foreach_cb(gpointer key, gpointer value, gpointer userdata)
1957 {
1958         guint *interval_array = (guint *)value;
1959         dynamic_interval_updator_user_data *updator_ud = (dynamic_interval_updator_user_data *)userdata;
1960         lbs_server_s *lbs_server = updator_ud->lbs_server;
1961
1962         if (lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL] > interval_array[LBS_BATCH_INTERVAL])
1963                 lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL] = interval_array[LBS_BATCH_INTERVAL];
1964
1965         if (lbs_server->optimized_batch_array[LBS_BATCH_PERIOD] > interval_array[LBS_BATCH_PERIOD])
1966                 lbs_server->optimized_batch_array[LBS_BATCH_PERIOD] = interval_array[LBS_BATCH_PERIOD];
1967
1968         LOG_GPS(DBG_LOW, "foreach dynamic-batch. key:[%s]-batch[interval:%u, period:%u], optimized [%u, %u]", (char *)key, interval_array[LBS_BATCH_INTERVAL], interval_array[LBS_BATCH_PERIOD], lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL], lbs_server->optimized_batch_array[LBS_BATCH_PERIOD]);
1969 }
1970
1971 static gboolean update_batch_tracking_interval(lbs_server_interval_manipulation_type type, const gchar *client, guint interval, guint period, gpointer userdata)
1972 {
1973         LOG_GPS(DBG_INFO, "update_batch_tracking_interval");
1974         if (userdata == NULL) return FALSE;
1975         if (client == NULL) {
1976                 LOG_GPS(DBG_ERR, "client is NULL");
1977                 return FALSE;
1978         }
1979
1980         lbs_server_s *lbs_server = (lbs_server_s *)userdata;
1981
1982         switch (type) {
1983                 case LBS_SERVER_INTERVAL_ADD: {
1984                         LOG_GPS(DBG_LOW, "ADD, client[%s], interval[%u], period[%u]", client, interval, period);
1985                         gchar *client_cpy = NULL;
1986                         client_cpy = g_strdup(client);
1987
1988                         guint* interval_array = (guint *) g_hash_table_lookup(lbs_server->batch_interval_table, client_cpy);
1989                         if (!interval_array) {
1990                                 LOG_GPS(DBG_LOW, "first add key[%s] to batch-table", client);
1991                                 interval_array = (guint *)g_malloc0(LBS_BATCH_SIZE * sizeof(guint));
1992                                 if (!interval_array) {
1993                                         LOG_GPS(DBG_ERR, "interval_array is NULL");
1994                                         g_free(client_cpy);
1995                                         return FALSE;
1996                                 }
1997                                 g_hash_table_insert(lbs_server->batch_interval_table, (gpointer)client_cpy, (gpointer)interval_array);
1998                         }
1999                         interval_array[LBS_BATCH_INTERVAL] = interval;
2000                         interval_array[LBS_BATCH_PERIOD] = period;
2001                         break;
2002                 }
2003
2004                 case LBS_SERVER_INTERVAL_REMOVE: {
2005                         LOG_GPS(DBG_LOW, "REMOVE, client[%s]", client);
2006                         guint *interval_array = (guint *) g_hash_table_lookup(lbs_server->batch_interval_table, client);
2007                         if (!interval_array) {
2008                                 LOG_GPS(DBG_INFO, "Client[%s] is already removed from batch-table", client);
2009                                 break;
2010                         }
2011                         LOG_GPS(DBG_LOW, "Remove interval_array(%p):[%u, %u] from batch-table", interval_array, interval_array[LBS_BATCH_INTERVAL], interval_array[LBS_BATCH_PERIOD]);
2012
2013                         if (!g_hash_table_remove(lbs_server->batch_interval_table, client))
2014                                 LOG_GPS(DBG_ERR, "g_hash_table_remove is failed.");
2015
2016                         break;
2017                 }
2018
2019                 default: {
2020                         LOG_GPS(DBG_ERR, "unhandled interval-update type");
2021                         return FALSE;
2022                 }
2023         }
2024
2025         lbs_server->optimized_batch_array[LBS_BATCH_INTERVAL] = MAX_BATCH_INTERVAL + 1;
2026         lbs_server->optimized_batch_array[LBS_BATCH_PERIOD] = MAX_BATCH_PERIOD + 1;
2027
2028         if (g_hash_table_size(lbs_server->batch_interval_table) == 0) {
2029                 return FALSE;
2030         } else {
2031                 LOG_GPS(DBG_LOW, "updates optimized-batch-interval.");
2032                 dynamic_interval_updator_user_data updator_user_data;
2033                 updator_user_data.lbs_server = lbs_server;
2034
2035                 g_hash_table_foreach(lbs_server->batch_interval_table,
2036                                                         (GHFunc) update_batch_interval_table_foreach_cb, (gpointer) &updator_user_data);
2037         }
2038         LOG_GPS(DBG_LOW, "Updates_batch_tracking_interval done.");
2039         return TRUE;
2040 }
2041 #endif