1 /* ************************************************************************** */
2 /*                                                                            */
3 /*                                                                            */
4 /*     Copyright (C)    2000-2008 Cédric Auger (cedric@grisbi.org)            */
5 /*          https://www.grisbi.org/                                            */
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_fyear_data.c
25  * work with the fyear 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_fyear.h"
38 #include "dialog.h"
39 #include "gsb_fyear.h"
40 #include "structures.h"
41 #include "utils_dates.h"
42 #include "utils_str.h"
43 /*END_INCLUDE*/
44 
45 
46 /**
47  * describe the invalid numbers
48  * */
49 enum fyear_invalid {
50     FYEAR_INVALID_DATE_ORDER = 1,
51     FYEAR_INVALID_CROSS,
52     FYEAR_INVALID_DATE
53 };
54 
55 /*START_STATIC*/
56 static void _gsb_data_fyear_free ( FyearStruct *fyear );
57 static gpointer gsb_data_fyear_get_structure ( gint fyear_number );
58 static gint gsb_data_fyear_max_number ( void );
59 /*END_STATIC*/
60 
61 /*START_EXTERN*/
62 /*END_EXTERN*/
63 
64 /** contains the g_slist of FyearStruct */
65 static GSList *fyear_list = NULL;
66 
67 /** a pointer to the last fyear used (to increase the speed) */
68 static FyearStruct *fyear_buffer;
69 
70 
71 /**
72  * set the fyears global variables to NULL,
73  * usually when we init all the global variables
74  *
75  * \param
76  *
77  * \return FALSE
78  * */
gsb_data_fyear_init_variables(void)79 gboolean gsb_data_fyear_init_variables ( void )
80 {
81     if ( fyear_list )
82     {
83         GSList* tmp_list  = fyear_list;
84         while ( tmp_list  )
85         {
86 	    FyearStruct *fyear;
87 	    fyear = tmp_list  -> data;
88 	    tmp_list = tmp_list -> next;
89 	    _gsb_data_fyear_free ( fyear );
90 	}
91         g_slist_free ( fyear_list );
92     }
93     fyear_list = NULL;
94     fyear_buffer = NULL;
95     return FALSE;
96 }
97 
98 
99 /**
100  * find and return the structure of the fyear asked
101  *
102  * \param fyear_number number of fyear
103  *
104  * \return the adr of the struct of the fyear (NULL if doesn't exit)
105  * */
gsb_data_fyear_get_structure(gint fyear_number)106 gpointer gsb_data_fyear_get_structure ( gint fyear_number )
107 {
108     GSList *tmp;
109 
110     if (!fyear_number)
111 	    return NULL;
112 
113     /* before checking all the fyears, we check the buffer */
114 
115     if ( fyear_buffer
116 	 &&
117 	 fyear_buffer -> fyear_number == fyear_number )
118 	    return fyear_buffer;
119 
120     tmp = fyear_list;
121 
122     while ( tmp )
123     {
124         FyearStruct *fyear;
125 
126 	    fyear = tmp -> data;
127 
128 	    if ( fyear -> fyear_number == fyear_number )
129 	    {
130 	        fyear_buffer = fyear;
131 	        return fyear;
132 	    }
133 
134 	    tmp = tmp -> next;
135     }
136     return NULL;
137 }
138 
139 
140 /**
141  * give the g_slist of fyears structure
142  * usefull when want to check all fyears
143  *
144  * \param none
145  *
146  * \return the g_slist of fyears structure
147  * */
gsb_data_fyear_get_fyears_list(void)148 GSList *gsb_data_fyear_get_fyears_list ( void )
149 {
150     return fyear_list;
151 }
152 
153 /**
154  * return the number of the fyears given in param
155  *
156  * \param fyear_ptr a pointer to the struct of the fyear
157  *
158  * \return the number of the fyear, 0 if problem
159  * */
gsb_data_fyear_get_no_fyear(gpointer fyear_ptr)160 gint gsb_data_fyear_get_no_fyear ( gpointer fyear_ptr )
161 {
162     FyearStruct *fyear;
163 
164     if ( !fyear_ptr )
165 	return 0;
166 
167     fyear = fyear_ptr;
168     fyear_buffer = fyear;
169     return fyear -> fyear_number;
170 }
171 
172 
173 /**
174  * find and return the last number of fyear
175  *
176  * \param none
177  *
178  * \return last number of fyear
179  * */
gsb_data_fyear_max_number(void)180 gint gsb_data_fyear_max_number ( void )
181 {
182     GSList *tmp;
183     gint number_tmp = 0;
184 
185     tmp = fyear_list;
186 
187     while ( tmp )
188     {
189 	FyearStruct *fyear;
190 
191 	fyear = tmp -> data;
192 
193 	if ( fyear -> fyear_number > number_tmp )
194 	    number_tmp = fyear -> fyear_number;
195 
196 	tmp = tmp -> next;
197     }
198     return number_tmp;
199 }
200 
201 
202 /**
203  * create a new fyear, give him a number, append it to the list
204  * and return the number
205  *
206  * \param name the name of the fyear (can be freed after, it's a copy) or NULL
207  *
208  * \return the number of the new fyear
209  * */
gsb_data_fyear_new(const gchar * name)210 gint gsb_data_fyear_new ( const gchar *name )
211 {
212     FyearStruct *fyear;
213 
214     fyear = g_malloc0 ( sizeof ( FyearStruct ));
215     fyear -> fyear_number = gsb_data_fyear_max_number () + 1;
216 
217     if (name)
218 	fyear -> fyear_name = my_strdup (name);
219     else
220 	fyear -> fyear_name = NULL;
221 
222     fyear_list = g_slist_append ( fyear_list, fyear );
223     fyear_buffer = fyear;
224 
225     return fyear -> fyear_number;
226 }
227 
228 
229 /**
230  * This internal function is called to free the memory used by a FyearStruct structure
231  */
_gsb_data_fyear_free(FyearStruct * fyear)232 static void _gsb_data_fyear_free ( FyearStruct *fyear )
233 {
234     if ( ! fyear )
235 	return;
236     if ( fyear -> fyear_name )
237 	g_free ( fyear -> fyear_name );
238     if ( fyear -> beginning_date )
239 	g_date_free ( fyear -> beginning_date );
240     if ( fyear -> end_date )
241 	g_date_free ( fyear -> end_date );
242     g_free ( fyear );
243     if ( fyear_buffer == fyear )
244 	fyear_buffer = NULL;
245 }
246 
247 /**
248  * remove a fyear
249  * set all the fyears of transaction which are this one to 0
250  *
251  * \param fyear_number the fyear we want to remove
252  *
253  * \return TRUE ok
254  * */
gsb_data_fyear_remove(gint fyear_number)255 gboolean gsb_data_fyear_remove ( gint fyear_number )
256 {
257     FyearStruct *fyear;
258 
259     fyear = gsb_data_fyear_get_structure ( fyear_number );
260 
261     if (!fyear)
262 	return FALSE;
263 
264     fyear_list = g_slist_remove ( fyear_list,
265 				  fyear );
266 
267     _gsb_data_fyear_free ( fyear );
268 
269     return TRUE;
270 }
271 
272 
273 /**
274  * set a new number for the fyear
275  * normally used only while loading the file because
276  * the number are given automaticly
277  *
278  * \param fyear_number the number of the fyear
279  * \param new_no_fyear the new number of the fyear
280  *
281  * \return the new number or 0 if the fyear doen't exist
282  * */
gsb_data_fyear_set_new_number(gint fyear_number,gint new_no_fyear)283 gint gsb_data_fyear_set_new_number ( gint fyear_number,
284                         gint new_no_fyear )
285 {
286     FyearStruct *fyear;
287 
288     fyear = gsb_data_fyear_get_structure ( fyear_number );
289 
290     if (!fyear)
291 	return 0;
292 
293     fyear -> fyear_number = new_no_fyear;
294     return new_no_fyear;
295 }
296 
297 
298 /**
299  * return the name of the fyear
300  *
301  * \param fyear_number the number of the fyear
302  *
303  * \return the name of the fyear or NULL if fail
304  * */
gsb_data_fyear_get_name(gint fyear_number)305 const gchar *gsb_data_fyear_get_name ( gint fyear_number )
306 {
307     FyearStruct *fyear;
308 
309     fyear = gsb_data_fyear_get_structure ( fyear_number );
310 
311     if (!fyear)
312         return NULL;
313 
314     return fyear -> fyear_name;
315 }
316 
317 
318 /**
319  * set the name of the fyear
320  * the value is dupplicate in memory
321  *
322  * \param fyear_number the number of the fyear
323  * \param name the name of the fyear
324  *
325  * \return TRUE if ok or FALSE if problem
326  * */
gsb_data_fyear_set_name(gint fyear_number,const gchar * name)327 gboolean gsb_data_fyear_set_name ( gint fyear_number,
328 				   const gchar *name )
329 {
330     FyearStruct *fyear;
331 
332     fyear = gsb_data_fyear_get_structure ( fyear_number );
333 
334     if (!fyear)
335 	return FALSE;
336 
337     /* we free the last name */
338     if ( fyear -> fyear_name )
339 	g_free (fyear -> fyear_name);
340 
341     /* and copy the new one */
342     fyear -> fyear_name = my_strdup (name);
343 
344    /* update list fyear in form */
345     if (fyear -> showed_in_form)
346 	gsb_fyear_update_fyear_list ();
347 
348     return TRUE;
349 }
350 
351 
352 
353 /**
354  * return the beginning date of the fyear
355  *
356  * \param fyear_number the number of the fyear
357  *
358  * \return the beginning date of the fyear or NULL if fail
359  * */
gsb_data_fyear_get_beginning_date(gint fyear_number)360 GDate *gsb_data_fyear_get_beginning_date ( gint fyear_number )
361 {
362     FyearStruct *fyear;
363 
364     fyear = gsb_data_fyear_get_structure ( fyear_number );
365 
366     if (!fyear)
367 	return NULL;
368 
369     return fyear -> beginning_date;
370 }
371 
372 
373 /**
374  * set the beginning date of the fyear
375  * the value is dupplicate in memory
376  *
377  * \param fyear_number the number of the fyear
378  * \param date the beginning date of the fyear
379  *
380  * \return TRUE if ok or FALSE if problem
381  * */
gsb_data_fyear_set_beginning_date(gint fyear_number,GDate * date)382 gboolean gsb_data_fyear_set_beginning_date ( gint fyear_number,
383 					    GDate *date )
384 {
385     FyearStruct *fyear;
386 
387     fyear = gsb_data_fyear_get_structure ( fyear_number );
388 
389     if (!fyear)
390 	return FALSE;
391 
392     /* we free the last date */
393     if ( fyear -> beginning_date )
394 	g_date_free (fyear -> beginning_date);
395 
396     /* and copy the new one */
397     fyear -> beginning_date = gsb_date_copy (date);
398 
399     return TRUE;
400 }
401 
402 
403 /**
404  * return the end date of the fyear
405  *
406  * \param fyear_number the number of the fyear
407  *
408  * \return the end date of the fyear or NULL if fail
409  * */
gsb_data_fyear_get_end_date(gint fyear_number)410 GDate *gsb_data_fyear_get_end_date ( gint fyear_number )
411 {
412     FyearStruct *fyear;
413 
414     fyear = gsb_data_fyear_get_structure ( fyear_number );
415 
416     if (!fyear)
417 	return NULL;
418 
419     return fyear -> end_date;
420 }
421 
422 
423 /**
424  * set the end date of the fyear
425  * the value is dupplicate in memory
426  *
427  * \param fyear_number the number of the fyear
428  * \param date the end date of the fyear
429  *
430  * \return TRUE if ok or FALSE if problem
431  * */
gsb_data_fyear_set_end_date(gint fyear_number,GDate * date)432 gboolean gsb_data_fyear_set_end_date ( gint fyear_number,
433 				       GDate *date )
434 {
435     FyearStruct *fyear;
436 
437     fyear = gsb_data_fyear_get_structure ( fyear_number );
438 
439     if (!fyear)
440 	return FALSE;
441 
442     /* we free the last date */
443     if ( fyear -> end_date )
444 	g_date_free (fyear -> end_date);
445 
446     /* and copy the new one */
447     fyear -> end_date = gsb_date_copy (date);
448 
449     return TRUE;
450 }
451 
452 
453 
454 /**
455  * return the showed_in_form of the fyear
456  *
457  * \param fyear_number the number of the fyear
458  *
459  * \return the showed_in_form of the fyear or NULL if fail
460  * */
gsb_data_fyear_get_form_show(gint fyear_number)461 gboolean gsb_data_fyear_get_form_show ( gint fyear_number )
462 {
463     FyearStruct *fyear;
464 
465     fyear = gsb_data_fyear_get_structure ( fyear_number );
466 
467     if (!fyear)
468 	return FALSE;
469 
470     return fyear -> showed_in_form;
471 }
472 
473 
474 /**
475  * set the showed_in_form of the fyear
476  *
477  * \param fyear_number the number of the fyear
478  * \param showed_in_form the showed_in_form of the fyear
479  *
480  * \return TRUE if ok or FALSE if problem
481  * */
gsb_data_fyear_set_form_show(gint fyear_number,gboolean showed_in_form)482 gboolean gsb_data_fyear_set_form_show ( gint fyear_number,
483 					gboolean showed_in_form )
484 {
485     FyearStruct *fyear;
486 
487     fyear = gsb_data_fyear_get_structure ( fyear_number );
488 
489     if (!fyear)
490 	return FALSE;
491 
492     /* and copy the new one */
493     fyear -> showed_in_form = showed_in_form;
494 
495     /* update list fyear in form */
496     gsb_fyear_update_fyear_list ();
497 
498     return TRUE;
499 }
500 
501 
502 /**
503  * return the invalid_fyear of the fyear
504  * the flag invalid is set automatickly by gsb_data_fyear_check_for_invalid
505  *
506  * \param fyear_number the number of the fyear
507  *
508  * \return TRUE if the fyear is invalid
509  * */
gsb_data_fyear_get_invalid(gint fyear_number)510 gint gsb_data_fyear_get_invalid ( gint fyear_number )
511 {
512     FyearStruct *fyear;
513 
514     fyear = gsb_data_fyear_get_structure ( fyear_number );
515 
516     if (!fyear)
517 	return FALSE;
518 
519     return fyear -> invalid_fyear;
520 }
521 
522 /**
523  * return the message error because of the invalid fyear
524  *
525  * \param fyear_number the number of the fyear
526  *
527  * \return a const gchar formatted with markup : error the message or NULL if not exist
528  * */
gsb_data_fyear_get_invalid_message(gint fyear_number)529 const gchar *gsb_data_fyear_get_invalid_message ( gint fyear_number )
530 {
531     FyearStruct *fyear;
532     gchar *string = NULL;
533 
534     fyear = gsb_data_fyear_get_structure ( fyear_number );
535 
536     if ( !fyear || !fyear -> invalid_fyear )
537         return NULL;
538 
539     switch ( fyear -> invalid_fyear )
540     {
541     case FYEAR_INVALID_DATE_ORDER:
542         string = dialogue_make_red ( _("Warning : the dates are not in good order.") );
543         break;
544     case FYEAR_INVALID_CROSS:
545         string = dialogue_make_red ( _("Warning : that financial year cross with another one.") );
546         break;
547     case FYEAR_INVALID_DATE:
548         string = dialogue_make_red ( _("Warning : Invalid date.") );
549         break;
550     }
551 
552     return string;
553 }
554 
555 /**
556  * check all the fyear if the are invalid and set their flag
557  * normaly called to each change of a fyear
558  * an invalid fyear will not be used by grisbi and showed as invalid in the configuration
559  *
560  * \param fyear_number the number of the fyear to check
561  *
562  * \return TRUE  if invalid, FALSE if not
563  * */
gsb_data_fyear_check_all_for_invalid(void)564 void gsb_data_fyear_check_all_for_invalid ( void )
565 {
566     GSList *tmp_list;
567 
568     tmp_list = fyear_list;
569 
570     while (tmp_list)
571     {
572 	fyear_buffer = tmp_list -> data;
573 	gsb_data_fyear_check_for_invalid ( fyear_buffer -> fyear_number);
574 
575 	tmp_list = tmp_list -> next;
576     }
577 }
578 
579 
580 /**
581  * check if the fyear is invalid and set the flag
582  * a fyear is invalid
583  * an invalid fyear will not be used by grisbi and showed as invalid in the configuration
584  *
585  * \param fyear_number the number of the fyear to check
586  *
587  * \return TRUE  if invalid, FALSE if not
588  * */
gsb_data_fyear_check_for_invalid(gint fyear_number)589 gboolean gsb_data_fyear_check_for_invalid ( gint fyear_number )
590 {
591     FyearStruct *fyear;
592 
593     fyear = gsb_data_fyear_get_structure ( fyear_number );
594 
595     if (!fyear)
596 	return FALSE;
597 
598     /* check if there is some good date */
599     if (!fyear -> beginning_date
600 	||
601 	!fyear -> end_date)
602     {
603 	fyear -> invalid_fyear = FYEAR_INVALID_DATE;
604 	return TRUE;
605     }
606 
607     /* first : we check that the first date is above the second */
608     if ( g_date_compare (fyear -> beginning_date,
609 			 fyear -> end_date) > 0)
610     {
611 	fyear -> invalid_fyear = FYEAR_INVALID_DATE_ORDER;
612 	return TRUE;
613     }
614 
615     /* second : we check if there is not a cross with another fyear */
616     if ( (gsb_data_fyear_get_from_date (fyear -> beginning_date) != fyear_number)
617 	 ||
618 	 (gsb_data_fyear_get_from_date (fyear -> end_date) != fyear_number))
619     {
620 	fyear -> invalid_fyear = FYEAR_INVALID_CROSS;
621 	return TRUE;
622     }
623 
624     /* it's ok, the fyear is valid */
625     fyear -> invalid_fyear = FALSE;
626 
627     return FALSE;
628 }
629 
630 
631 
632 /**
633  * get the financial year corresponding to the given date
634  * if there is more than 1 financial year corresponding to that date, return -1
635  *
636  * \param date
637  *
638  * \return the number of financial year, 0 if none on that date, -1 if more than 1 on that date
639  * */
gsb_data_fyear_get_from_date(const GDate * date)640 gint gsb_data_fyear_get_from_date ( const GDate *date )
641 {
642     GSList *tmp_list;
643     gint return_value = 0;
644 
645     if (!date)
646 	return 0;
647 
648     tmp_list = fyear_list;
649     while (tmp_list)
650     {
651 	FyearStruct *fyear;
652 
653 	fyear = tmp_list -> data;
654 
655 	/* check the fyear only if the dates are valid */
656 	if (fyear -> beginning_date && fyear -> end_date)
657 	{
658 	    if ( g_date_compare ( date, fyear -> beginning_date) >= 0
659 		 &&
660 		 g_date_compare ( date, fyear -> end_date) <= 0 )
661 	    {
662 		if (return_value)
663 		    return_value = -1;
664 		else
665 		    return_value = fyear -> fyear_number;
666 	    }
667 	}
668 	tmp_list = tmp_list -> next;
669     }
670     return return_value;
671 }
672 
673 
674 /**
675  * compare 2 financial years
676  *
677  * \param fyear_number_1
678  * \param fyear_number_2
679  *
680  * \return -1 if fyear 1 is before 2 ; +1 if fyear 1 is after 2 ; 0 if problem
681  * */
gsb_data_fyear_compare(gint fyear_number_1,gint fyear_number_2)682 gint gsb_data_fyear_compare ( gint fyear_number_1, gint fyear_number_2 )
683 {
684     FyearStruct *fyear_1;
685     FyearStruct *fyear_2;
686 
687     fyear_1 = gsb_data_fyear_get_structure (fyear_number_1);
688     fyear_2 = gsb_data_fyear_get_structure (fyear_number_2);
689 
690     return gsb_data_fyear_compare_from_struct ( fyear_1, fyear_2, 0);
691 
692  }
693 
694 
695 /**
696  * compare 2 financial years bye FyearStruct *fyear
697  *
698  * \param FyearStruct *fyear_1
699  * \param FyearStruct *fyear_2
700  *
701  * \return -1 if fyear 2 is before 1 ; +1 if fyear 2 is after 1 ; 0 if problem
702  * */
gsb_data_fyear_compare_from_struct(FyearStruct * fyear_1,FyearStruct * fyear_2,gpointer sort_order)703 gint gsb_data_fyear_compare_from_struct (FyearStruct *fyear_1,
704 										 FyearStruct *fyear_2,
705 										 gpointer sort_order)
706 {
707 	gint fyear_combobox_sort_order;
708 
709 	fyear_combobox_sort_order = GPOINTER_TO_INT (sort_order);
710 
711     if ( !fyear_1 || !fyear_2 )
712 	{
713         return 0;
714 	}
715 
716 	if (fyear_combobox_sort_order)
717 	{
718 		if ( !fyear_1 -> beginning_date )
719 			return 1;
720 		if ( !fyear_2 -> beginning_date )
721 			return 1;
722 
723 		if ( g_date_compare ( fyear_1 -> end_date, fyear_2 -> beginning_date ) < 0 )
724 			return 1;
725 		if ( g_date_compare ( fyear_1 -> beginning_date, fyear_2 -> end_date ) > 0 )
726 			return -1;
727 		return 0;
728 	}
729 	else
730 	{
731 		if ( !fyear_1 -> beginning_date )
732 			return -1;
733 		if ( !fyear_2 -> beginning_date )
734 			return -1;
735 
736 		if ( g_date_compare ( fyear_1 -> end_date, fyear_2 -> beginning_date ) < 0 )
737 			return -1;
738 		if ( g_date_compare ( fyear_1 -> beginning_date, fyear_2 -> end_date ) > 0 )
739 			return 1;
740 		return 0;
741 	}
742 }
743 
744 
745 /**
746  * retourne l'exercice précédent l'exercice passé en paramètre
747  *
748  * \param fyear_number
749  *
750  * \return previous_fyear_number ou 0 si pas d'exercice precedent
751  * */
gsb_data_fyear_get_previous_financial_year(const gint fyear_number)752 gint gsb_data_fyear_get_previous_financial_year ( const gint fyear_number )
753 {
754     gint previous_fyear_number = 0;
755     GSList *tmp_list;
756 
757     tmp_list = fyear_list;
758 
759     while ( tmp_list )
760     {
761         gint tmp_fyear_number;
762 
763         tmp_fyear_number = gsb_data_fyear_get_no_fyear ( tmp_list -> data );
764 
765         if ( gsb_data_fyear_compare ( fyear_number, tmp_fyear_number ) == 1)
766         {
767             if ( previous_fyear_number )
768             {
769                 if ( gsb_data_fyear_compare ( previous_fyear_number, tmp_fyear_number ) == -1)
770                     previous_fyear_number = tmp_fyear_number;
771             }
772             else
773             {
774                 previous_fyear_number = tmp_fyear_number;
775             }
776         }
777         tmp_list = tmp_list -> next;
778     }
779 
780     return previous_fyear_number;
781 }
782 
783 
784 /**
785  *
786  *
787  * \param
788  *
789  * \return
790  * */
791 /* Local Variables: */
792 /* c-basic-offset: 4 */
793 /* End: */
794