]> pilppa.org Git - libplp.git/blob - src/StoreCache.cc
d95c9fb0fdf72cc74610df68cc1793825f7b7427
[libplp.git] / src / StoreCache.cc
1 /*
2  * StoreCache.cc
3  *
4  *  Created on: Jan 6, 2011
5  *      Author: lamikr
6  */
7 #include <sstream>
8 #include <fstream>
9
10 #include "log.h"
11 #include "Store.hh"
12 #include "StoreCache.hh"
13 #include "StoreDay.hh"
14 #include "DeviceConfig.hh"
15 #include "FileUtil.hh"
16
17 using namespace std;
18 using namespace plp;
19
20 StoreCache::StoreCache(string device_id_param,
21         Date *date_time_param): Store(device_id_param, date_time_param) {
22 }
23
24 StoreCache::~StoreCache() {
25 }
26
27 string StoreCache::get_dir_name(string device_id_param,
28                                 Date *date_time_param,
29                                 EnumSummaryPeriod period_type_param,
30                                 EnumSummaryCalculationType calc_type_param) {
31         string  ret_val;
32         char    buffer[30];
33         string  bd_name;
34         string  period_name;
35         string  calc_type;
36
37         period_name     = DataSummary::get_summary_period_name(period_type_param);
38         calc_type       = DataSummary::get_summary_calculation_name(calc_type_param);
39
40         bd_name = DeviceConfig::get_base_dir_name();
41         bd_name = FileUtil::concat_paths(bd_name, CACHE_DIR_NAME);
42         bd_name = FileUtil::concat_paths(bd_name, device_id_param);
43         bd_name = FileUtil::concat_paths(bd_name, period_name);
44         bd_name = FileUtil::concat_paths(bd_name, calc_type);
45         if (period_type_param == PERIOD_YEARLY) {
46                 ret_val = bd_name;
47         }
48         else if (period_type_param == PERIOD_MONTHLY) {
49                 snprintf(buffer, 30, "%d", date_time_param->year);
50                 ret_val = bd_name + "/" + buffer;
51         }
52         else {
53                 snprintf(buffer, 30, "%d/%02d", date_time_param->year, date_time_param->month);
54                 ret_val = bd_name + "/" + buffer;
55         }
56         return ret_val;
57 }
58
59 string StoreCache::get_file_name(string device_id_param,
60                                 Date *date_time_param,
61                                 EnumSummaryPeriod period_type_param,
62                                 EnumSummaryCalculationType calc_type_param) {
63         string  ret_val;
64         string  fname;
65         char    buffer[30];
66
67         if (period_type_param == PERIOD_YEARLY) {
68                 snprintf(buffer, 30, "%d", date_time_param->year);
69         }
70         else if (period_type_param == PERIOD_MONTHLY) {
71                 snprintf(buffer, 30, "%d-%02d",
72                         date_time_param->year,
73                         date_time_param->month);
74         }
75         else {
76                 snprintf(buffer, 30, "%d-%02d-%02d",
77                         date_time_param->year,
78                         date_time_param->month,
79                         date_time_param->day);
80         }
81         fname   = buffer;
82         fname   = fname + DATAFILE_SUFFIX;
83         ret_val = get_dir_name(device_id_param, date_time_param, period_type_param, calc_type_param);
84         ret_val = FileUtil::concat_paths(ret_val, fname);
85         return ret_val;
86 }
87
88 plp::Date *StoreCache::get_scanning_limit_date(EnumSummaryPeriod period_type_param) {
89         Data    *cur_data;;
90         Date    *ret_val;
91
92         cur_data        = get_latest_data(date, device_id, period_type_param);
93         if (cur_data != NULL) {
94                 ret_val = cur_data->get_date().clone();
95                 ret_val->next_second();
96                 delete(cur_data);
97                 cur_data        = NULL;
98         }
99         else {
100                 ret_val = date->clone();
101                 if (period_type_param == PERIOD_YEARLY) {
102                         ret_val->next_year();
103                 }
104                 else {
105                         ret_val->next_month();
106                 }
107         }
108         return ret_val;
109 }
110
111 DataRange *StoreCache::get_mean(EnumSummaryPeriod period_type_param) {
112         int             row_count;
113         DataRange       *ret_val;
114         Data            *dta;
115         string          fname;
116
117         ret_val = NULL;
118         fname   = get_file_name(device_id,
119                                 date,
120                                 period_type_param,
121                                 MEAN);
122         if (store_data == NULL) {
123                 if (access(fname.c_str(), R_OK) == 0) {
124                         load(fname);
125                 }
126         }
127         if (store_data != NULL) {
128                 row_count       = store_data->get_count();
129                 if (row_count > 0) {
130                         ret_val = new DataRange();
131                         dta     = store_data->get(0);
132                         ret_val->add(dta);
133                         delete(dta);
134                 }
135         }
136         if (ret_val == NULL) {
137                 switch(period_type_param) {
138                         case PERIOD_YEARLY:
139                         case PERIOD_MONTHLY:
140                         {
141                                         Data            *cur_data;
142                                         Data            *res_data;
143                                         Date            *cur_date;
144                                         Date            *max_date;
145                                         int             ii;
146                                         int             cnt;
147                                         int             val_cnt;
148                                         DataRange       *dr;
149                                         Store           *store;
150
151                                         cur_date        = date->clone();
152                                         max_date        = get_scanning_limit_date(period_type_param);
153                                         cur_data        = NULL;
154                                         res_data        = NULL;
155                                         cnt             = 0;
156                                         val_cnt         = 0;
157                                         dr              = NULL;
158                                         while(cur_date->before(max_date)) {
159                                                 if (period_type_param == PERIOD_YEARLY) {
160                                                         store   = new StoreCache(device_id, cur_date);
161                                                         dr      = store->get_mean(PERIOD_MONTHLY);
162                                                 }
163                                                 else {
164                                                         if (StoreDay::exist(device_id, cur_date, false)) {
165                                                                 store   = new StoreDay(device_id, cur_date);
166                                                                 dr      = store->get_mean(PERIOD_DAILY);
167                                                         }
168                                                         if (dr == NULL) {
169                                                                 // data not found for that day, try to find next date containing data
170                                                                 StoreDay::get_next_date_with_data(device_id,
171                                                                                         cur_date,
172                                                                                         max_date);
173                                                                 continue;
174                                                         }
175                                                 }
176                                                 if (dr != NULL) {
177                                                         cur_data        = dr->get_first();
178                                                         if (cur_data != NULL) {
179                                                                 cnt++;
180                                                                 if (res_data == NULL) {
181                                                                         res_data        = cur_data;
182                                                                         val_cnt         = res_data->get_value_count();
183                                                                 }
184                                                                 else {
185                                                                         for (ii = 0; ii < val_cnt; ii++) {
186                                                                                 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
187                                                                         }
188                                                                         delete(cur_data);
189                                                                 }
190                                                         }
191                                                         delete(dr);
192                                                 }
193                                                 delete(store);
194                                                 if (period_type_param == PERIOD_YEARLY) {
195                                                         cur_date->next_month();
196                                                 }
197                                                 else {
198                                                         cur_date->next_day();
199                                                 }
200                                         }
201                                         if ((res_data != NULL) &&
202                                             (cnt > 0)) {
203                                                 for (ii = 0; ii < val_cnt; ii++) {
204                                                         res_data->value_arr[ii] = res_data->value_arr[ii] / cnt;
205                                                 }
206                                                 ret_val = new DataRange(res_data);
207                                                 save(fname, ret_val, 4);
208                                                 delete(res_data);
209                                         }
210                                         delete(cur_date);
211                                         delete(max_date);
212                                 }
213                                 break;
214                         case PERIOD_DAILY:
215                         case PERIOD_HOURLY:
216                         case PERIOD_MINUTELY:
217                         case PERIOD_SECONDLY:
218                                 if (StoreDay::exist(device_id, date, false)) {
219                                         StoreDay        *store;
220
221                                         store   = new StoreDay(device_id, date);
222                                         ret_val = store->get_mean(period_type_param);
223                                         if ((ret_val != NULL) &&
224                                             (period_type_param != PERIOD_MINUTELY) &&
225                                             (period_type_param != PERIOD_SECONDLY)) {
226                                                 // no need cache second or minute data
227                                                 save(fname, ret_val, 4);
228                                         }
229                                         delete(store);
230                                 }
231                                 break;
232                 }
233         }
234         return ret_val;
235 }
236
237 DataRange *StoreCache::get_sum(EnumSummaryPeriod period_type_param) {
238         int             row_count;
239         DataRange       *ret_val;
240         Data            *dta;
241         string          fname;
242         Store           *store;
243
244         ret_val = NULL;
245         fname   = get_file_name(device_id,
246                                 date,
247                                 period_type_param,
248                                 SUM);
249         if (store_data == NULL) {
250                 if (access(fname.c_str(), R_OK) == 0) {
251                         load(fname);
252                 }
253         }
254         if (store_data != NULL) {
255                 row_count       = store_data->get_count();
256                 if (row_count > 0) {
257                         ret_val = new DataRange();
258                         dta     = store_data->get(0);
259                         ret_val->add(dta);
260                         delete(dta);
261                 }
262         }
263         if (ret_val == NULL) {
264                 switch(period_type_param) {
265                         case PERIOD_YEARLY:
266                         case PERIOD_MONTHLY: {
267                                         Data            *cur_data;
268                                         Data            *res_data;
269                                         Date            *cur_date;
270                                         Date            *max_date;
271                                         int             ii;
272                                         int             cnt;
273                                         int             val_cnt;
274                                         DataRange       *dr;
275
276                                         cur_date        = date->clone();
277                                         max_date        = get_scanning_limit_date(period_type_param);
278                                         cur_data        = NULL;
279                                         res_data        = NULL;
280                                         cnt             = 0;
281                                         while(cur_date->before(max_date)) {
282                                                 if (period_type_param == PERIOD_YEARLY) {
283                                                         store   = new StoreCache(device_id, cur_date);
284                                                         dr      = store->get_sum(PERIOD_MONTHLY);
285                                                 }
286                                                 else {
287                                                         if (StoreDay::exist(device_id, cur_date, false)) {
288                                                                 store   = new StoreDay(device_id, cur_date);
289                                                                 dr      = store->get_sum(PERIOD_DAILY);
290                                                         }
291                                                         if (dr == NULL) {
292                                                                 // data not found for that day, try to find next date containing data
293                                                                 StoreDay::get_next_date_with_data(device_id,
294                                                                                                 cur_date,
295                                                                                                 max_date);
296                                                                 continue;
297                                                         }
298                                                 }
299                                                 if (dr != NULL) {
300                                                         cur_data        = dr->get_first();
301                                                         if (cur_data != NULL) {
302                                                                 cnt++;
303                                                                 if (res_data == NULL) {
304                                                                         res_data        = cur_data;
305                                                                 }
306                                                                 else {
307                                                                         val_cnt = res_data->get_value_count();
308                                                                         for (ii = 0; ii < val_cnt; ii++) {
309                                                                                 res_data->value_arr[ii] = res_data->value_arr[ii] + cur_data->value_arr[ii];
310                                                                         }
311                                                                         delete(cur_data);
312                                                                 }
313                                                         }
314                                                         delete(dr);
315                                                 }
316                                                 delete(store);
317                                                 if (period_type_param == PERIOD_YEARLY) {
318                                                         cur_date->next_month();
319                                                 }
320                                                 else {
321                                                         cur_date->next_day();
322                                                 }
323                                         }
324                                         if ((res_data != NULL) &&
325                                             (cnt > 0)) {
326                                                 ret_val = new DataRange(res_data);
327                                                 save(fname, ret_val, 4);
328                                                 delete(res_data);
329                                         }
330                                         delete(cur_date);
331                                         delete(max_date);
332                                 }
333                                 break;
334                         case PERIOD_DAILY:
335                         case PERIOD_HOURLY:
336                         case PERIOD_MINUTELY:
337                         case PERIOD_SECONDLY:
338                                 if (StoreDay::exist(device_id, date, false)) {
339                                         store   = new StoreDay(device_id, date);
340                                         ret_val = store->get_sum(period_type_param);
341                                         if ((ret_val != NULL) &&
342                                             (period_type_param != PERIOD_MINUTELY) &&
343                                             (period_type_param != PERIOD_SECONDLY)) {
344                                                 // no need cache second or minute data
345                                                 save(fname, ret_val, 4);
346                                         }
347                                         delete(store);
348                                 }
349                                 break;
350                 }
351         }
352         return ret_val;
353 }
354
355 DataRange *StoreCache::get_delta(EnumSummaryPeriod period_type_param) {
356         int             row_count;
357         DataRange       *ret_val;
358         Data            *dta;
359         string          fname;
360         StoreDay        *store;
361
362         ret_val = NULL;
363         fname   = get_file_name(device_id,
364                                 date,
365                                 period_type_param,
366                                 DELTA);
367         if (store_data == NULL) {
368                 if (access(fname.c_str(), R_OK) == 0) {
369                         // read from cache file
370                         load(fname);
371                 }
372         }
373         if (store_data != NULL) {
374                 row_count       = store_data->get_count();
375                 if (row_count > 0) {
376                         ret_val = new DataRange();
377                         dta     = store_data->get(0);
378                         ret_val->add(dta);
379                         delete(dta);
380                 }
381         }
382         if (ret_val == NULL) {
383                 switch(period_type_param) {
384                         case PERIOD_YEARLY: {
385                                         Data    *first_data;
386                                         Data    *last_data;
387                                         int     ii;
388                                         int     cnt;
389
390                                         first_data      = get_oldest_data(date, device_id, PERIOD_YEARLY);
391                                         if (first_data != NULL) {
392                                                 last_data       = get_latest_data(date, device_id, PERIOD_YEARLY);
393                                                 if (last_data != NULL) {
394                                                         ret_val         = new DataRange();
395                                                         cnt             = last_data->get_value_count();
396                                                         for (ii = 0; ii < cnt; ii++) {
397                                                                 last_data->value_arr[ii]        = last_data->value_arr[ii] - first_data->value_arr[ii];
398                                                         }
399                                                         ret_val->add(last_data);
400                                                         delete(last_data);
401                                                 }
402                                                 delete(first_data);
403                                                 save(fname, ret_val, 4);
404                                         }
405                                         else {
406                                                 log_error("Could not read first or last data item from device %s for year: %d", device_id.c_str(), date->year);
407                                         }
408                                 }
409                                 break;
410                         case PERIOD_MONTHLY: {
411                                         Data    *first_data;
412                                         Data    *last_data;
413                                         Data    *cur_data;
414                                         Date    *cur_date;
415                                         Date    *max_date;
416                                         int     ii;
417                                         int     cnt;
418
419                                         cur_date        = date->clone();
420                                         max_date        = date->clone();
421                                         max_date->next_month();
422                                         first_data      = NULL;
423                                         last_data       = NULL;
424                                         while(cur_date->before(max_date)) {
425                                                 if (StoreDay::exist(device_id,
426                                                                 cur_date,
427                                                                 false)) {
428                                                         store   = new StoreDay(device_id, cur_date);
429                                                         if (first_data == NULL) {
430                                                                 cur_data        = store->get_oldest_data();
431                                                                 if (cur_data != NULL) {
432                                                                         first_data      = cur_data->clone();
433                                                                         last_data       = cur_data->clone();
434                                                                         delete(cur_data);
435                                                                 }
436                                                         }
437                                                         cur_data        = store->get_latest_data();
438                                                         if (cur_data != NULL) {
439                                                                 if (last_data != NULL) {
440                                                                         delete(last_data);
441                                                                 }
442                                                                 last_data       = cur_data;
443                                                         }
444                                                         delete(store);
445                                                         cur_date->next_day();
446                                                 }
447                                                 else {
448                                                         // data not found for that day, try to find next date containing data
449                                                         StoreDay::get_next_date_with_data(device_id,
450                                                                                 cur_date,
451                                                                                 max_date);
452                                                 }
453                                         }
454                                         delete(cur_date);
455                                         delete(max_date);
456                                         if (first_data != NULL) {
457                                                 if (last_data == NULL) {
458                                                         last_data       = first_data->clone();
459                                                 }
460                                                 cnt     = last_data->get_value_count();
461                                                 for (ii = 0; ii < cnt; ii++) {
462                                                         last_data->value_arr[ii]        = last_data->value_arr[ii] - first_data->value_arr[ii];
463                                                 }
464                                                 cur_date        = first_data->get_date().clone();
465                                                 last_data->set_date(cur_date);
466                                                 delete(cur_date);
467                                                 ret_val = new DataRange(last_data);
468                                                 delete(first_data);
469                                                 delete(last_data);
470                                                 save(fname, ret_val, 4);
471                                         }
472                                 }
473                                 break;
474                         case PERIOD_DAILY:
475                         case PERIOD_HOURLY:
476                         case PERIOD_MINUTELY:
477                         case PERIOD_SECONDLY:
478                                 if (StoreDay::exist(device_id, date, false)) {
479                                         store   = new StoreDay(device_id, date);
480                                         ret_val = store->get_delta(period_type_param);
481                                         if ((period_type_param != PERIOD_MINUTELY) ||
482                                             (period_type_param != PERIOD_SECONDLY)) {
483                                                 // no need cache second or minute data
484                                                 save(fname, ret_val, 4);
485                                         }
486                                         delete(store);
487                                 }
488                                 break;
489                 }
490         }
491         return ret_val;
492 }
493
494 DataRange *StoreCache::get_max(EnumSummaryPeriod period_type_param) {
495         int             row_count;
496         DataRange       *ret_val;
497         Data            *dta;
498         string          fname;
499         Store           *store;
500
501         ret_val = NULL;
502         fname   = get_file_name(device_id,
503                                 date,
504                                 period_type_param,
505                                 MAX);
506         if (store_data == NULL) {
507                 if (access(fname.c_str(), R_OK) == 0) {
508                         load(fname);
509                 }
510         }
511         if (store_data != NULL) {
512                 row_count       = store_data->get_count();
513                 if (row_count > 0) {
514                         ret_val = new DataRange();
515                         dta     = store_data->get(0);
516                         ret_val->add(dta);
517                         delete(dta);
518                 }
519         }
520         if (ret_val == NULL) {
521                 switch(period_type_param) {
522                         case PERIOD_YEARLY:
523                         case PERIOD_MONTHLY: {
524                                         Data            *cur_data;
525                                         Data            *res_data;
526                                         Date            *cur_date;
527                                         Date            *max_date;
528                                         int             ii;
529                                         int             cnt;
530                                         int             val_cnt;
531                                         DataRange       *dr;
532
533                                         cur_date        = date->clone();
534                                         max_date        = get_scanning_limit_date(period_type_param);
535                                         cur_data        = NULL;
536                                         res_data        = NULL;
537                                         cnt             = 0;
538                                         while(cur_date->before(max_date)) {
539                                                 if (period_type_param == PERIOD_YEARLY) {
540                                                         store   = new StoreCache(device_id, cur_date);
541                                                         dr      = store->get_max(PERIOD_MONTHLY);
542                                                 }
543                                                 else {
544                                                         if (StoreDay::exist(device_id, cur_date, false)) {
545                                                                 store   = new StoreDay(device_id, cur_date);
546                                                                 dr      = store->get_max(PERIOD_DAILY);
547                                                         }
548                                                         else {
549                                                                 StoreDay::get_next_date_with_data(device_id,
550                                                                                                 cur_date,
551                                                                                                 max_date);
552                                                                 continue;
553                                                         }
554                                                 }
555                                                 if (dr != NULL) {
556                                                         cur_data        = dr->get_first();
557                                                         if (cur_data != NULL) {
558                                                                 cnt++;
559                                                                 if (res_data == NULL) {
560                                                                         res_data        = cur_data;
561                                                                 }
562                                                                 else {
563                                                                         val_cnt = res_data->get_value_count();
564                                                                         int changed = 0;
565                                                                         for (ii = 0; ii < val_cnt; ii++) {
566                                                                                 if (cur_data->value_arr[ii] > res_data->value_arr[ii]) {
567                                                                                         res_data->value_arr[ii] = cur_data->value_arr[ii];
568                                                                                         changed = 1;
569                                                                                 }
570                                                                         }
571                                                                         if (changed == 1) {
572                                                                                 Date new_date;
573
574                                                                                 new_date        = cur_data->get_date();
575                                                                                 res_data->set_date(&new_date);
576                                                                         }
577                                                                         delete(cur_data);
578                                                                 }
579                                                         }
580                                                         delete(dr);
581                                                 }
582                                                 delete(store);
583                                                 if (period_type_param == PERIOD_YEARLY) {
584                                                         cur_date->next_month();
585                                                 }
586                                                 else {
587                                                         cur_date->next_day();
588                                                 }
589                                         }
590                                         if ((res_data != NULL) &&
591                                             (cnt > 0)) {
592                                                 ret_val = new DataRange(res_data);
593                                                 save(fname, ret_val, 4);
594                                                 delete(res_data);
595                                         }
596                                         delete(cur_date);
597                                         delete(max_date);
598                                 }
599                                 break;
600                         case PERIOD_DAILY:
601                         case PERIOD_HOURLY:
602                         case PERIOD_MINUTELY:
603                         case PERIOD_SECONDLY:
604                                 if (StoreDay::exist(device_id, date, false)) {
605                                         store   = new StoreDay(device_id, date);
606                                         ret_val = store->get_max(period_type_param);
607                                         if ((period_type_param != PERIOD_MINUTELY) ||
608                                             (period_type_param != PERIOD_SECONDLY)) {
609                                                 // no need cache second or minute data
610                                                 save(fname, ret_val, 4);
611                                         }
612                                         delete(store);
613                                 }
614                                 break;
615                 }
616         }
617         return ret_val;
618 }
619
620 DataRange *StoreCache::get_min(EnumSummaryPeriod period_type_param) {
621         int             row_count;
622         DataRange       *ret_val;
623         Data            *dta;
624         string          fname;
625         Store           *store;
626
627         ret_val = NULL;
628         fname   = get_file_name(device_id,
629                                 date,
630                                 period_type_param,
631                                 MIN);
632         if (store_data == NULL) {
633                 if (access(fname.c_str(), R_OK) == 0) {
634                         load(fname);
635                 }
636         }
637         if (store_data != NULL) {
638                 row_count       = store_data->get_count();
639                 if (row_count > 0) {
640                         ret_val = new DataRange();
641                         dta     = store_data->get(0);
642                         ret_val->add(dta);
643                         delete(dta);
644                 }
645         }
646         if (ret_val == NULL) {
647                 switch(period_type_param) {
648                         case PERIOD_YEARLY:
649                         case PERIOD_MONTHLY: {
650                                         Data            *cur_data;
651                                         Data            *res_data;
652                                         Date            *cur_date;
653                                         Date            *max_date;
654                                         int             ii;
655                                         int             cnt;
656                                         int             val_cnt;
657                                         DataRange       *dr;
658
659                                         cur_date        = date->clone();
660                                         max_date        = get_scanning_limit_date(period_type_param);
661                                         cur_data        = NULL;
662                                         res_data        = NULL;
663                                         cnt             = 0;
664                                         while(cur_date->before(max_date)) {
665                                                 if (period_type_param == PERIOD_YEARLY) {
666                                                         store   = new StoreCache(device_id, cur_date);
667                                                         dr      = store->get_min(PERIOD_MONTHLY);
668                                                 }
669                                                 else {
670                                                         if (StoreDay::exist(device_id, cur_date, false)) {
671                                                                 store   = new StoreDay(device_id, cur_date);
672                                                                 dr      = store->get_min(PERIOD_DAILY);
673                                                         }
674                                                         else {
675                                                                 StoreDay::get_next_date_with_data(device_id,
676                                                                                                 cur_date,
677                                                                                                 max_date);
678                                                                 continue;
679                                                         }
680                                                 }
681                                                 if (dr != NULL) {
682                                                         cur_data        = dr->get_first();
683                                                         if (cur_data != NULL) {
684                                                                 cnt++;
685                                                                 if (res_data == NULL) {
686                                                                         res_data        = cur_data;
687                                                                 }
688                                                                 else {
689                                                                         val_cnt = res_data->get_value_count();
690                                                                         int changed = 0;
691                                                                         for (ii = 0; ii < val_cnt; ii++) {
692                                                                                 if (cur_data->value_arr[ii] < res_data->value_arr[ii]) {
693                                                                                         res_data->value_arr[ii] = cur_data->value_arr[ii];
694                                                                                         changed = 1;
695                                                                                 }
696                                                                         }
697                                                                         if (changed == 1) {
698                                                                                 Date new_date;
699
700                                                                                 new_date        = cur_data->get_date();
701                                                                                 res_data->set_date(&new_date);
702                                                                         }
703                                                                         delete(cur_data);
704                                                                 }
705                                                         }
706                                                         delete(dr);
707                                                 }
708                                                 delete(store);
709                                                 if (period_type_param == PERIOD_YEARLY) {
710                                                         cur_date->next_month();
711                                                 }
712                                                 else {
713                                                         cur_date->next_day();
714                                                 }
715                                         }
716                                         if ((res_data != NULL) &&
717                                             (cnt > 0)) {
718                                                 ret_val = new DataRange(res_data);
719                                                 save(fname, ret_val, 4);
720                                                 delete(res_data);
721                                         }
722                                         delete(cur_date);
723                                         delete(max_date);
724                                 }
725                                 break;
726                         case PERIOD_DAILY:
727                         case PERIOD_HOURLY:
728                         case PERIOD_MINUTELY:
729                         case PERIOD_SECONDLY:
730                                 if (StoreDay::exist(device_id, date, false)) {
731                                         store   = new StoreDay(device_id, date);
732                                         ret_val = store->get_min(period_type_param);
733                                         if ((period_type_param != PERIOD_MINUTELY) ||
734                                             (period_type_param != PERIOD_SECONDLY)) {
735                                                 // no need cache second or minute data
736                                                 save(fname, ret_val, 4);
737                                         }
738                                         delete(store);
739                                 }
740                                 break;
741                 }
742         }
743         return ret_val;
744 }
745
746 void StoreCache::save(std::string fname_param, plp::DataRange *datarange_param, int decimal_count_param) {
747         string          line;
748         Data            *data;
749         ofstream        *ostream;
750         int             ii;
751         int             cnt;
752
753         cnt     = datarange_param->get_count();
754         ostream =  NULL;
755         //log_info("[%s] cacheing %d data values.\n", device_id.c_str(), cnt);
756         ostream = FileUtil::open_for_writing(fname_param.c_str());
757         if ((ostream != NULL) &&
758             (ostream->is_open() == true)) {
759                 // TODO: add mutex to protect string_list while it's read and emptied
760                 for(ii = 0; ii < cnt; ii++) {
761                         data    = datarange_param->get(ii);
762                         if (data != NULL) {
763                                 line    = data->to_string(decimal_count_param);
764                                 if (line.length() > 0) {
765                                         *ostream << line << endl;
766                                 }
767                                 delete(data);
768                         }
769                 }
770         }
771         else {
772                 log_error("[%s] File open for data save failed: %s\n", device_id.c_str(), fname_param.c_str());
773         }
774         if (ostream != NULL) {
775                 ostream->close();
776                 delete(ostream);
777         }
778 }
779
780 Data *StoreCache::get_oldest_data(Date *date_param,
781                         string device_id_param,
782                         EnumSummaryPeriod period_type_param) {
783         int             size;
784         unsigned int    ii;
785         string          year_dr;
786         string          mon_dr;
787         vector<string>  mon_vcr;
788         vector<string>  dta_vcr;
789         string          f_name;
790         StoreDay        *store;
791         Data            *ret_val;
792         string          device_dir;
793         char            buffer[30];
794         string          year_name;
795
796         ret_val = NULL;
797         if (period_type_param == PERIOD_YEARLY) {
798                 snprintf(buffer, 30, "%d", date_param->year);
799                 year_name.append(buffer);
800                 device_dir      = DeviceConfig::get_base_dir_name();
801                 device_dir      = FileUtil::concat_paths(device_dir, device_id_param);
802                 year_dr = FileUtil::concat_paths(device_dir, year_name);
803                 mon_vcr = FileUtil::get_subdirectories(year_dr);
804                 for (ii = 0; ii < mon_vcr.size(); ii++) {
805                         mon_dr  = mon_vcr.at(ii);
806                         mon_dr  = FileUtil::concat_paths(year_dr, mon_dr);
807                         // scan data files from month dir
808                         dta_vcr = FileUtil::get_data_files(mon_dr);
809                         size    = dta_vcr.size();
810                         if (size > 0) {
811                                 f_name  = dta_vcr.at(0);
812                                 f_name  = FileUtil::concat_paths(mon_dr, f_name);
813                                 store   = new StoreDay(f_name);
814                                 ret_val = store->get_oldest_data();
815                                 delete(store);
816                                 break;
817                         }
818                 }
819         }
820         else if (period_type_param == PERIOD_MONTHLY) {
821                 ret_val         = NULL;
822                 snprintf(buffer, 30, "%d", date_param->year);
823                 year_name.append(buffer);
824                 device_dir      = DeviceConfig::get_base_dir_name();
825                 device_dir      = FileUtil::concat_paths(device_dir, device_id_param);
826                 year_dr         = FileUtil::concat_paths(device_dir, year_name);
827                 snprintf(buffer, 30, "%02d", date_param->month);
828                 mon_dr.append(buffer);
829                 mon_dr          = FileUtil::concat_paths(year_dr, mon_dr);
830                 // scan data files from month dir
831                 dta_vcr         = FileUtil::get_data_files(mon_dr);
832                 size            = dta_vcr.size();
833                 if (size > 0) {
834                         f_name  = dta_vcr.at(0);
835                         f_name  = FileUtil::concat_paths(mon_dr, f_name);
836                         store   = new StoreDay(f_name);
837                         ret_val = store->get_oldest_data();
838                         delete(store);
839                 }
840
841         }
842         else {
843                 store   = new StoreDay(device_id_param, date_param);
844                 ret_val = store->get_oldest_data();
845                 delete(store);
846         }
847         return ret_val;
848 }
849
850 Data *StoreCache::get_latest_data(Date *date_param,
851                         string device_id_param,
852                         EnumSummaryPeriod period_type_param) {
853         int             ii;
854         string          mon_dr;
855         vector<string>  mon_vcr;
856         vector<string>  dta_vcr;
857         string          f_name;
858         StoreDay        *store;
859         Data            *ret_val;
860         string          year_dr;
861         int             size;
862         string          device_dir;
863         char            buffer[30];
864         string          year_name;
865
866         ret_val = NULL;
867         if (period_type_param == PERIOD_YEARLY) {
868                 snprintf(buffer, 30, "%d", date_param->year);
869                 year_name.append(buffer);
870                 device_dir      = DeviceConfig::get_base_dir_name();
871                 device_dir      = FileUtil::concat_paths(device_dir, device_id_param);
872                 year_dr = FileUtil::concat_paths(device_dir, year_name);
873                 mon_vcr = FileUtil::get_subdirectories(year_dr);
874                 for (ii = mon_vcr.size() - 1; ii >= 0; ii--) {
875                         mon_dr  = mon_vcr.at(ii);
876                         mon_dr  = FileUtil::concat_paths(year_dr, mon_dr);
877                         // scan data files from month dir
878                         dta_vcr = FileUtil::get_data_files(mon_dr);
879                         size    = dta_vcr.size();
880                         if (size > 0) {
881                                 f_name  = dta_vcr.at(size - 1);
882                                 f_name  = FileUtil::concat_paths(mon_dr, f_name);
883                                 store   = new StoreDay(f_name);
884                                 ret_val = store->get_latest_data();
885                                 delete(store);
886                                 break;
887                         }
888                 }
889         }
890         else if (period_type_param == PERIOD_MONTHLY) {
891                 ret_val         = NULL;
892                 snprintf(buffer, 30, "%d", date_param->year);
893                 year_name.append(buffer);
894                 device_dir      = DeviceConfig::get_base_dir_name();
895                 device_dir      = FileUtil::concat_paths(device_dir, device_id_param);
896                 year_dr         = FileUtil::concat_paths(device_dir, year_name);
897                 snprintf(buffer, 30, "%02d", date_param->month);
898                 mon_dr.append(buffer);
899                 mon_dr          = FileUtil::concat_paths(year_dr, mon_dr);
900                 // scan data files from month dir
901                 dta_vcr         = FileUtil::get_data_files(mon_dr);
902                 size            = dta_vcr.size();
903                 if (size > 0) {
904                         f_name  = dta_vcr.at(size - 1);
905                         f_name  = FileUtil::concat_paths(mon_dr, f_name);
906                         store   = new StoreDay(f_name);
907                         ret_val = store->get_latest_data();
908                         delete(store);
909                 }
910
911         }
912         else {
913                 store   = new StoreDay(device_id_param, date_param);
914                 ret_val = store->get_latest_data();
915                 delete(store);
916         }
917         return ret_val;
918 }