1/*
2* Copyright (c) 2011-2013 Yorba Foundation
3*
4* This program is free software; you can redistribute it and/or
5* modify it under the terms of the GNU Lesser General Public
6* License as published by the Free Software Foundation; either
7* version 2.1 of the License, or (at your option) any later version.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12* General Public License for more details.
13*
14* You should have received a copy of the GNU General Public
15* License along with this program; if not, write to the
16* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17* Boston, MA 02110-1301 USA
18*/
19
20public struct EventID {
21    public const int64 INVALID = -1;
22
23    public int64 id;
24
25    public EventID (int64 id = INVALID) {
26        this.id = id;
27    }
28
29    public bool is_invalid () {
30        return (id == INVALID);
31    }
32
33    public bool is_valid () {
34        return (id != INVALID);
35    }
36}
37
38public class EventRow {
39    public EventID event_id;
40    public string? name;
41    public int64 time_created;
42    public string? primary_source_id;
43    public string? comment;
44}
45
46public class EventTable : DatabaseTable {
47    private static EventTable instance = null;
48
49    private EventTable () {
50        var stmt = create_stmt (
51            "CREATE TABLE IF NOT EXISTS EventTable ("
52            + "id INTEGER PRIMARY KEY, "
53            + "name TEXT, "
54            + "primary_photo_id INTEGER, "
55            + "time_created INTEGER,"
56            + "primary_source_id TEXT,"
57            + "comment TEXT"
58            + ")");
59
60        var res = stmt.step ();
61        if (res != Sqlite.DONE)
62            fatal ("create photo table", res);
63
64        set_table_name ("EventTable");
65    }
66
67    public static EventTable get_instance () {
68        if (instance == null)
69            instance = new EventTable ();
70
71        return instance;
72    }
73
74    // Returns a valid source ID, creating one from a legacy primary photo ID when needed.
75    private string? source_id_upgrade (int64 primary_photo_id, string? primary_source_id) {
76        if (MediaCollectionRegistry.get_instance ().is_valid_source_id (primary_source_id)) {
77            return primary_source_id;
78        }
79        if (primary_photo_id != PhotoID.INVALID) {
80            // Upgrade to source_id from photo_id.
81            return PhotoID.upgrade_photo_id_to_source_id (PhotoID (primary_photo_id));
82        }
83        return null;
84    }
85
86    public EventRow create (string? primary_source_id, string? comment) throws DatabaseError {
87        assert (primary_source_id != null && primary_source_id != "");
88
89        var stmt = create_stmt ("INSERT INTO EventTable (primary_source_id, time_created, comment) VALUES (?, ?, ?)");
90
91        int64 time_created = now_sec ();
92
93        bind_text (stmt, 1, primary_source_id);
94        bind_int64 (stmt, 2, time_created);
95        bind_text (stmt, 3, comment);
96
97        var res = stmt.step ();
98        if (res != Sqlite.DONE)
99            throw_error ("EventTable.create", res);
100
101        EventRow row = new EventRow ();
102        row.event_id = EventID (db.last_insert_rowid ());
103        row.name = null;
104        row.primary_source_id = primary_source_id;
105        row.time_created = time_created;
106        row.comment = comment;
107
108        return row;
109    }
110
111    // NOTE: The event_id in EventRow is ignored here.  No checking is done to prevent
112    // against creating duplicate events or for the validity of other fields in the row (i.e.
113    // the primary photo ID).
114    public EventID create_from_row (EventRow row) {
115        var stmt = create_stmt ("INSERT INTO EventTable (name, primary_photo_id, primary_source_id, time_created, comment) VALUES (?, ?, ?, ?, ?)");
116
117        bind_text (stmt, 1, row.name);
118        bind_int64 (stmt, 2, PhotoID.INVALID);
119        bind_text (stmt, 3, row.primary_source_id);
120        bind_int64 (stmt, 4, row.time_created);
121        bind_text (stmt, 5, row.comment);
122
123        var res = stmt.step ();
124        if (res != Sqlite.DONE) {
125            fatal ("Event create_from_row", res);
126
127            return EventID ();
128        }
129
130        return EventID (db.last_insert_rowid ());
131    }
132
133    public EventRow? get_row (EventID event_id) {
134        var stmt = create_stmt ("SELECT name, primary_photo_id, primary_source_id, time_created, comment FROM EventTable WHERE id=?");
135
136        bind_int64 (stmt, 1, event_id.id);
137
138        if (stmt.step () != Sqlite.ROW) {
139            return null;
140        }
141
142        EventRow row = new EventRow ();
143        row.event_id = event_id;
144        row.name = stmt.column_text (0);
145        if (row.name != null && row.name.length == 0)
146            row.name = null;
147        row.primary_source_id = source_id_upgrade (stmt.column_int64 (1), stmt.column_text (2));
148        row.time_created = stmt.column_int64 (3);
149        row.comment = stmt.column_text (4);
150
151        return row;
152    }
153
154    public void remove (EventID event_id) throws DatabaseError {
155        delete_by_id (event_id.id);
156    }
157
158    public Gee.ArrayList < EventRow?> get_events () {
159        var stmt = create_stmt ("SELECT id, name, primary_photo_id, primary_source_id, time_created, comment FROM EventTable");
160
161        Gee.ArrayList < EventRow?> event_rows = new Gee.ArrayList < EventRow?> ();
162        for (;;) {
163            var res = stmt.step ();
164            if (res == Sqlite.DONE) {
165                break;
166            } else if (res != Sqlite.ROW) {
167                fatal ("get_events", res);
168
169                break;
170            }
171
172            EventRow row = new EventRow ();
173
174            row.event_id = EventID (stmt.column_int64 (0));
175            row.name = stmt.column_text (1);
176            row.primary_source_id = source_id_upgrade (stmt.column_int64 (2), stmt.column_text (3));
177            row.time_created = stmt.column_int64 (4);
178            row.comment = stmt.column_text (5);
179
180            event_rows.add (row);
181        }
182
183        return event_rows;
184    }
185
186    public bool rename (EventID event_id, string? name) {
187        return update_text_by_id (event_id.id, "name", name != null ? name : "");
188    }
189
190    public string? get_name (EventID event_id) {
191        Sqlite.Statement stmt;
192        if (!select_by_id (event_id.id, "name", out stmt))
193            return null;
194
195        string name = stmt.column_text (0);
196
197        return (name != null && name.length > 0) ? name : null;
198    }
199
200    public string? get_primary_source_id (EventID event_id) {
201        Sqlite.Statement stmt;
202        if (!select_by_id (event_id.id, "primary_source_id", out stmt))
203            return null;
204
205        return stmt.column_text (0);
206    }
207
208    public bool set_primary_source_id (EventID event_id, string primary_source_id) {
209        return update_text_by_id (event_id.id, "primary_source_id", primary_source_id);
210    }
211
212    public int64 get_time_created (EventID event_id) {
213        Sqlite.Statement stmt;
214        if (!select_by_id (event_id.id, "time_created", out stmt))
215            return 0;
216
217        return stmt.column_int64 (0);
218    }
219
220    public bool set_comment (EventID event_id, string new_comment) {
221        return update_text_by_id (event_id.id, "comment", new_comment != null ? new_comment : "");
222    }
223}
224