]> pilppa.org Git - libplp.git/blob - src/StoreDay.cc
39a23005f7c3314cc237fdb5f409db3130e47e33
[libplp.git] / src / StoreDay.cc
1 /*
2  * Store.cc
3  *
4  *  Created on: Oct 31, 2010
5  *      Author: lamikr
6  */
7
8 #include <list>
9 #include <string>
10 #include <fstream>
11 #include <limits>
12
13 #include <time.h>
14 #include <dirent.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18
19 #include "log.h"
20 #include "DeviceConfig.hh"
21 #include "StoreDay.hh"
22 #include "FileUtil.hh"
23
24 using namespace std;
25 using namespace plp;
26
27 StoreDay::StoreDay(string device_id_param,
28                 Date *date_time_param): Store(device_id_param, date_time_param) {
29         store_fname     = get_file_name(device_id_param, date_time_param);
30 }
31
32 StoreDay::StoreDay(string fname_param): Store("", NULL) {
33         store_data      = NULL;
34         range_data      = NULL;
35         store_fname     = fname_param;
36 }
37
38 StoreDay::~StoreDay() {
39         if (store_data != NULL) {
40                 delete(store_data);
41                 store_data      = NULL;
42         }
43 }
44
45 string StoreDay::get_year_dir_name(string device_id,
46                                 Date *date_time_param) {
47         string  ret_val;
48         char    buffer[10];
49         string  bd_name;
50
51         snprintf(buffer, 10, "%d", date_time_param->year);
52         bd_name = DeviceConfig::get_base_dir_name();
53         bd_name = FileUtil::concat_paths(bd_name, device_id);
54         ret_val = bd_name + "/" + buffer;
55         return ret_val;
56 }
57
58 string StoreDay::get_dir_name(string device_id,
59                         Date *date_time_param) {
60         string  ret_val;
61         char    buffer[30];
62         string  bd_name;
63
64         snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month);
65         bd_name = DeviceConfig::get_base_dir_name();
66         bd_name = FileUtil::concat_paths(bd_name, device_id);
67         ret_val = bd_name + "/" + buffer;
68         return ret_val;
69 }
70
71 string StoreDay::get_file_name(string device_id,
72                         Date *date_time_param) {
73         string  ret_val;
74         string  fname;
75         char    buffer[30];
76
77         snprintf(buffer,
78                 30,
79                 "%d-%02d-%02d",
80                 date_time_param->year,
81                 date_time_param->month,
82                 date_time_param->day);
83         fname   = buffer;
84         fname   = fname + DATAFILE_SUFFIX;
85         ret_val = get_dir_name(device_id, date_time_param);
86         ret_val = FileUtil::concat_paths(ret_val, fname);
87         return ret_val;
88 }
89
90 void StoreDay::save(string device_id,
91                 std::list<Data *> *data_list,
92                 int dec_precision) {
93         string                  n_path;
94         string                  f_path;
95         string                  line;
96         Data                    *data;
97         ofstream                *ostream;
98         Date                    date;
99         list<Data *>::iterator  iter;
100
101         ostream =  NULL;
102         f_path  = "";
103         /* needs to be casted to long unsigned int value is "unsigned int" in some
104            toolchains and that would otherwise cause an warning/error 
105         */
106         log_info("[%s] saving %lu data values.\n", device_id.c_str(),
107                 (long unsigned int)data_list->size());
108         // TODO: add mutex to protect string_list while it's read and emptied
109         for(iter = data_list->begin(); iter != data_list->end(); iter++) {
110                 data    = (Data *)*iter;
111                 date    = data->get_date();
112                 n_path  = get_file_name(device_id, &date);
113                 if (n_path.compare(f_path) != 0) {
114                         if (ostream != NULL) {
115                                 ostream->close();
116                                 delete(ostream);
117                         }
118                         f_path  = n_path;
119                         log_info("[%s] Opening file for save: %s\n", device_id.c_str(), f_path.c_str());
120                         ostream = FileUtil::open_for_writing(f_path.c_str());
121                 }
122                 if ((ostream != NULL) &&
123                     (ostream->is_open() == true)) {
124                         line    = data->to_string(dec_precision);
125                         if (line.length() > 0) {
126                                 log_debug("storing line: %s\n", line.c_str());
127                                 *ostream << line << endl;
128                         }
129                 }
130                 else {
131                         log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), f_path.c_str());
132                 }
133         }
134         if (ostream != NULL) {
135                 ostream->close();
136                 delete(ostream);
137         }
138 }
139
140 bool StoreDay::load() {
141         return Store::load(store_fname);
142 }
143
144 bool StoreDay::exist(string fname_param, bool writable) {
145         bool    ret_val;
146         ret_val = FileUtil::file_exist(fname_param.c_str(), writable);
147         return ret_val;
148 }
149
150 bool StoreDay::exist(string dev_id_param,
151                 Date *date,
152                 bool writable) {
153         bool    ret_val;
154         string  f_name;
155
156         f_name  = get_file_name(dev_id_param, date);
157         ret_val = FileUtil::file_exist(f_name.c_str(), writable);
158         return ret_val;
159 }
160
161 bool StoreDay::exist_in_month(string dev_id_param,
162                         Date *date,
163                         bool writable) {
164         string  dirname;
165         bool    ret_val;
166
167         dirname = StoreDay::get_dir_name(dev_id_param, date);
168         ret_val = FileUtil::dir_exist(dirname.c_str(), writable);
169         return ret_val;
170 }
171
172 bool StoreDay::exist_in_year(string dev_id_param,
173                         Date *date,
174                         bool writable) {
175         string  dirname;
176         bool    ret_val;
177
178         dirname = StoreDay::get_year_dir_name(dev_id_param, date);
179         ret_val = FileUtil::dir_exist(dirname.c_str(), writable);
180         return ret_val;
181 }
182
183 bool StoreDay::exist(bool writable) {
184         return exist(store_fname, writable);
185 }
186
187 static int get_summary_period_as_freq_seconds(EnumSummaryPeriod period_type_param) {
188         int     ret_val;
189
190         ret_val = 3600;
191         switch(period_type_param) {
192                 case PERIOD_SECONDLY:
193                         ret_val = 1;
194                         break;
195                 case PERIOD_MINUTELY:
196                         ret_val = 60;
197                         break;
198                 case PERIOD_HOURLY:
199                         ret_val = 3600;
200                         break;
201                 case PERIOD_DAILY:
202                 case PERIOD_MONTHLY:
203                 case PERIOD_YEARLY:
204                 default:
205                         // -1 as freq means that show all data from the current store
206                         ret_val = -1;
207                         break;
208         }
209         return ret_val;
210 }
211
212 plp::DataRange *StoreDay::get_sum(EnumSummaryPeriod period_type_param) {
213         int             row_count;
214         int             col_count;
215         int             jj;
216         int             ii;
217         Data            *data;
218         Data            *calc;
219         Date            *limit_d;
220         Date            date;
221         DataRange       *ret_val;
222         int             frq_sec;
223         bool            succ;
224
225         ret_val = NULL;
226         calc    = NULL;
227         limit_d = NULL;
228         frq_sec = get_summary_period_as_freq_seconds(period_type_param);
229         if (store_data == NULL) {
230                 succ    = load();
231         }
232         if ((succ == true) &&
233             (store_data != NULL)) {
234                 row_count       = store_data->get_count();
235                 if (row_count > 0) {
236                         col_count       = store_data->get_data_item_value_count();
237                         if (col_count > 0) {
238                                 ret_val = new DataRange();
239                                 for (ii = 0; ii < row_count; ii++) {
240                                         data    = store_data->get(ii);
241                                         if (data != NULL) {
242                                                 if (calc == NULL) {
243                                                         calc            = data->clone();
244                                                         limit_d         = data->get_date().clone();
245                                                         limit_d->min    = 0;
246                                                         limit_d->sec    = 0;
247                                                         limit_d->inc_seconds(frq_sec);
248                                                 }
249                                                 date    = data->get_date();
250                                                 if ((ii <= (row_count -1)) &&
251                                                     ((frq_sec == -1) || (date.before(limit_d)))) {
252                                                         for (jj = 0; jj < col_count; jj++) {
253                                                                 calc->value_arr[jj]     = calc->value_arr[jj] + data->value_arr[jj];
254                                                         }
255                                                 }
256                                                 if ((ii >= (row_count -1)) ||
257                                                     ((frq_sec != -1) && (date.before(limit_d) == false))) {
258                                                         ret_val->add(calc);
259                                                         delete(calc);
260                                                         calc    = data->clone();
261                                                         if (limit_d != NULL) {
262                                                                 delete(limit_d);
263                                                         }
264                                                         limit_d         = data->get_date().clone();
265                                                         limit_d->min    = 0;
266                                                         limit_d->sec    = 0;
267                                                         limit_d->inc_seconds(frq_sec);
268                                                 }
269                                                 delete(data);
270                                         }
271                                 }
272                                 if (calc != NULL) {
273                                         delete(calc);
274                                         calc    = NULL;
275                                 }
276                                 if (limit_d != NULL) {
277                                         delete(limit_d);
278                                 }
279                         }
280                 }
281         }
282         return ret_val;
283 }
284
285 plp::DataRange *StoreDay::get_mean(EnumSummaryPeriod period_type_param) {
286         int             row_count;
287         int             col_count;
288         int             d_count;
289         int             jj;
290         int             ii;
291         Data            *data;
292         Data            *calc;
293         Date            *limit_d;
294         Date            date;
295         DataRange       *ret_val;
296         int             frq_sec;
297         bool            succ;
298
299         ret_val = NULL;
300         calc    = NULL;
301         limit_d = NULL;
302         d_count = 1;
303         frq_sec = get_summary_period_as_freq_seconds(period_type_param);
304         if (store_data == NULL) {
305                 succ    = load();
306         }
307         if ((succ == true) &&
308             (store_data != NULL)) {
309                 row_count       = store_data->get_count();
310                 if (row_count > 0) {
311                         col_count       = store_data->get_data_item_value_count();
312                         if (col_count > 0) {
313                                 ret_val = new DataRange();
314                                 for (ii = 0; ii < row_count; ii++) {
315                                         data    = store_data->get(ii);
316                                         if (data != NULL) {
317                                                 if (calc == NULL) {
318                                                         d_count         = 1;
319                                                         calc            = data->clone();
320                                                         limit_d         = data->get_date().clone();
321                                                         limit_d->min    = 0;
322                                                         limit_d->sec    = 0;
323                                                         limit_d->inc_seconds(frq_sec);
324                                                 }
325                                                 date    = data->get_date();
326                                                 if ((ii <= (row_count -1)) &&
327                                                     ((frq_sec == -1) || (date.before(limit_d)))) {
328                                                         for (jj = 0; jj < col_count; jj++) {
329                                                                 calc->value_arr[jj]     = calc->value_arr[jj] + data->value_arr[jj];
330                                                         }
331                                                         d_count++;
332                                                 }
333                                                 if ((ii >= (row_count -1)) ||
334                                                     ((frq_sec != -1) && (date.before(limit_d) == false))) {
335                                                         for (jj = 0; jj < col_count; jj++) {
336                                                                 calc->value_arr[jj]     = calc->value_arr[jj] / d_count;
337                                                         }
338                                                         ret_val->add(calc);
339                                                         delete(calc);
340                                                         d_count         = 1;
341                                                         calc            = data->clone();
342                                                         if (limit_d != NULL) {
343                                                                 delete(limit_d);
344                                                         }
345                                                         limit_d         = data->get_date().clone();
346                                                         limit_d->min    = 0;
347                                                         limit_d->sec    = 0;
348                                                         limit_d->inc_seconds(frq_sec);
349                                                 }
350                                                 delete(data);
351                                         }
352                                 }
353                                 if (calc != NULL) {
354                                         delete(calc);
355                                         calc    = NULL;
356                                 }
357                                 if (limit_d != NULL) {
358                                         delete(limit_d);
359                                 }
360                         }
361                 }
362         }
363         return ret_val;
364 }
365
366 plp::DataRange *StoreDay::get_delta(EnumSummaryPeriod period_type_param) {
367         int             row_count;
368         int             col_count;
369         int             jj;
370         int             ii;
371         Data            *data;
372         Data            *calc1;
373         Data            *calc2;
374         Date            *limit_d;
375         Date            date;
376         DataRange       *ret_val;
377         int             frq_sec;
378         bool            succ;
379
380         ret_val = NULL;
381         calc1   = NULL;
382         calc2   = NULL;
383         limit_d = NULL;
384         frq_sec = get_summary_period_as_freq_seconds(period_type_param);
385         if (store_data == NULL) {
386                 succ    = load();
387         }
388         if ((succ == true) &&
389             (store_data != NULL)) {
390                 row_count       = store_data->get_count();
391                 if (row_count > 0) {
392                         col_count       = store_data->get_data_item_value_count();
393                         if (col_count > 0) {
394                                 ret_val = new DataRange();
395                                 for (ii = 0; ii < row_count; ii++) {
396                                         data    = store_data->get(ii);
397                                         if (data != NULL) {
398                                                 if (calc1 == NULL) {
399                                                         calc1           = data->clone();
400                                                         limit_d         = data->get_date().clone();
401                                                         limit_d->min    = 0;
402                                                         limit_d->sec    = 0;
403                                                         limit_d->inc_seconds(frq_sec);
404                                                         if (calc2 != NULL) {
405                                                                 delete(calc2);
406                                                         }
407                                                         calc2           = NULL;
408                                                 }
409                                                 date    = data->get_date();
410                                                 if ((ii <= (row_count -1)) &&
411                                                     ((frq_sec == -1) || (date.before(limit_d)))) {
412                                                         if (calc2 != NULL) {
413                                                                 delete(calc2);
414                                                         }
415                                                         calc2   = data->clone();
416                                                 }
417                                                 if ((ii >= (row_count -1)) ||
418                                                     ((frq_sec != -1) && (date.before(limit_d) == false))) {
419                                                         if (calc2 == NULL) {
420                                                                 calc2   = calc1->clone();
421                                                         }
422                                                         for (jj = 0; jj < col_count; jj++) {
423                                                                 calc2->value_arr[jj]    = calc2->value_arr[jj] - calc1->value_arr[jj];
424                                                         }
425                                                         ret_val->add(calc2);
426                                                         delete(calc1);
427                                                         calc1   = data->clone();
428                                                         delete(calc2);
429                                                         calc2   = NULL;
430                                                         if (limit_d != NULL) {
431                                                                 delete(limit_d);
432                                                         }
433                                                         limit_d         = data->get_date().clone();
434                                                         limit_d->min    = 0;
435                                                         limit_d->sec    = 0;
436                                                         limit_d->inc_seconds(frq_sec);
437                                                 }
438                                                 delete(data);
439                                         }
440                                 }
441                                 if (calc1 != NULL) {
442                                         delete(calc1);
443                                         calc1   = NULL;
444                                 }
445                                 if (calc2 != NULL) {
446                                         delete(calc2);
447                                         calc2   = NULL;
448                                 }
449                                 if (limit_d != NULL) {
450                                         delete(limit_d);
451                                 }
452                         }
453                 }
454         }
455         return ret_val;
456 }
457
458 plp::DataRange *StoreDay::get_max_or_min(EnumSummaryPeriod period_type_param, bool max) {
459         int             row_count;
460         int             col_count;
461         int             jj;
462         int             ii;
463         Data            *data;
464         Data            *calc;
465         Date            *limit_d;
466         Date            date;
467         DataRange       *ret_val;
468         int             frq_sec;
469         bool            succ;
470
471         ret_val = NULL;
472         calc    = NULL;
473         limit_d = NULL;
474         frq_sec = get_summary_period_as_freq_seconds(period_type_param);
475         if (store_data == NULL) {
476                 succ    = load();
477         }
478         if ((succ == true) &&
479             (store_data != NULL)) {
480                 row_count       = store_data->get_count();
481                 if (row_count > 0) {
482                         col_count       = store_data->get_data_item_value_count();
483                         if (col_count > 0) {
484                                 ret_val = new DataRange();
485                                 for (ii = 0; ii < row_count; ii++) {
486                                         data    = store_data->get(ii);
487                                         if (data != NULL) {
488                                                 if (calc == NULL) {
489                                                         calc            = data->clone();
490                                                         limit_d         = data->get_date().clone();
491                                                         limit_d->min    = 0;
492                                                         limit_d->sec    = 0;
493                                                         limit_d->inc_seconds(frq_sec);
494                                                 }
495                                                 date    = data->get_date();
496                                                 if ((ii <= (row_count -1)) &&
497                                                     ((frq_sec == -1) || (date.before(limit_d)))) {
498                                                         int changed = 0;
499                                                         if (max == true) {
500                                                                 for (jj = 0; jj < col_count; jj++) {
501                                                                         if (calc->value_arr[jj] < data->value_arr[jj]) {
502                                                                                 calc->value_arr[jj]     = data->value_arr[jj];
503                                                                                 changed = 1;
504                                                                         }
505                                                                 }
506                                                         }
507                                                         else {
508                                                                 for (jj = 0; jj < col_count; jj++) {
509                                                                         if (data->value_arr[jj] < calc->value_arr[jj]) {
510                                                                                 calc->value_arr[jj]     = data->value_arr[jj];
511                                                                                 changed = 1;
512                                                                         }
513                                                                 }
514                                                         }
515                                                         if (changed == 1) {
516                                                                 Date new_date;
517
518                                                                 new_date        = data->get_date();
519                                                                 calc->set_date(&new_date);
520                                                         }
521                                                 }
522                                                 if ((ii >= (row_count -1)) ||
523                                                     ((frq_sec != -1) && (date.before(limit_d) == false))) {
524                                                         ret_val->add(calc);
525                                                         delete(calc);
526                                                         calc    = data->clone();
527                                                         if (limit_d != NULL) {
528                                                                 delete(limit_d);
529                                                         }
530                                                         limit_d         = data->get_date().clone();
531                                                         limit_d->min    = 0;
532                                                         limit_d->sec    = 0;
533                                                         limit_d->inc_seconds(frq_sec);
534                                                 }
535                                                 delete(data);
536                                         }
537                                 }
538                                 if (calc != NULL) {
539                                         delete(calc);
540                                         calc    = NULL;
541                                 }
542                                 if (limit_d != NULL) {
543                                         delete(limit_d);
544                                 }
545                         }
546                 }
547         }
548         return ret_val;
549 }
550
551 plp::DataRange *StoreDay::get_max(EnumSummaryPeriod period_type_param) {
552         DataRange       *ret_val;
553
554         ret_val = get_max_or_min(period_type_param, true);
555         return ret_val;
556 }
557
558 plp::DataRange *StoreDay::get_min(EnumSummaryPeriod period_type_param) {
559         DataRange       *ret_val;
560
561         ret_val = get_max_or_min(period_type_param, false);
562         return ret_val;
563 }
564
565 DataRange *StoreDay::get_oldest_and_latest_data(string fname_param) {
566         DataRange       *ret_val;
567         ifstream        in;
568         Data            *o_data;
569         Data            *n_data;
570         string          latest;
571         int             row_count;
572         string          line;
573         string          prev_line;
574
575         ret_val = NULL;
576         o_data  = NULL;
577         n_data  = NULL;
578         if (store_data != NULL) {
579                 row_count       = store_data->get_count();
580                 if (row_count > 0) {
581                         o_data  = store_data->get(0);
582                         n_data  = store_data->get(row_count - 1);
583                 }
584         }
585         else {
586                 if (range_data != NULL) {
587                         row_count       = range_data->get_count();
588                         if (row_count > 0) {
589                                 o_data  = range_data->get(0);
590                                 n_data  = range_data->get(row_count - 1);
591                         }
592                 }
593                 else {
594                         in.open(fname_param.c_str());
595                         if (in.is_open() == true) {
596                                 while (in.eof() == false) {
597                                         getline(in, line);
598                                         if (line.empty() == false) {
599                                                 if (o_data == NULL) {
600                                                         o_data  = Data::parse_string(line);
601                                                 }
602                                                 prev_line       = line;
603                                         }
604                                 }
605                                 if (prev_line.empty() == false) {
606                                         n_data  = Data::parse_string(prev_line);
607                                 }
608                         }
609                 }
610         }
611         if ((o_data != NULL) &&
612             (n_data != NULL)) {
613                 ret_val = new DataRange(o_data);
614                 ret_val->add(n_data);
615                 if (range_data != NULL) {
616                         range_data      = new DataRange(o_data);
617                         range_data->add(n_data);
618                 }
619         }
620         if (o_data != NULL) {
621                 delete(o_data);
622         }
623         if (n_data != NULL) {
624                 delete(n_data);
625         }
626         return ret_val;
627 }
628
629 DataRange *StoreDay::get_oldest_and_latest_data() {
630         return get_oldest_and_latest_data(store_fname);
631 }
632
633 Data *StoreDay::get_oldest_data() {
634         int             row_count;
635         Data            *ret_val;
636         DataRange       *dr;
637
638         ret_val = NULL;
639         dr      = get_oldest_and_latest_data();
640         if (dr != NULL) {
641                 row_count       = dr->get_count();
642                 if (row_count >= 1) {
643                         ret_val = dr->get(0);
644                 }
645                 delete(dr);
646         }
647         return ret_val;
648 }
649
650 Data *StoreDay::get_latest_data() {
651         int             row_count;
652         Data            *ret_val;
653         DataRange       *dr;
654
655         ret_val = NULL;
656         dr      = get_oldest_and_latest_data();
657         if (dr != NULL) {
658                 row_count       = dr->get_count();
659                 if (row_count == 2) {
660                         ret_val = dr->get(1);
661                 }
662                 delete(dr);
663         }
664         return ret_val;
665 }
666
667 bool StoreDay::data_day_scan_days_in_month(string dev_id_param,
668                                 Date *new_date,
669                                 Date *max_date) {
670         bool    ret_val;
671         string  fname;
672
673         ret_val = false;
674         while((ret_val == false) &&
675               (new_date->before(max_date))) {
676                 new_date->next_day();
677                 fname   = get_file_name(dev_id_param, new_date);
678                 if (exist(fname, false) == true) {
679                         ret_val = true;
680                         break;
681                 }
682                 if (new_date->is_last_day_of_month() == true) {
683                         break;
684                 }
685         }
686         return ret_val;
687 }
688
689 bool StoreDay::data_day_scan_month_in_year(string dev_id_param,
690                                 Date *new_date,
691                                 Date *max_date) {
692         bool    ret_val;
693
694         ret_val = false;
695         // next scan months dir existence under the first year
696         while((ret_val == false) &&
697               (new_date->before(max_date))) {
698                 new_date->next_month();
699                 if (exist_in_month(dev_id_param,
700                                 new_date,
701                                 false)) {
702                         ret_val = data_day_scan_days_in_month(dev_id_param,
703                                                         new_date,
704                                                         max_date);
705                         if (ret_val == true)
706                                 break;
707                 }
708                 if (new_date->month == 12)
709                         break;
710         }
711         return ret_val;
712 }
713
714 bool StoreDay::data_day_scan_years(string dev_id_param,
715                         Date *new_date,
716                         Date *max_date) {
717         bool    ret_val;
718
719         ret_val = false;
720         while((ret_val == false) &&
721               (new_date->before(max_date))) {
722                 new_date->next_year();
723                 if (exist_in_year(dev_id_param,
724                                 new_date,
725                                 false)) {
726                         ret_val = data_day_scan_month_in_year(dev_id_param,
727                                                         new_date,
728                                                         max_date);
729                         if (ret_val == true)
730                                 break;
731                 }
732         }
733         return ret_val;
734 }
735
736 bool StoreDay::get_next_date_with_data(std::string dev_id_param,
737                                 plp::Date *next_date,
738                                 plp::Date *max_date) {
739         bool    ret_val;
740         Date    *new_date;
741         string  fname;
742         string  dirname;
743
744         new_date        = next_date->clone();
745         // scan first dates in current month
746         ret_val         = data_day_scan_days_in_month(dev_id_param,
747                                                 new_date,
748                                                 max_date);
749         if (ret_val == false) {
750                 ret_val = data_day_scan_month_in_year(dev_id_param,
751                                                 new_date,
752                                                 max_date);
753                 if (ret_val == false) {
754                         ret_val = data_day_scan_years(dev_id_param,
755                                                 new_date,
756                                                 max_date);
757                 }
758         }
759         if (ret_val == true)
760                 new_date->copy(next_date);
761         else
762                 max_date->copy(next_date);
763         delete(new_date);
764         return ret_val;
765 }