1 /* ************************************************************************** */
2 /*                                                                            */
3 /*                                                                            */
4 /*     Copyright (C)    2000-2008 Cédric Auger (cedric@grisbi.org)            */
5 /*          2003-2008 Benjamin Drieu (bdrieu@april.org)                       */
6 /*          https://www.grisbi.org/                                            */
7 /*                                                                            */
8 /*  This program is free software; you can redistribute it and/or modify      */
9 /*  it under the terms of the GNU General Public License as published by      */
10 /*  the Free Software Foundation; either version 2 of the License, or         */
11 /*  (at your option) any later version.                                       */
12 /*                                                                            */
13 /*  This program is distributed in the hope that it will be useful,           */
14 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of            */
15 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
16 /*  GNU General Public License for more details.                              */
17 /*                                                                            */
18 /*  You should have received a copy of the GNU General Public License         */
19 /*  along with this program; if not, write to the Free Software               */
20 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21 /*                                                                            */
22 /* ************************************************************************** */
23 
24 /**
25  * \file gsb_data_archive.c
26  * work with the archive store structure, no GUI here
27  * the archive store are used to show the archive in the list of transactions
28  * as an archive by itself contains several accounts and no balance for each account
29  * at the opening of grisbi, we create an intermediate list of structures which contains
30  * the link to the archive, but 1 structure per account, with the number of transactions
31  * and the balance for each.
32  */
33 
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include "include.h"
40 
41 /*START_INCLUDE*/
42 #include "gsb_data_archive_store.h"
43 #include "dialog.h"
44 #include "gsb_data_account.h"
45 #include "gsb_data_currency.h"
46 #include "gsb_data_transaction.h"
47 #include "gsb_real.h"
48 #include "transaction_list.h"
49 #include "erreur.h"
50 /*END_INCLUDE*/
51 
52 
53 /*START_STATIC*/
54 static void _gsb_data_archive_store_free ( struct_store_archive *archive );
55 static struct_store_archive *gsb_data_archive_store_find_struct ( gint archive_number,
56                         gint account_number );
57 static gint gsb_data_archive_store_max_number ( void );
58 static gint gsb_data_archive_store_new ( void );
59 /*END_STATIC*/
60 
61 /*START_EXTERN*/
62 /*END_EXTERN*/
63 
64 /** contains the g_slist of struct_store_archive */
65 static GSList *archive_store_list = NULL;
66 
67 /** a pointer to the last archive_store used (to increase the speed) */
68 static struct_store_archive *archive_store_buffer;
69 
70 
71 /**
72  * set the archives global variables to NULL,
73  * usually when we init all the global variables
74  *
75  * \param
76  *
77  * \return FALSE
78  * */
gsb_data_archive_store_init_variables(void)79 gboolean gsb_data_archive_store_init_variables ( void )
80 {
81     if ( archive_store_list )
82     {
83         GSList *tmp_list;
84 
85         tmp_list = archive_store_list;
86         while ( tmp_list )
87         {
88             struct_store_archive *archive;
89 
90             archive = tmp_list -> data;
91             transaction_list_remove_archive ( archive->archive_number );
92             tmp_list = tmp_list -> next;
93             _gsb_data_archive_store_free ( archive );
94         }
95         g_slist_free ( archive_store_list );
96     }
97     archive_store_list = NULL;
98     archive_store_buffer = NULL;
99 
100     return FALSE;
101 }
102 
103 
104 /**
105  * give the g_slist of archives structure
106  * usefull when want to check all archives
107  *
108  * \param none
109  *
110  * \return the g_slist of archives structure
111  * */
gsb_data_archive_store_get_archives_list(void)112 GSList *gsb_data_archive_store_get_archives_list ( void )
113 {
114     return archive_store_list;
115 }
116 
117 /**
118  * return the number of the archives given in param
119  *
120  * \param archive_ptr a pointer to the struct of the archive
121  *
122  * \return the number of the archive, 0 if problem
123  * */
gsb_data_archive_store_get_number(gpointer archive_ptr)124 gint gsb_data_archive_store_get_number ( gpointer archive_ptr )
125 {
126     struct_store_archive *archive;
127 
128     if ( !archive_ptr )
129     return 0;
130 
131     archive = archive_ptr;
132     archive_store_buffer = archive;
133 
134     return archive -> archive_store_number;
135 }
136 
137 
138 
139 /**
140  * function called at the opening of grisbi
141  * create all the archive store according to the archives in grisbi
142  *
143  * \param
144  *
145  * \return
146  * */
gsb_data_archive_store_create_list(void)147 void gsb_data_archive_store_create_list ( void )
148 {
149     GSList *tmp_list;
150 
151     tmp_list = gsb_data_transaction_get_complete_transactions_list ();
152     while (tmp_list)
153     {
154     gint transaction_number;
155     gint archive_number;
156 
157     transaction_number = gsb_data_transaction_get_transaction_number (tmp_list -> data);
158 
159     archive_number = gsb_data_transaction_get_archive_number (transaction_number);
160 
161     if (archive_number)
162     {
163         struct_store_archive *archive_store;
164         gint floating_point;
165         gint account_number;
166 
167         account_number = gsb_data_transaction_get_account_number (transaction_number);
168         floating_point = gsb_data_currency_get_floating_point (
169                             gsb_data_account_get_currency (account_number) );
170         archive_store = gsb_data_archive_store_find_struct ( archive_number, account_number);
171         if (archive_store)
172         {
173             /* there is already a struct_store_archive for the same archive and the same account,
174              * we increase the balance except for operations */
175             if ( !gsb_data_transaction_get_mother_transaction_number ( transaction_number ) )
176                 archive_store -> balance = gsb_real_add ( archive_store -> balance,
177                                     gsb_data_transaction_get_adjusted_amount (
178                                     transaction_number,
179                                     floating_point));
180             archive_store -> nb_transactions++;
181         }
182         else
183         {
184             /* there is no struct_store_archive for that transaction, we make a new one
185              * with the balance of the transaction as balance */
186             gint archive_store_number;
187 
188             archive_store_number = gsb_data_archive_store_new ();
189             archive_store = gsb_data_archive_store_get_structure (archive_store_number);
190 
191             archive_store -> archive_number = archive_number;
192             archive_store -> account_number = account_number;
193             archive_store -> balance = gsb_data_transaction_get_adjusted_amount (
194                             transaction_number, floating_point);
195             if ( ! gsb_data_transaction_get_mother_transaction_number ( transaction_number ) )
196                 archive_store -> nb_transactions = 1;
197         }
198     }
199     tmp_list = tmp_list -> next;
200     }
201 }
202 
203 /**
204  * This internal function is called to free the memory used by a struct_store_archive structure
205  */
_gsb_data_archive_store_free(struct_store_archive * archive)206 static void _gsb_data_archive_store_free ( struct_store_archive *archive )
207 {
208     if ( !archive )
209         return;
210 
211     g_free ( archive );
212 
213     if ( archive_store_buffer == archive )
214         archive_store_buffer = NULL;
215 }
216 
217 /**
218  * remove an archive store
219  *
220  * \param archive_store_number the archive store we want to remove
221  *
222  * \return TRUE ok
223  * */
gsb_data_archive_store_remove(gint archive_store_number)224 gboolean gsb_data_archive_store_remove ( gint archive_store_number )
225 {
226     struct_store_archive *archive;
227 
228     archive = gsb_data_archive_store_get_structure ( archive_store_number );
229 
230     if (!archive)
231     return FALSE;
232 
233     archive_store_list = g_slist_remove ( archive_store_list,
234                       archive );
235 
236     _gsb_data_archive_store_free ( archive );
237     return TRUE;
238 }
239 
240 /**
241  * remove all the archives stores corresponding to the archive
242  *
243  * \param archive_number the archive we want remove the corresponding archives stores
244  *
245  * \return TRUE ok
246  * */
gsb_data_archive_store_remove_by_archive(gint archive_number)247 gboolean gsb_data_archive_store_remove_by_archive ( gint archive_number )
248 {
249     GSList *tmp_list;
250 
251     tmp_list = archive_store_list;
252     while (tmp_list)
253     {
254     struct_store_archive *archive;
255 
256     archive = tmp_list -> data;
257     tmp_list = tmp_list -> next;
258     if (archive -> archive_number == archive_number)
259     {
260         archive_store_list = g_slist_remove ( archive_store_list,
261                           archive );
262         _gsb_data_archive_store_free ( archive );
263     }
264     }
265     return TRUE;
266 }
267 
268 
269 
270 
271 /**
272  * return the number of the corresponding archive
273  *
274  * \param archive_store_number the number of the archive store
275  *
276  * \return the  of the archive or 0 if fail
277  * */
gsb_data_archive_store_get_archive_number(gint archive_store_number)278 gint gsb_data_archive_store_get_archive_number ( gint archive_store_number )
279 {
280     struct_store_archive *archive;
281 
282     archive = gsb_data_archive_store_get_structure ( archive_store_number );
283 
284     if (!archive)
285     return 0;
286 
287     return archive -> archive_number;
288 }
289 
290 /**
291  * return the account_number of the archive store
292  *
293  * \param archive_store_number the number of the archive store
294  *
295  * \return the  of the archive or 0 if fail
296  * */
gsb_data_archive_store_get_account_number(gint archive_store_number)297 gint gsb_data_archive_store_get_account_number ( gint archive_store_number )
298 {
299     struct_store_archive *archive;
300 
301     archive = gsb_data_archive_store_get_structure ( archive_store_number );
302 
303     if (!archive)
304     return 0;
305 
306     return archive -> account_number;
307 }
308 
309 /**
310  * return the balance of the archive store
311  * ie the balance of the archive for the account in the archive store
312  *
313  * \param archive_store_number the number of the archive store
314  *
315  * \return the  of the archive or 0 if fail
316  * */
gsb_data_archive_store_get_balance(gint archive_store_number)317 GsbReal gsb_data_archive_store_get_balance ( gint archive_store_number )
318 {
319     struct_store_archive *archive;
320 
321     archive = gsb_data_archive_store_get_structure ( archive_store_number );
322 
323     if (!archive)
324     return null_real;
325 
326     return archive -> balance;
327 }
328 
329 /**
330  * return the number of transactions of the archive store
331  *
332  * \param archive_store_number the number of the archive store
333  *
334  * \return the  of the archive or 0 if fail
335  * */
gsb_data_archive_store_get_transactions_number(gint archive_store_number)336 gint gsb_data_archive_store_get_transactions_number ( gint archive_store_number )
337 {
338     struct_store_archive *archive;
339 
340     archive = gsb_data_archive_store_get_structure ( archive_store_number );
341 
342     if (!archive)
343     return 0;
344 
345     return archive -> nb_transactions;
346 }
347 
348 
349 
350 /**
351  * find and return the structure of the archive asked
352  *
353  * \param archive_store_number number of archive
354  *
355  * \return the adr of the struct of the archive (NULL if doesn't exit)
356  * */
gsb_data_archive_store_get_structure(gint archive_store_number)357 gpointer gsb_data_archive_store_get_structure ( gint archive_store_number )
358 {
359     GSList *tmp;
360 
361     if (!archive_store_number)
362     return NULL;
363 
364     /* before checking all the archives, we check the buffer */
365     if ( archive_store_buffer
366      &&
367      archive_store_buffer -> archive_store_number == archive_store_number )
368     return archive_store_buffer;
369 
370     tmp = archive_store_list;
371 
372     while ( tmp )
373     {
374     struct_store_archive *archive;
375 
376     archive = tmp -> data;
377 
378     if ( archive -> archive_store_number == archive_store_number )
379     {
380         archive_store_buffer = archive;
381         return archive;
382     }
383 
384     tmp = tmp -> next;
385     }
386     return NULL;
387 }
388 
389 /**
390  * find and return the last number of archive
391  *
392  * \param none
393  *
394  * \return last number of archive
395  * */
gsb_data_archive_store_max_number(void)396 static gint gsb_data_archive_store_max_number ( void )
397 {
398     GSList *tmp;
399     gint number_tmp = 0;
400 
401     tmp = archive_store_list;
402 
403     while ( tmp )
404     {
405     struct_store_archive *archive;
406 
407     archive = tmp -> data;
408 
409     if ( archive -> archive_store_number > number_tmp )
410         number_tmp = archive -> archive_store_number;
411 
412     tmp = tmp -> next;
413     }
414     return number_tmp;
415 }
416 
417 /**
418  * find the archive  store corresponding to the archive number and account number
419  * given in param
420  *
421  * \param archive_number the wanted archive number
422  * \param account_number the wanted account number
423  *
424  * \return a pointer to the found struct_store_archive or NULL
425  * */
gsb_data_archive_store_find_struct(gint archive_number,gint account_number)426 static struct_store_archive *gsb_data_archive_store_find_struct ( gint archive_number,
427                         gint account_number )
428 {
429     GSList *tmp_list;
430 
431     tmp_list = archive_store_list;
432     while (tmp_list)
433     {
434     struct_store_archive *archive;
435 
436     archive = tmp_list -> data;
437 
438     if (archive -> archive_number == archive_number
439         &&
440         archive -> account_number == account_number )
441         return archive;
442 
443     tmp_list = tmp_list -> next;
444     }
445     return NULL;
446 }
447 
448 /**
449  * create a new archive store, give it a number, append it to the list
450  * and return the number
451  *
452  * \param
453  *
454  * \return the number of the new archive store
455  * */
gsb_data_archive_store_new(void)456 static gint gsb_data_archive_store_new ( void )
457 {
458     struct_store_archive *archive;
459 
460     archive = g_malloc0 ( sizeof ( struct_store_archive ));
461     if (!archive)
462     {
463     dialogue_error_memory ();
464     return 0;
465     }
466     archive -> archive_store_number = gsb_data_archive_store_max_number () + 1;
467 
468     archive_store_list = g_slist_append ( archive_store_list, archive );
469     archive_store_buffer = archive;
470 
471     return archive -> archive_store_number;
472 }
473 
474 
475 /**
476  *
477  *
478  *
479  */
gsb_data_archive_store_get_archives_balance(gint account_number)480 GsbReal gsb_data_archive_store_get_archives_balance ( gint account_number )
481 {
482     GSList *tmp_list;
483     GsbReal balance = null_real;
484 
485     tmp_list = gsb_data_archive_store_get_archives_list ( );
486 
487     while (tmp_list)
488     {
489         struct_store_archive *archive_store;
490 
491         archive_store = tmp_list -> data;
492 
493         if ( archive_store -> account_number == account_number )
494             balance = gsb_real_add ( balance, archive_store -> balance );
495 
496         tmp_list = tmp_list -> next;
497     }
498 
499     return balance;
500 }
501 
502 
503 /**
504  *
505  *
506  *
507  */
gsb_data_archive_store_get_transactions_visibles(gint archive_number,gint account_number)508 gboolean gsb_data_archive_store_get_transactions_visibles ( gint archive_number,
509                         gint account_number )
510 {
511     struct_store_archive *archive_store;
512 
513     archive_store = gsb_data_archive_store_find_struct ( archive_number, account_number );
514 
515     if ( archive_store )
516         return archive_store -> transactions_visibles;
517     else
518         return FALSE;
519 }
520 
521 
522 /**
523  *
524  *
525  *
526  */
gsb_data_archive_store_set_transactions_visibles(gint archive_number,gint account_number,gboolean transactions_visibles)527 gboolean gsb_data_archive_store_set_transactions_visibles ( gint archive_number,
528                         gint account_number,
529                         gboolean transactions_visibles )
530 {
531     struct_store_archive *archive_store;
532 
533     archive_store = gsb_data_archive_store_find_struct ( archive_number, account_number );
534 
535     if ( archive_store )
536     {
537         archive_store -> transactions_visibles = transactions_visibles;
538         return TRUE;
539     }
540     else
541         return FALSE;
542 }
543 
544 
545 /**
546  *
547  *
548  *
549  */
gsb_data_archive_store_account_have_transactions_visibles(gint account_number)550 gboolean gsb_data_archive_store_account_have_transactions_visibles ( gint account_number )
551 {
552     GSList *tmp_list;
553 
554     tmp_list = gsb_data_archive_store_get_archives_list ( );
555 
556     while (tmp_list)
557     {
558         struct_store_archive *archive_store;
559 
560         archive_store = tmp_list -> data;
561 
562         if ( archive_store -> account_number == account_number
563          &&
564          archive_store -> transactions_visibles == TRUE )
565             return TRUE;
566 
567         tmp_list = tmp_list -> next;
568     }
569 
570     return FALSE;
571 }
572 
573 
574 /* Local Variables: */
575 /* c-basic-offset: 4 */
576 /* End: */
577