]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/async/ConfigReader.java
config restore: skip null entries
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / async / ConfigReader.java
1 /*
2  * Copyright © 2021 Damyan Ivanov.
3  * This file is part of MoLe.
4  * MoLe is free software: you can distribute it and/or modify it
5  * under the term of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your opinion), any later version.
8  *
9  * MoLe 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
12  * GNU General Public License terms for details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with MoLe. If not, see <https://www.gnu.org/licenses/>.
16  */
17
18 package net.ktnx.mobileledger.async;
19
20 import android.content.Context;
21 import android.net.Uri;
22 import android.util.JsonReader;
23 import android.util.JsonToken;
24
25 import net.ktnx.mobileledger.dao.CurrencyDAO;
26 import net.ktnx.mobileledger.dao.ProfileDAO;
27 import net.ktnx.mobileledger.dao.TemplateHeaderDAO;
28 import net.ktnx.mobileledger.db.Currency;
29 import net.ktnx.mobileledger.db.DB;
30 import net.ktnx.mobileledger.db.Profile;
31 import net.ktnx.mobileledger.db.TemplateAccount;
32 import net.ktnx.mobileledger.db.TemplateHeader;
33 import net.ktnx.mobileledger.db.TemplateWithAccounts;
34 import net.ktnx.mobileledger.model.Data;
35 import net.ktnx.mobileledger.utils.Misc;
36
37 import java.io.BufferedReader;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.IOException;
41 import java.io.InputStreamReader;
42 import java.util.ArrayList;
43 import java.util.List;
44
45 public class ConfigReader extends ConfigIO {
46     private final OnDoneListener onDoneListener;
47     private JsonReader r;
48     public ConfigReader(Context context, Uri uri, OnErrorListener onErrorListener,
49                         OnDoneListener onDoneListener) throws FileNotFoundException {
50         super(context, uri, onErrorListener);
51
52         this.onDoneListener = onDoneListener;
53     }
54     @Override
55     protected String getStreamMode() {
56         return "r";
57     }
58     @Override
59     protected void initStream() {
60         r = new JsonReader(new BufferedReader(
61                 new InputStreamReader(new FileInputStream(pfd.getFileDescriptor()))));
62     }
63     @Override
64     protected void processStream() throws IOException {
65         List<Currency> commodities = null;
66         List<Profile> profiles = null;
67         List<TemplateWithAccounts> templates = null;
68         String currentProfile = null;
69         r.beginObject();
70         while (r.hasNext()) {
71             String item = r.nextName();
72             if (r.peek() == JsonToken.NULL) {
73                 r.nextNull();
74                 continue;
75             }
76             switch (item) {
77                 case Keys.COMMODITIES:
78                     commodities = readCommodities(r);
79                     break;
80                 case Keys.PROFILES:
81                     profiles = readProfiles(r);
82                     break;
83                 case Keys.TEMPLATES:
84                     templates = readTemplates(r);
85                     break;
86                 case Keys.CURRENT_PROFILE:
87                     currentProfile = r.nextString();
88                     break;
89                 default:
90                     throw new RuntimeException("unexpected top-level item " + item);
91             }
92         }
93         r.endObject();
94
95         restoreCommodities(commodities);
96         restoreProfiles(profiles);
97         restoreTemplates(templates);
98
99         if (Data.getProfile() == null) {
100             Profile p = null;
101             final ProfileDAO dao = DB.get()
102                                      .getProfileDAO();
103             if (currentProfile != null)
104                 p = dao.getByUuidSync(currentProfile);
105
106             if (p == null)
107                 dao.getAnySync();
108
109             if (p != null)
110                 Data.postCurrentProfile(p);
111         }
112
113         if (onDoneListener != null)
114             Misc.onMainThread(onDoneListener::done);
115     }
116     private void restoreTemplates(List<TemplateWithAccounts> list) {
117         if (list == null)
118             return;
119
120         TemplateHeaderDAO dao = DB.get()
121                                   .getTemplateDAO();
122
123         for (TemplateWithAccounts t : list) {
124             if (dao.getTemplateWithAccountsByUuidSync(t.header.getUuid()) == null)
125                 dao.insertSync(t);
126         }
127     }
128     private void restoreProfiles(List<Profile> list) {
129         if (list == null)
130             return;
131
132         ProfileDAO dao = DB.get()
133                            .getProfileDAO();
134
135         for (Profile p : list) {
136             if (dao.getByUuidSync(p.getUuid()) == null)
137                 dao.insert(p);
138         }
139     }
140     private void restoreCommodities(List<Currency> list) {
141         if (list == null)
142             return;
143
144         CurrencyDAO dao = DB.get()
145                             .getCurrencyDAO();
146
147         for (Currency c : list) {
148             if (dao.getByNameSync(c.getName()) == null)
149                 dao.insert(c);
150         }
151     }
152     private TemplateAccount readTemplateAccount(JsonReader r) throws IOException {
153         r.beginObject();
154         TemplateAccount result = new TemplateAccount(0L, 0L, 0L);
155         while (r.peek() != JsonToken.END_OBJECT) {
156             String item = r.nextName();
157             if (r.peek() == JsonToken.NULL) {
158                 r.nextNull();
159                 continue;
160             }
161             switch (item) {
162                 case Keys.NAME:
163                     result.setAccountName(r.nextString());
164                     break;
165                 case Keys.NAME_GROUP:
166                     result.setAccountNameMatchGroup(r.nextInt());
167                     break;
168                 case Keys.COMMENT:
169                     result.setAccountComment(r.nextString());
170                     break;
171                 case Keys.COMMENT_GROUP:
172                     result.setAccountCommentMatchGroup(r.nextInt());
173                     break;
174                 case Keys.AMOUNT:
175                     result.setAmount((float) r.nextDouble());
176                     break;
177                 case Keys.AMOUNT_GROUP:
178                     result.setAmountMatchGroup(r.nextInt());
179                     break;
180                 case Keys.NEGATE_AMOUNT:
181                     result.setNegateAmount(r.nextBoolean());
182                     break;
183                 case Keys.CURRENCY:
184                     result.setCurrency(r.nextLong());
185                     break;
186                 case Keys.CURRENCY_GROUP:
187                     result.setCurrencyMatchGroup(r.nextInt());
188                     break;
189
190                 default:
191                     throw new IllegalStateException("Unexpected template account item: " + item);
192             }
193         }
194         r.endObject();
195
196         return result;
197     }
198     private TemplateWithAccounts readTemplate(JsonReader r) throws IOException {
199         r.beginObject();
200         String name = null;
201         TemplateHeader t = new TemplateHeader(0L, "", "");
202         List<TemplateAccount> accounts = new ArrayList<>();
203
204         while (r.peek() != JsonToken.END_OBJECT) {
205             String item = r.nextName();
206             if (r.peek() == JsonToken.NULL) {
207                 r.nextNull();
208                 continue;
209             }
210             switch (item) {
211                 case Keys.UUID:
212                     t.setUuid(r.nextString());
213                     break;
214                 case Keys.NAME:
215                     t.setName(r.nextString());
216                     break;
217                 case Keys.REGEX:
218                     t.setRegularExpression(r.nextString());
219                     break;
220                 case Keys.TEST_TEXT:
221                     t.setTestText(r.nextString());
222                     break;
223                 case Keys.DATE_YEAR:
224                     t.setDateYear(r.nextInt());
225                     break;
226                 case Keys.DATE_YEAR_GROUP:
227                     t.setDateYearMatchGroup(r.nextInt());
228                     break;
229                 case Keys.DATE_MONTH:
230                     t.setDateMonth(r.nextInt());
231                     break;
232                 case Keys.DATE_MONTH_GROUP:
233                     t.setDateMonthMatchGroup(r.nextInt());
234                     break;
235                 case Keys.DATE_DAY:
236                     t.setDateDay(r.nextInt());
237                     break;
238                 case Keys.DATE_DAY_GROUP:
239                     t.setDateDayMatchGroup(r.nextInt());
240                     break;
241                 case Keys.TRANSACTION:
242                     t.setTransactionDescription(r.nextString());
243                     break;
244                 case Keys.TRANSACTION_GROUP:
245                     t.setTransactionDescriptionMatchGroup(r.nextInt());
246                     break;
247                 case Keys.COMMENT:
248                     t.setTransactionComment(r.nextString());
249                     break;
250                 case Keys.COMMENT_GROUP:
251                     t.setTransactionCommentMatchGroup(r.nextInt());
252                     break;
253                 case Keys.IS_FALLBACK:
254                     t.setFallback(r.nextBoolean());
255                     break;
256                 case Keys.ACCOUNTS:
257                     r.beginArray();
258                     while (r.peek() == JsonToken.BEGIN_OBJECT) {
259                         accounts.add(readTemplateAccount(r));
260                     }
261                     r.endArray();
262                     break;
263                 default:
264                     throw new RuntimeException("Unknown template header item: " + item);
265             }
266         }
267         r.endObject();
268
269         TemplateWithAccounts result = new TemplateWithAccounts();
270         result.header = t;
271         result.accounts = accounts;
272         return result;
273     }
274     private List<TemplateWithAccounts> readTemplates(JsonReader r) throws IOException {
275         List<TemplateWithAccounts> list = new ArrayList<>();
276
277         r.beginArray();
278         while (r.peek() == JsonToken.BEGIN_OBJECT) {
279             list.add(readTemplate(r));
280         }
281         r.endArray();
282
283         return list;
284     }
285     private List<Currency> readCommodities(JsonReader r) throws IOException {
286         List<Currency> list = new ArrayList<>();
287
288         r.beginArray();
289         while (r.peek() == JsonToken.BEGIN_OBJECT) {
290             Currency c = new Currency();
291
292             r.beginObject();
293             while (r.peek() != JsonToken.END_OBJECT) {
294                 final String item = r.nextName();
295                 if (r.peek() == JsonToken.NULL) {
296                     r.nextNull();
297                     continue;
298                 }
299                 switch (item) {
300                     case Keys.NAME:
301                         c.setName(r.nextString());
302                         break;
303                     case Keys.POSITION:
304                         c.setPosition(r.nextString());
305                         break;
306                     case Keys.HAS_GAP:
307                         c.setHasGap(r.nextBoolean());
308                         break;
309                     default:
310                         throw new RuntimeException("Unknown commodity key: " + item);
311                 }
312             }
313             r.endObject();
314
315             if (c.getName()
316                  .isEmpty())
317                 throw new RuntimeException("Missing commodity name");
318
319             list.add(c);
320         }
321         r.endArray();
322
323         return list;
324     }
325     private List<Profile> readProfiles(JsonReader r) throws IOException {
326         List<Profile> list = new ArrayList<>();
327         r.beginArray();
328         while (r.peek() == JsonToken.BEGIN_OBJECT) {
329             Profile p = new Profile();
330             r.beginObject();
331             while (r.peek() != JsonToken.END_OBJECT) {
332                 String item = r.nextName();
333                 if (r.peek() == JsonToken.NULL) {
334                     r.nextNull();
335                     continue;
336                 }
337
338                 switch (item) {
339                     case Keys.UUID:
340                         p.setUuid(r.nextString());
341                         break;
342                     case Keys.NAME:
343                         p.setName(r.nextString());
344                         break;
345                     case Keys.URL:
346                         p.setUrl(r.nextString());
347                         break;
348                     case Keys.USE_AUTH:
349                         p.setUseAuthentication(r.nextBoolean());
350                         break;
351                     case Keys.AUTH_USER:
352                         p.setAuthUser(r.nextString());
353                         break;
354                     case Keys.AUTH_PASS:
355                         p.setAuthPassword(r.nextString());
356                         break;
357                     case Keys.API_VER:
358                         p.setApiVersion(r.nextInt());
359                         break;
360                     case Keys.CAN_POST:
361                         p.setPermitPosting(r.nextBoolean());
362                         break;
363                     case Keys.DEFAULT_COMMODITY:
364                         p.setDefaultCommodity(r.nextString());
365                         break;
366                     case Keys.SHOW_COMMODITY:
367                         p.setShowCommodityByDefault(r.nextBoolean());
368                         break;
369                     case Keys.SHOW_COMMENTS:
370                         p.setShowCommentsByDefault(r.nextBoolean());
371                         break;
372                     case Keys.FUTURE_DATES:
373                         p.setFutureDates(r.nextInt());
374                         break;
375                     case Keys.PREF_ACCOUNT:
376                         p.setPreferredAccountsFilter(r.nextString());
377                         break;
378                     case Keys.COLOUR:
379                         p.setTheme(r.nextInt());
380                         break;
381
382
383                     default:
384                         throw new IllegalStateException("Unexpected profile item: " + item);
385                 }
386             }
387             r.endObject();
388
389             list.add(p);
390         }
391         r.endArray();
392
393         return list;
394     }
395     abstract static public class OnDoneListener {
396         public abstract void done();
397     }
398 }