Automatically set parent family in individual, when adding child to the family.
[familia.git] / src / storage / positions.c
1 /****************************************************************************
2  *  Familia Lignum - Genealogical program                                   *
3  *  Copyright (C) 2011-2012 Rafał Długołęcki <rafal@dlugolecki.net.pl>      *
4  *                                                                          *
5  *  This program is free software; you can redistribute it and/or modify    *
6  *  it under the terms of the GNU General Public License as published by    *
7  *  the Free Software Foundation; version 2 of the License.                 *
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           *
12  *  GNU General Public License for more details.                            *
13  *                                                                          *
14  *  You should have received a copy of the GNU General Public License along *
15  *  with this program; if not, write to the Free Software Foundation, Inc., *
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.             *
17  *                                                                          *
18  ****************************************************************************/
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "../debug.h"
24
25 #include "positions.h"
26
27 /**
28  * Structure holding individual and position pair
29  */
30 struct familia_storage_individual_position {
31         struct familia_individual *ind;
32         struct position *pos;
33 };
34
35 /**
36  * Structure holding family and position pair
37  */
38 struct familia_storage_family_position {
39         struct familia_family *fam;
40         struct position *pos;
41 };
42
43 /**
44  * Structure holding individual and family positions
45  */
46 struct familia_storage_positions {
47         struct familia_storage_individual_position **individuals;
48
49         unsigned int individuals_no;
50
51         struct familia_storage_family_position **families;
52
53         unsigned int families_no;
54 };
55
56 /**
57  * Global variable for storing positions of graphic objects.
58  *
59  * Example graphic object is an individual or family...
60  */
61 struct familia_storage_positions * storage_positions;
62
63 /**
64  * Initializes storage for individual and family positions.
65  */
66 void _familia_storage_positions_init()
67 {
68         if (!storage_positions) {
69                 storage_positions = malloc(sizeof(struct familia_storage_positions));
70                 
71                 if (!storage_positions) {
72                         debug("["__FILE__ "] There was a problem with allocating memory for storage of positions.\n");
73                 }
74                 else {
75                         storage_positions->individuals_no = 0;
76                         storage_positions->families_no = 0;
77                 }
78         }
79 }
80
81 /**
82  * Frees storage for the positions
83  */
84 void _familia_storage_positions_free()
85 {
86         if (storage_positions) {
87                 if (storage_positions->individuals) {
88                         free(storage_positions->individuals);
89                 }
90
91                 if (storage_positions->families) {
92                         free(storage_positions->families);
93                 }
94
95                 free(storage_positions);
96                 storage_positions = NULL;
97         }
98 }
99
100 /**
101  * Adds new position for the given individual.
102  *
103  * This function should be invoked only internaly and thus is not declared in
104  * header. Usage without caution can create duplicates in global variable
105  * storage_positions. Variable storage_positions is not prepared for such duplicates
106  * and this can provide to errors.
107  */
108 void _familia_positions_add_individual_position(struct familia_individual *individual, struct position *pos)
109 {
110         struct familia_storage_individual_position ** tmp = NULL;
111         unsigned int alloc_size = sizeof(struct familia_storage_individual_position *);
112
113         int size = (storage_positions->individuals_no + 1);
114
115         tmp = realloc(storage_positions->individuals, size * alloc_size);
116
117         if (tmp) {
118                 storage_positions->individuals = tmp;
119                 storage_positions->individuals[storage_positions->individuals_no]->ind = individual;
120                 storage_positions->individuals[storage_positions->individuals_no]->pos = pos;
121                 storage_positions->individuals_no++;
122         }
123         else {
124                 debug("There were problems with allocating memory for storage of individual positions->\n");
125         }
126 }
127
128 /**
129  * Adds new position for the given family.
130  *
131  * This function should be invoked only internaly and thus is not declared in
132  * header. Usage without caution can create duplicates in global variable
133  * storage_positions. Variable storage_positions is not prepared for such duplicates
134  * and this can provide to errors.
135  */
136 void _familia_positions_add_family_position(struct familia_family *family, struct position *pos)
137 {
138         struct familia_storage_family_position ** tmp = NULL;
139         unsigned int alloc_size = sizeof(struct familia_storage_family_position *);
140
141         int size = (storage_positions->families_no + 1);
142
143         tmp = realloc(storage_positions->families, size * alloc_size);
144
145         if (tmp) {
146                 storage_positions->families = tmp;
147                 storage_positions->families[storage_positions->families_no]->fam = family;
148                 storage_positions->families[storage_positions->families_no]->pos = pos;
149                 storage_positions->families_no++;
150         }
151         else {
152                 debug("There were problems with allocating memory for storage of family positions.\n");
153         }
154 }
155
156 void familia_positions_set_individual_position(struct familia_individual *individual, struct position *pos)
157 {
158         struct position * p = NULL;
159
160         p = familia_position_get_individual_position(individual);
161
162         /* If not found create a new one */
163         if (p == NULL) {
164                 _familia_positions_add_individual_position(individual, pos);
165         }
166 }
167
168 void familia_positions_set_family_position(struct familia_family *family, struct position *pos)
169 {
170         struct position * p = NULL;
171
172         p = familia_position_get_family_position(family);
173
174         /* If not found create a new one */
175         if (p == NULL) {
176                 _familia_positions_add_family_position(family, pos);
177         }
178 }
179
180 struct position * familia_position_get_individual_position(struct familia_individual *individual)
181 {
182         unsigned int i;
183         unsigned int id;
184
185         /*
186          * Uninitialized global. Return error.
187          */
188         if (!storage_positions || !storage_positions->individuals) {
189                 debug("Trying to request individual position, but positions storage is not initialized.\n");
190                 return NULL;
191         }
192
193         id = individual->id;
194
195         for (i = 0; i < storage_positions->individuals_no; i++) {
196                 if (storage_positions->individuals[i]->ind->id == id) {
197                         return storage_positions->individuals[i]->pos;
198                 }
199         }
200
201         /*
202          * Entry not found for a given individual. Return error.
203          */
204         return NULL;
205 }
206
207 struct position * familia_position_get_family_position(struct familia_family *family)
208 {
209         unsigned int i;
210         unsigned int id;
211
212         /*
213          * Uninitialized global. Return error.
214          */
215         if (!storage_positions || !storage_positions->families) {
216                 debug("Trying to request family position, but positions storage is not initialized.\n");
217                 return NULL;
218         }
219
220         id = family->id;
221
222         for (i = 0; i < storage_positions->families_no; i++) {
223                 if (storage_positions->families[i]->fam->id == id) {
224                         return storage_positions->families[i]->pos;
225                 }
226         }
227
228         /*
229          * Entry not found for a given individual. Return error.
230          */
231         return NULL;
232 }
233