summaryrefslogtreecommitdiff
path: root/src/visited.c
blob: af976be532c8fe08063fedb0eea6bf19319e56e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "visited.h"
#include "app.h"

#include <the_Foundation/file.h>
#include <the_Foundation/path.h>
#include <the_Foundation/sortedarray.h>

static const size_t maxAgeVisited_Visited_ = 3600 * 24 * 30; /* one month */

void init_VisitedUrl(iVisitedUrl *d) {
    initCurrent_Time(&d->when);
    init_String(&d->url);
}

void deinit_VisitedUrl(iVisitedUrl *d) {
    deinit_String(&d->url);
}

static int cmpUrl_VisitedUrl_(const void *a, const void *b) {
    return cmpString_String(&((const iVisitedUrl *) a)->url, &((const iVisitedUrl *) b)->url);
}

static int cmpNewer_VisitedUrl_(const void *insert, const void *existing) {
    return seconds_Time(&((const iVisitedUrl *) insert  )->when) >
           seconds_Time(&((const iVisitedUrl *) existing)->when);
}

/*----------------------------------------------------------------------------------------------*/

struct Impl_Visited {
    iSortedArray visited;
};

iDefineTypeConstruction(Visited)

void init_Visited(iVisited *d) {
    init_SortedArray(&d->visited, sizeof(iVisitedUrl), cmpUrl_VisitedUrl_);
}

void deinit_Visited(iVisited *d) {
    clear_Visited(d);
    deinit_SortedArray(&d->visited);
}

void save_Visited(const iVisited *d, const char *dirPath) {
    iString *line = new_String();
    iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt"));
    if (open_File(f, writeOnly_FileMode | text_FileMode)) {
        iConstForEach(Array, i, &d->visited.values) {
            const iVisitedUrl *item = i.value;
            iDate date;
            init_Date(&date, &item->when);
            format_String(line,
                          "%04d-%02d-%02dT%02d:%02d:%02d %s\n",
                          date.year,
                          date.month,
                          date.day,
                          date.hour,
                          date.minute,
                          date.second,
                          cstr_String(&item->url));
            writeData_File(f, cstr_String(line), size_String(line));
        }
    }
    iRelease(f);
    delete_String(line);
}

void load_Visited(iVisited *d, const char *dirPath) {
    iFile *f = newCStr_File(concatPath_CStr(dirPath, "visited.txt"));
    if (open_File(f, readOnly_FileMode | text_FileMode)) {
        const iRangecc src  = range_Block(collect_Block(readAll_File(f)));
        iRangecc       line = iNullRange;
        iTime          now;
        initCurrent_Time(&now);
        while (nextSplit_Rangecc(&src, "\n", &line)) {
            int y, m, D, H, M, S;
            sscanf(line.start, "%04d-%02d-%02dT%02d:%02d:%02d ", &y, &m, &D, &H, &M, &S);
            if (!y) break;
            iVisitedUrl item;
            init_VisitedUrl(&item);
            init_Time(
                &item.when,
                &(iDate){ .year = y, .month = m, .day = D, .hour = H, .minute = M, .second = S });
            if (secondsSince_Time(&now, &item.when) > maxAgeVisited_Visited_) {
                continue; /* Too old. */
            }
            initRange_String(&item.url, (iRangecc){ line.start + 20, line.end });
            insert_SortedArray(&d->visited, &item);
        }
    }
    iRelease(f);
}

void clear_Visited(iVisited *d) {
    iForEach(Array, v, &d->visited.values) {
        deinit_VisitedUrl(v.value);
    }
    clear_SortedArray(&d->visited);
}

void visitUrl_Visited(iVisited *d, const iString *url) {
    iVisitedUrl visit;
    init_VisitedUrl(&visit);
    set_String(&visit.url, url);
    size_t pos;
    if (locate_SortedArray(&d->visited, &visit, &pos)) {
        iVisitedUrl *old = at_SortedArray(&d->visited, pos);
        if (cmpNewer_VisitedUrl_(&visit, old)) {
            old->when = visit.when;
            deinit_VisitedUrl(&visit);
            return;
        }
    }
    insert_SortedArray(&d->visited, &visit);
}

iTime urlVisitTime_Visited(const iVisited *d, const iString *url) {
    iVisitedUrl item;
    size_t pos;
    iZap(item);
    initCopy_String(&item.url, url);
    if (locate_SortedArray(&d->visited, &item, &pos)) {
        item.when = ((const iVisitedUrl *) constAt_SortedArray(&d->visited, pos))->when;
    }
    deinit_String(&item.url);
    return item.when;
}