Migrate from 2.4 code repo
[platform/core/context/context-service.git] / src / context_trigger / script_generator.cpp
1 /*
2  * context-service
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
20 #include <sstream>
21 #include <set>
22 #include <glib.h>
23 #include <string>
24 #include <json.h>
25 #include <types_internal.h>
26 #include <context_trigger_types_internal.h>
27 #include "script_generator.h"
28 #include "timer_types.h"
29
30 #define EVENT_WEEKDAY "(or (eq ?DayOfWeek \"Mon\") (eq ?DayOfWeek \"Tue\") (eq ?DayOfWeek \"Wed\") (eq ?DayOfWeek \"Thu\") (eq ?DayOfWeek \"Fri\"))"
31 #define EVENT_WEEKEND "(or (eq ?DayOfWeek \"Sat\") (eq ?DayOfWeek \"Sun\"))"
32 #define CONDITION_WEEKDAY "(or (eq (send [%s] get-DayOfWeek) \"Mon\") (eq (send [%s] get-DayOfWeek) \"Tue\") (eq (send [%s] get-DayOfWeek) \"Wed\") (eq (send [%s] get-DayOfWeek) \"Thu\") (eq (send [%s] get-DayOfWeek) \"Fri\"))"
33 #define CONDITION_WEEKEND "(or (eq (send [%s] get-DayOfWeek) \"Sat\") (eq (send [%s] get-DayOfWeek) \"Sun\"))"
34
35 static std::string generate_initial_fact(ctx::json event_template, ctx::json option);
36 static std::string generate_event_data(ctx::json event);
37 static std::string generate_condition_data(std::string rule_id, ctx::json conditions, std::string rule_op, ctx::json* inst_names);
38
39 static std::string int_to_string(int i)
40 {
41         std::ostringstream convert;
42         convert << i;
43         std::string str = convert.str();
44         return str;
45 }
46
47 static std::string convert_condition_weekday_weekend(std::string inst_name, std::string day)
48 {
49         std::string buf = (day.compare(TIMER_WEEKDAY) == 0)? CONDITION_WEEKDAY : CONDITION_WEEKEND;
50
51         size_t pos = 0;
52         while((pos = buf.find("%s", pos)) != std::string::npos) {
53                 buf.replace(pos, 2, inst_name);
54                 pos += inst_name.length();
55         }
56
57         return buf;
58 }
59
60 std::string ctx::script_generator::generate_deftemplate(ctx::json* item)
61 {
62         std::string script;
63
64         std::string name;
65         item->get(NULL, "name", &name);
66
67         std::set<std::string> slot;
68
69         std::string opt_name;
70         for (int i = 0; item->get_array_elem(NULL, "option", i, &opt_name); i++) {
71                 slot.insert(opt_name);
72         }
73
74         std::string attr_name;
75         for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
76                 slot.insert(attr_name);
77         }
78
79         //template name is "itemname"
80         script = "(deftemplate ";
81         script += name;
82         script += " ";
83
84         for (std::set<std::string>::iterator it = slot.begin(); it != slot.end(); ++it){
85                 script += "(slot ";
86                 script += *it;
87                 script += " (default null))";
88         }
89         script += ")";
90
91 //      _D("Deftemplate script is generated: %s", script.c_str());
92         script += "\n";
93
94         return script;
95 }
96
97 std::string ctx::script_generator::generate_defclass(ctx::json* item)
98 {
99         std::string script;
100
101         std::string name;
102         item->get(NULL, "name", &name);
103
104         //class name is "C.itemname"
105         script = "(defclass C.";
106         script += name;
107         script += " (is-a USER) (role concrete) ";
108
109         std::string attr_name;
110         for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
111                 script += "(slot ";
112                 script += attr_name;
113                 script += " (create-accessor read-write))";
114         }
115         script += ")";
116
117 //      _D("Defclass script is generated: %s", script.c_str());
118         script += "\n";
119
120         return script;
121 }
122
123 std::string ctx::script_generator::generate_makeinstance(ctx::json* item)
124 {
125         std::string script;
126
127         std::string name;
128         item->get(NULL, "name", &name);
129
130         std::string instance_name;
131         if (!item->get(NULL, "instance_name", &instance_name)) {
132                 instance_name = name;
133         }
134
135         //instance name is "[itemname]"
136         script = "([";
137         script += instance_name;
138         script += "] of C.";
139         script += name;
140
141         std::string attr_name;
142         for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
143                 script += " (";
144                 script += attr_name;
145                 script += " 0)";
146         }
147         script += ")";
148
149 //      _D("Makeinstance script is generated: %s", script.c_str());
150         script += "\n";
151
152         return script;
153 }
154
155 std::string ctx::script_generator::generate_undefrule(std::string rule_id)
156 {
157         std::string script;
158         script = "(undefrule rule";
159         script += rule_id;
160         script += ")";
161
162         return script;
163 }
164
165 std::string ctx::script_generator::generate_defrule(std::string rule_id, ctx::json event_template, ctx::json rule, ctx::json* inst_names, std::string zone)
166 {
167         std::string script;
168         ctx::json option = NULL;
169         rule.get(CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &option);
170
171         script = "(defrule rule";
172         script += rule_id;
173         script += " ";
174
175         script += generate_initial_fact(event_template, option);
176         script += " => ";
177
178         int eventdata_num = rule.array_get_size(CT_RULE_EVENT, CT_RULE_DATA_ARR);
179         int condition_num = rule.array_get_size(NULL, CT_RULE_CONDITION);
180
181         if (condition_num > 0) {
182                 // case1: condition exists
183                 script += "(if (and (eq ?*zone* \"";
184                 script += zone;
185                 script += "\") ";
186
187                 if (eventdata_num > 0) {
188                         ctx::json event;
189                         rule.get(NULL, CT_RULE_EVENT, &event);
190                         script += generate_event_data(event);
191                 }
192
193                 // condition
194                 ctx::json conditions;
195                 rule.get(NULL, CT_RULE_CONDITION, &conditions);
196                 std::string rule_op;
197                 rule.get(NULL, CT_RULE_OPERATOR, &rule_op);
198                 script += generate_condition_data(rule_id, conditions, rule_op, inst_names);
199
200                 script += ")";
201                 script += " then ";
202                 script += " (execute_action rule";
203                 script += rule_id;
204                 script += "))";
205         } else if (eventdata_num > 0) {
206                 // case2: no conditions, but event data
207                 ctx::json event;
208                 rule.get(NULL, CT_RULE_EVENT, &event);
209
210                 script += "(if (and (eq ?*zone* \"";
211                 script += zone;
212                 script += "\") ";
213                 script += generate_event_data(event);
214                 script += ") then ";
215                 script += " (execute_action rule";
216                 script += rule_id;
217                 script += "))";
218         } else {
219                 // case3: only action
220                 script += "if (eq ?*zone* \"";
221                 script += zone;
222                 script += "\") then (execute_action rule";
223                 script += rule_id;
224                 script += ")";
225         }
226
227         script += ")";
228         _D("Defrule script generated: %s", script.c_str());
229         return script;
230 }
231
232 std::string generate_initial_fact(ctx::json event_template, ctx::json option)
233 {
234         std::string script = "(";
235         std::string e_name;
236         event_template.get(NULL, "name", &e_name);
237
238         script += e_name;
239         script += " ";
240
241         // options
242         std::string opt_key;
243         for (int i = 0; event_template.get_array_elem(NULL, "option", i, &opt_key); i++) {
244                 script += "(";
245                 script += opt_key;
246                 script += " ";
247
248                 std::string val_str;
249                 int val;
250                 if (option.get(NULL, opt_key.c_str(), &val_str)) {
251                         script += val_str;
252                 } else if (option.get(NULL, opt_key.c_str(), &val)) {
253                         script += int_to_string(val);
254                 } else {
255                         script += "?";
256                         script += opt_key;
257                 }
258
259                 script += ")";
260         }
261
262         // attributes
263         std::string attr;
264         for (int i = 0; event_template.get_array_elem(NULL, "attributes", i, &attr); i++) {
265                 script += "(";
266                 script += attr;
267                 script += " ?";
268                 script += attr;
269                 script += ")";
270         }
271         script += ")";
272
273 //      _D("Initial event fact is %s", script.c_str());
274         return script;
275 }
276
277 std::string generate_event_data(ctx::json event)
278 {
279         std::string ename;
280         event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
281
282         std::string script;
283         int edata_count = event.array_get_size(NULL, CT_RULE_DATA_ARR);
284
285         if (edata_count > 1) {
286                 std::string item_op;
287                 event.get(NULL, CT_RULE_EVENT_OPERATOR, &item_op);
288                 script += "(";
289                 script += item_op;
290                 script += " ";
291         }
292
293         ctx::json edata;
294         for (int i = 0; event.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &edata); i++) {
295                 std::string key_name;
296                 if (ename.compare(TIMER_EVENT_SUBJECT) == 0) {
297                         edata.get(NULL, CT_RULE_DATA_KEY, &key_name);
298                 }
299
300                 int valuecount = edata.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
301                 int opcount = edata.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
302                 std::string key;
303                 edata.get(NULL, CT_RULE_DATA_KEY, &key);
304
305                 if (valuecount != opcount) {
306                         _E("Invalid event data. (Value count:%d, Operator count: %d)", valuecount, opcount);
307                         return "";
308                 }
309
310                 if (valuecount > 1) {
311                         script += "(";
312
313                         std::string key_op;
314                         edata.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &key_op);
315                         script += key_op;
316                         script += " ";
317                 }
318
319                 for (int j = 0; j < valuecount; j++){
320                         std::string val_op;
321                         std::string val;
322                         edata.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &val_op);
323                         edata.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &val);
324
325                         if (key_name.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
326                                 if (val.compare("\"" TIMER_WEEKDAY "\"") == 0) {
327                                         script += (val_op.compare("eq") == 0)? EVENT_WEEKDAY : EVENT_WEEKEND;
328                                         continue;
329                                 } else if (val.compare("\"" TIMER_WEEKEND "\"") == 0) {
330                                         script += (val_op.compare("eq") == 0)? EVENT_WEEKEND : EVENT_WEEKDAY;
331                                         continue;
332                                 }
333                         }
334
335                         script += "(";
336                         script += val_op;
337                         script += " ?";
338                         script += key;
339                         script += " ";
340                         script += val;
341                         script += ")";
342                 }
343
344                 if (valuecount > 1) {
345                         script += ")";
346                 }
347         }
348
349         if (edata_count > 1) {
350                 script += ")";
351         }
352
353         return script;
354 }
355
356 std::string generate_condition_data(std::string rule_id, ctx::json conditions, std::string rule_op, ctx::json* inst_names)
357 {
358         std::string script;
359
360         ctx::json conds;
361         conds.set(NULL, CT_RULE_CONDITION, conditions);
362
363         int conds_count = conds.array_get_size(NULL, CT_RULE_CONDITION);
364         if (conds_count > 1) {
365                 script += "(";
366                 script += rule_op;      // operator between each condition item
367                 script += " ";
368         }
369
370         ctx::json it;
371         for (int i = 0; conds.get_array_elem(NULL, CT_RULE_CONDITION, i, &it); i++) {
372                 std::string cond_name;
373                 it.get(NULL, CT_RULE_CONDITION_ITEM, &cond_name);
374
375                 std::string inst_name;
376                 (inst_names)->get(NULL, cond_name.c_str(), &inst_name);
377
378                 int data_count = it.array_get_size(NULL, CT_RULE_DATA_ARR);
379
380                 if (data_count > 1) {
381                         std::string item_op;
382                         it.get(NULL, CT_RULE_CONDITION_OPERATOR, &item_op);
383                         script += "(";
384                         script += item_op; // operator between data keys of a condition item
385                         script += " ";
386                 }
387
388                 ctx::json data;
389                 for (int j = 0; it.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &data); j++) {
390                         std::string key_name;
391                         data.get(NULL, CT_RULE_DATA_KEY, &key_name);
392                         int dval_count = data.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
393                         int dvalop_count = data.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
394
395                         if (dval_count != dvalop_count) {
396                                 _E("Invalid condition data. (Data value count %d, Data value operator count %d)", dval_count, dvalop_count);
397                         }
398
399                         if (dval_count > 1) {
400                                 std::string dkey_op;
401                                 data.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &dkey_op);
402
403                                 script += "(";
404                                 script += dkey_op; // operator between comparison data values of a condition data key
405                                 script += " " ;
406                         }
407
408                         for (int k = 0; k < dval_count; k++) {
409                                 std::string dval_op;
410                                 std::string dval;
411                                 data.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, k, &dval_op);
412                                 data.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, k, &dval);
413
414                                 if (inst_name.compare(TIMER_CONDITION_SUBJECT) == 0 && key_name.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
415                                         if (dval.compare("\"" TIMER_WEEKDAY "\"") == 0) {
416                                                 script += convert_condition_weekday_weekend(inst_name, (dval_op.compare("eq") == 0)? TIMER_WEEKDAY : TIMER_WEEKEND);
417                                                 continue;
418                                         } else if (dval.compare("\"" TIMER_WEEKEND "\"") == 0) {
419                                                 script += convert_condition_weekday_weekend(inst_name, (dval_op.compare("eq") == 0)? TIMER_WEEKEND : TIMER_WEEKDAY);
420                                                 continue;
421                                         }
422                                 }
423
424                                 script += "(";
425                                 script += dval_op;
426                                 script += " (send [";
427                                 script += inst_name;
428                                 script += "] get-";
429                                 script += key_name;
430                                 script += ") ";
431                                 script += dval;
432                                 script += ")";
433                         }
434
435                         if (dval_count > 1) {
436                                 script += ")";
437                         }
438                 }
439
440                 if (data_count > 1 ) {
441                         script += ")";
442                 }
443         }
444
445         if (conds_count > 1) {
446                 script += ")";
447         }
448
449         return script;
450 }
451
452 std::string ctx::script_generator::generate_fact(std::string item_name, ctx::json event_template, ctx::json option, ctx::json data)
453 {
454         // Generate Fact script for invoked event
455         std::string script = "(";
456         script += item_name;
457         script += " ";
458
459         std::string opt_key;
460         std::string key;
461         std::string val_str;
462         int value;
463
464         for (int i = 0; event_template.get_array_elem(NULL, "option", i, &opt_key); i++) {
465                 script += "(";
466                 script += opt_key;
467                 script += " ";
468                 if (option.get(NULL, opt_key.c_str(), &val_str)) {      // string type data
469                         script += val_str;
470                 } else if (option.get(NULL, opt_key.c_str(), &value)) { // integer type data
471                         script += int_to_string(value);
472                 } else {
473                         script += "nil";
474                 }
475                 script += ")";
476         }
477
478         for (int i = 0; event_template.get_array_elem(NULL, "attributes", i, &key); i++) {
479                 script += "(";
480                 script += key;
481                 script += " ";
482                 if (data.get(NULL, key.c_str(), &val_str)) {    // string type data
483                         script += "\"" + val_str + "\"";
484                 } else if (data.get(NULL, key.c_str(), &value)) {       // integer type data
485                         script += int_to_string(value);
486                 } else {
487                         script += "nil";
488                 }
489                 script += ")";
490         }
491         script += ")";
492
493         return script;
494 }
495
496 std::string ctx::script_generator::generate_modifyinstance(std::string instance_name, ctx::json condition_template, ctx::json data)
497 {
498         std::string script = "(modify-instance [";
499         script += instance_name;
500         script += "] ";
501
502         std::string key;
503         std::string val_str;
504         int value;
505         for (int i = 0; condition_template.get_array_elem(NULL, "attributes", i, &key); i++) {
506                 if (data.get(NULL, key.c_str(), &val_str)) {    // string type data
507                         script += "(" + key + " \"" + val_str + "\")";
508                 } else  if (data.get(NULL, key.c_str(), &value)) {      // integer type data
509                         script += "(" + key + " " + int_to_string(value) + ")";
510                 }
511                 // else continue;
512         }
513         script += ")";
514
515         return script;
516 }