1 /* ************************************************************************** */
2 /*                                                                            */
3 /*     Copyright (C)    2000-2006 Cédric Auger (cedric@grisbi.org)            */
4 /*          https://www.grisbi.org/                                            */
5 /*                      2009 Pierre Biava (grisbi@pierre.biava.name)          */
6 /*                                                                            */
7 /*  This program is free software; you can redistribute it and/or modify      */
8 /*  it under the terms of the GNU General Public License as published by      */
9 /*  the Free Software Foundation; either version 2 of the License, or         */
10 /*  (at your option) any later version.                                       */
11 /*                                                                            */
12 /*  This program is distributed in the hope that it will be useful,           */
13 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of            */
14 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
15 /*  GNU General Public License for more details.                              */
16 /*                                                                            */
17 /*  You should have received a copy of the GNU General Public License         */
18 /*  along with this program; if not, write to the Free Software               */
19 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20 /*                                                                            */
21 /* ************************************************************************** */
22 
23 /**
24  * \file gsb_data_currency_link.c
25  * work with the currency_link structure, no GUI here
26  */
27 
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "include.h"
34 #include <glib/gi18n.h>
35 
36 /*START_INCLUDE*/
37 #include "gsb_data_currency_link.h"
38 #include "utils_dates.h"
39 #include "dialog.h"
40 #include "gsb_real.h"
41 /*END_INCLUDE*/
42 
43 
44 /**
45  * \struct
46  * Describe a currency_link
47  */
48 typedef struct	_CurrencyLink		 CurrencyLink;
49 
50 struct _CurrencyLink
51 {
52     gint currency_link_number;
53 
54     gint first_currency;
55     gint second_currency;
56     gint fixed_link;  /* si = 1 le lien entre devises est fixe */
57     GsbReal change_rate;
58     GDate *modified_date;
59 
60     /* a link is invalid when :
61      * - it's a comparison between 2 same currencies
62      * - the same link exists before
63      * it's set invalid while the configuration */
64     gboolean invalid_link;
65 
66 };
67 
68 /*START_STATIC*/
69 static void _g_data_currency_link_free ( CurrencyLink *currency_link );
70 static gboolean gsb_data_currency_link_check_for_invalid ( gint currency_link_number );
71 static gpointer gsb_data_currency_link_get_structure ( gint currency_link_number );
72 static gint gsb_data_currency_link_max_number ( void );
73 /*END_STATIC*/
74 
75 /*START_EXTERN*/
76 /*END_EXTERN*/
77 
78 /** contains the g_slist of CurrencyLink */
79 static GSList *currency_link_list = NULL;
80 
81 /** a pointer to the last currency_link used (to increase the speed) */
82 static CurrencyLink *currency_link_buffer;
83 
84 
85 /**
86  * set the currency_links global variables to NULL, usually when we init all the global variables
87  *
88  * \param none
89  *
90  * \return FALSE
91  * */
gsb_data_currency_link_init_variables(void)92 gboolean gsb_data_currency_link_init_variables ( void )
93 {
94     if ( currency_link_list )
95     {
96         GSList* tmp_list = currency_link_list;
97         while ( tmp_list )
98         {
99 	    CurrencyLink *currency_link;
100 	    currency_link = tmp_list -> data;
101 	    tmp_list = tmp_list -> next;
102             _g_data_currency_link_free ( currency_link );
103         }
104 	g_slist_free ( currency_link_list );
105     }
106     currency_link_list = NULL;
107     currency_link_buffer = NULL;
108     return FALSE;
109 }
110 
111 
112 /**
113  * find and return the structure of the currency_link asked
114  *
115  * \param currency_link_number number of currency_link
116  *
117  * \return the adr of the struct of the currency_link (NULL if doesn't exit)
118  * */
gsb_data_currency_link_get_structure(gint currency_link_number)119 gpointer gsb_data_currency_link_get_structure ( gint currency_link_number )
120 {
121     GSList *tmp;
122 
123     if (!currency_link_number)
124 	return NULL;
125 
126     /* before checking all the currency_links, we check the buffer */
127 
128     if ( currency_link_buffer
129 	 &&
130 	 currency_link_buffer -> currency_link_number == currency_link_number )
131 	return currency_link_buffer;
132 
133     tmp = currency_link_list;
134 
135     while ( tmp )
136     {
137 	CurrencyLink *currency_link;
138 
139 	currency_link = tmp -> data;
140 
141 	if ( currency_link -> currency_link_number == currency_link_number )
142 	{
143 	    currency_link_buffer = currency_link;
144 	    return currency_link;
145 	}
146 	tmp = tmp -> next;
147     }
148     return NULL;
149 }
150 
151 /**
152  * return the number of the currency_link given in param
153  *
154  * \param currency_link_ptr a pointer to the struct of the currency_link
155  *
156  * \return the number of the currency_link, 0 if problem
157  * */
gsb_data_currency_link_get_no_currency_link(gpointer currency_link_ptr)158 gint gsb_data_currency_link_get_no_currency_link ( gpointer currency_link_ptr )
159 {
160     CurrencyLink *currency_link;
161 
162     if ( !currency_link_ptr )
163 	return 0;
164 
165     currency_link = currency_link_ptr;
166     currency_link_buffer = currency_link;
167     return currency_link -> currency_link_number;
168 }
169 
170 
171 /**
172  * give the g_slist of currency_link structure
173  * usefull when want to check all currency_links
174  *
175  * \param none
176  *
177  * \return the g_slist of currency_links structure
178  * */
gsb_data_currency_link_get_currency_link_list(void)179 GSList *gsb_data_currency_link_get_currency_link_list ( void )
180 {
181     return currency_link_list;
182 }
183 
184 
185 
186 /**
187  * find and return the last number of currency_link
188  *
189  * \param none
190  *
191  * \return last number of currency_link
192  * */
gsb_data_currency_link_max_number(void)193 gint gsb_data_currency_link_max_number ( void )
194 {
195     GSList *tmp;
196     gint number_tmp = 0;
197 
198     tmp = currency_link_list;
199 
200     while ( tmp )
201     {
202 	CurrencyLink *currency_link;
203 
204 	currency_link = tmp -> data;
205 
206 	if ( currency_link -> currency_link_number > number_tmp )
207 	    number_tmp = currency_link -> currency_link_number;
208 
209 	tmp = tmp -> next;
210     }
211     return number_tmp;
212 }
213 
214 
215 /**
216  * create a new currency_link, give him a number, append it to the list
217  * and return the number
218  *
219  * \param currency_link_number the number of the new currency link or 0 for automatic
220  * 		(should be always automatic, except while loading a file)
221  *
222  * \return the number of the new currency_link
223  * */
gsb_data_currency_link_new(gint currency_link_number)224 gint gsb_data_currency_link_new ( gint currency_link_number )
225 {
226     CurrencyLink *currency_link;
227 
228     currency_link = g_malloc0 ( sizeof ( CurrencyLink ));
229 
230     if (currency_link_number)
231 	currency_link -> currency_link_number = currency_link_number;
232     else
233 	currency_link -> currency_link_number = gsb_data_currency_link_max_number () + 1;
234 
235     currency_link -> modified_date = gdate_today ( );
236 
237     currency_link_list = g_slist_append ( currency_link_list, currency_link );
238 
239     return currency_link -> currency_link_number;
240 }
241 
242 
243 /**
244  * This internal function is called to free the memory used by a CurrencyLink structure.
245  */
_g_data_currency_link_free(CurrencyLink * currency_link)246 static void _g_data_currency_link_free ( CurrencyLink *currency_link )
247 {
248     if ( ! currency_link )
249         return ;
250     if ( currency_link -> modified_date )
251         g_date_free ( currency_link -> modified_date );
252     g_free (currency_link);
253     if ( currency_link_buffer == currency_link )
254 	currency_link_buffer = NULL;
255 }
256 
257 /**
258  * remove a currency_link
259  * set all the currency_links of transaction which are this one to 0
260  * update combofix and mark file as modified
261  *
262  * \param currency_link_number the currency_link we want to remove
263  *
264  * \return TRUE ok
265  * */
gsb_data_currency_link_remove(gint currency_link_number)266 gboolean gsb_data_currency_link_remove ( gint currency_link_number )
267 {
268     CurrencyLink *currency_link;
269 
270     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
271 
272     if (!currency_link)
273 	return FALSE;
274 
275     currency_link_list = g_slist_remove ( currency_link_list,
276 					  currency_link );
277 
278     _g_data_currency_link_free ( currency_link );
279 
280     return TRUE;
281 }
282 
283 
284 /**
285  * set a new number for the currency_link
286  * normally used only while loading the file because
287  * the number are given automaticly
288  *
289  * \param currency_link_number the number of the currency_link
290  * \param new_no_currency_link the new number of the currency_link
291  *
292  * \return the new number or 0 if the currency_link doen't exist
293  * */
gsb_data_currency_link_set_new_number(gint currency_link_number,gint new_no_currency_link)294 gint gsb_data_currency_link_set_new_number ( gint currency_link_number,
295                         gint new_no_currency_link )
296 {
297     CurrencyLink *currency_link;
298 
299     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
300 
301     if (!currency_link)
302 	return 0;
303 
304     currency_link -> currency_link_number = new_no_currency_link;
305     return new_no_currency_link;
306 }
307 
308 
309 
310 /**
311  * return the first_currency of the currency_link
312  *
313  * \param currency_link_number the number of the currency_link
314  *
315  * \return the first_currency of the currency_link or 0 if fail
316  * */
gsb_data_currency_link_get_first_currency(gint currency_link_number)317 gint gsb_data_currency_link_get_first_currency ( gint currency_link_number )
318 {
319     CurrencyLink *currency_link;
320 
321     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
322 
323     if (!currency_link)
324 	return 0;
325 
326     return currency_link -> first_currency;
327 }
328 
329 
330 /**
331  * set the first_currency of the currency_link
332  * check and fill the invalid flag
333  *
334  * \param currency_link_number the number of the currency_link
335  * \param first_currency the first_currency of the currency_link
336  *
337  * \return TRUE if ok or FALSE if problem
338  * */
gsb_data_currency_link_set_first_currency(gint currency_link_number,gint first_currency)339 gboolean gsb_data_currency_link_set_first_currency ( gint currency_link_number,
340                         gint first_currency )
341 {
342     CurrencyLink *currency_link;
343 
344     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
345 
346     if (!currency_link)
347 	return FALSE;
348 
349     currency_link -> first_currency = first_currency;
350     gsb_data_currency_link_check_for_invalid (currency_link_number);
351 
352     return TRUE;
353 }
354 
355 
356 /**
357  * return the second_currency of the currency_link
358  *
359  * \param currency_link_number the number of the currency_link
360  *
361  * \return the second_currency of the currency_link or 0 if fail
362  * */
gsb_data_currency_link_get_second_currency(gint currency_link_number)363 gint gsb_data_currency_link_get_second_currency ( gint currency_link_number )
364 {
365     CurrencyLink *currency_link;
366 
367     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
368 
369     if (!currency_link)
370 	return 0;
371 
372     return currency_link -> second_currency;
373 }
374 
375 
376 /**
377  * set the second_currency of the currency_link
378  * check and fill the invalid flag
379  *
380  * \param currency_link_number the number of the currency_link
381  * \param second_currency the second_currency of the currency_link
382  *
383  * \return TRUE if ok or FALSE if problem
384  * */
gsb_data_currency_link_set_second_currency(gint currency_link_number,gint second_currency)385 gboolean gsb_data_currency_link_set_second_currency ( gint currency_link_number,
386                         gint second_currency )
387 {
388     CurrencyLink *currency_link;
389 
390     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
391 
392     if (!currency_link)
393 	return FALSE;
394 
395     currency_link -> second_currency = second_currency;
396     gsb_data_currency_link_check_for_invalid (currency_link_number);
397 
398     return TRUE;
399 }
400 
401 
402 /**
403  * return the change_rate of the currency_link *
404  * \param currency_link_number the number of the currency_link
405  *
406  * \return the change_rate of the currency_link or 0 if problem
407  * */
gsb_data_currency_link_get_change_rate(gint currency_link_number)408 GsbReal gsb_data_currency_link_get_change_rate ( gint currency_link_number )
409 {
410     CurrencyLink *currency_link;
411 
412     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
413 
414     if (!currency_link)
415 	return null_real;
416 
417     return currency_link -> change_rate;
418 }
419 
420 
421 /**
422  * set the change_rate of the currency_link
423  *
424  * \param currency_link_number the number of the currency_link
425  * \param  the  of the currency_link
426  *
427  * \return TRUE if ok or FALSE if problem
428  * */
gsb_data_currency_link_set_change_rate(gint currency_link_number,GsbReal change_rate)429 gboolean gsb_data_currency_link_set_change_rate ( gint currency_link_number,
430                         GsbReal change_rate )
431 {
432     CurrencyLink *currency_link;
433 
434     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
435 
436     if (!currency_link)
437 	return FALSE;
438 
439     currency_link -> change_rate = change_rate;
440 
441     return TRUE;
442 }
443 
444 
445 
446 /**
447  * return the invalid_link of the currency_link
448  * the flag invalid is set automatickly by gsb_data_currency_link_check_for_invalid
449  * when change 1 of the currency
450  *
451  * \param currency_link_number the number of the currency_link
452  *
453  * \return TRUE if the link is invalid
454  * */
gsb_data_currency_link_get_invalid_link(gint currency_link_number)455 gint gsb_data_currency_link_get_invalid_link ( gint currency_link_number )
456 {
457     CurrencyLink *currency_link;
458 
459     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
460 
461     if (!currency_link)
462 	return 0;
463 
464     return currency_link -> invalid_link;
465 }
466 
467 
468 
469 /**
470  * return the message error because of the invalid link
471  *
472  * \param currency_link_number the number of the currency_link
473  *
474  * \return a const gchar formatted with markup : error the message
475  * */
gsb_data_currency_link_get_invalid_message(gint currency_link_number)476 const gchar *gsb_data_currency_link_get_invalid_message ( gint currency_link_number )
477 {
478     CurrencyLink *currency_link;
479 
480     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
481 
482     if (!currency_link)
483         return 0;
484 
485     if (!currency_link -> invalid_link)
486         return NULL;
487 
488     if ( currency_link -> first_currency == currency_link -> second_currency)
489         return dialogue_make_red ( _("Warning : the two currencies of the link are identicals.") );
490 
491     return dialogue_make_red ( _("Warning : that link is already defined.") );
492 }
493 
494 
495 /**
496  * check if the link is invalid and set the flag
497  * a link is invalid if :
498  * - the 2 currencies are the same
499  * - another similar link exists already
500  * an invalid link will not be used by grisbi and showed as invalid in the configuration
501  *
502  * \param currency_link_number the number of the currency_link to check
503  *
504  * \return TRUE  if invalid, FALSE if not
505  * */
gsb_data_currency_link_check_for_invalid(gint currency_link_number)506 gboolean gsb_data_currency_link_check_for_invalid ( gint currency_link_number )
507 {
508     CurrencyLink *currency_link;
509     GSList *tmp_list;
510 
511     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
512 
513     if (!currency_link)
514 	return FALSE;
515 
516     /* first check : if the 2 currencies are identical */
517 
518     if ( currency_link -> first_currency == currency_link -> second_currency)
519     {
520 	currency_link -> invalid_link = TRUE;
521 	return TRUE;
522     }
523 
524     /* second check : if that link exists already */
525 
526     tmp_list = currency_link_list;
527 
528     while (tmp_list)
529     {
530 	CurrencyLink *tmp_currency_link;
531 
532 	tmp_currency_link = tmp_list -> data;
533 
534 	if ( tmp_currency_link -> currency_link_number != currency_link -> currency_link_number
535 	     &&
536 	     (( tmp_currency_link -> first_currency == currency_link -> first_currency
537 		&&
538 		tmp_currency_link -> second_currency == currency_link -> second_currency )
539 	      ||
540 	      ( tmp_currency_link -> first_currency == currency_link -> second_currency
541 		&&
542 		tmp_currency_link -> second_currency == currency_link -> first_currency )))
543 	{
544 	    currency_link -> invalid_link = TRUE;
545 	    return TRUE;
546 	}
547 
548 	tmp_list = tmp_list -> next;
549     }
550 
551     /* it's ok, the link is valid */
552     currency_link -> invalid_link = FALSE;
553 
554     return FALSE;
555 }
556 
557 
558 /**
559  * look for a link between the 2 currencies given in the param
560  *
561  * \param currency_1 the number of the first currency
562  * \param currency_2 the number of the second currency
563  *
564  * \return the number of the link, 0 if not found, -1 if they are the same currencies
565  * */
gsb_data_currency_link_search(gint currency_1,gint currency_2)566 gint gsb_data_currency_link_search ( gint currency_1,
567                         gint currency_2 )
568 {
569     GSList *tmp_list;
570 
571     if (!currency_1
572 	||
573 	!currency_2 )
574 	return 0;
575 
576     if ( currency_1 == currency_2 )
577 	return -1;
578 
579     tmp_list = currency_link_list;
580 
581     while (tmp_list)
582     {
583 	CurrencyLink *tmp_currency_link;
584 
585 	tmp_currency_link = tmp_list -> data;
586 
587 	if ( !tmp_currency_link -> invalid_link
588 	     &&
589 	     (( tmp_currency_link -> first_currency == currency_1
590 		&&
591 		tmp_currency_link -> second_currency == currency_2 )
592 	      ||
593 	      ( tmp_currency_link -> first_currency == currency_2
594 		&&
595 		tmp_currency_link -> second_currency == currency_1 )))
596 	    return tmp_currency_link -> currency_link_number;
597 
598 	tmp_list = tmp_list -> next;
599     }
600     return 0;
601 }
602 
603 
604 /**
605  * get the GDate of the currency link
606  *
607  * \param currency_link_number
608  *
609  * \return the GDate of the currency link
610  * */
gsb_data_currency_link_get_modified_date(gint currency_link_number)611 GDate *gsb_data_currency_link_get_modified_date ( gint currency_link_number )
612 {
613     CurrencyLink *currency_link;
614 
615     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
616 
617     if (!currency_link)
618         return NULL;
619 
620     return currency_link -> modified_date;
621 }
622 
623 
624 /**
625  * set the GDate of the currency link
626  *
627  * \param currency_link_number
628  * \param date
629  *
630  * \return TRUE if ok
631  * */
gsb_data_currency_link_set_modified_date(gint currency_link_number,GDate * date)632 gboolean gsb_data_currency_link_set_modified_date ( gint currency_link_number,
633                         GDate *date )
634 {
635     CurrencyLink *currency_link;
636 
637     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
638 
639     if ( !currency_link )
640         return FALSE;
641 
642     if ( !date )
643         return FALSE;
644 
645     if ( currency_link -> modified_date )
646         g_date_free ( currency_link -> modified_date );
647 
648     currency_link -> modified_date = gsb_date_copy ( date );
649 
650     return TRUE;
651 }
652 
653 
654 /**
655  * return the change_link_currency flag
656  *
657  * \param currency_link_number the number of the currency_link
658  *
659  * \return TRUE if ok or FALSE if no ok
660  * */
gsb_data_currency_link_get_fixed_link(gint currency_link_number)661 gboolean gsb_data_currency_link_get_fixed_link ( gint currency_link_number )
662 {
663     CurrencyLink *currency_link;
664 
665     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
666 
667     if ( !currency_link )
668 	    return FALSE;
669 
670     return currency_link -> fixed_link;
671 }
672 
673 
674 /**
675  * set the change_link_currency flag
676  *
677  * \param currency_link_number the number of the currency_link
678  * \param  the change_link_currency flag for the currency_link
679  *
680  * \return TRUE if ok or FALSE if problem
681  * */
gsb_data_currency_link_set_fixed_link(gint currency_link_number,gboolean fixed_link)682 gboolean gsb_data_currency_link_set_fixed_link ( gint currency_link_number,
683                         gboolean fixed_link )
684 {
685     CurrencyLink *currency_link;
686 
687     currency_link = gsb_data_currency_link_get_structure ( currency_link_number );
688 
689     if ( !currency_link )
690 	    return FALSE;
691 
692     currency_link -> fixed_link = fixed_link;
693 
694     return TRUE;
695 }
696 
697 
698 /* Local Variables: */
699 /* c-basic-offset: 4 */
700 /* End: */
701