1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2010-2012 Free Software Foundation, Inc.
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, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <json-glib/json-glib.h>
26 #include <gthumb.h>
27 #include "facebook-photo.h"
28 
29 
30 static void facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface);
31 
32 
33 G_DEFINE_TYPE_WITH_CODE (FacebookPhoto,
34 			 facebook_photo,
35 			 G_TYPE_OBJECT,
36 			 G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
37 						facebook_photo_json_serializable_interface_init))
38 
39 
40 enum {
41 	PROP_0,
42 	PROP_ID,
43 	PROP_PICTURE,
44 	PROP_SOURCE,
45 	PROP_WIDTH,
46 	PROP_HEIGHT,
47 	PROP_LINK,
48 	PROP_CREATED_TIME,
49 	PROP_UPDATED_TIME,
50 	PROP_IMAGES
51 };
52 
53 
54 /* -- facebook_image -- */
55 
56 
57 static FacebookImage *
facebook_image_new(void)58 facebook_image_new (void)
59 {
60 	FacebookImage *image;
61 
62 	image = g_new (FacebookImage, 1);
63 	image->source = NULL;
64 	image->width = 0;
65 	image->height = 0;
66 
67 	return image;
68 }
69 
70 
71 static FacebookImage *
facebook_image_copy(FacebookImage * source)72 facebook_image_copy (FacebookImage *source)
73 {
74 	FacebookImage *dest;
75 
76 	dest = facebook_image_new ();
77 	_g_str_set (&dest->source, source->source);
78 	dest->width = source->width;
79 	dest->height = source->height;
80 
81 	return dest;
82 }
83 
84 
85 static void
facebook_image_free(FacebookImage * image)86 facebook_image_free (FacebookImage *image)
87 {
88 	g_free (image->source);
89 	g_free (image);
90 }
91 
92 
93 /* -- facebook_image_list -- */
94 
95 
96 #define FACEBOOK_TYPE_IMAGE_LIST (facebook_image_list_get_type ())
97 
98 
99 static GList *
facebook_image_list_copy(GList * source)100 facebook_image_list_copy (GList *source)
101 {
102 	return g_list_copy_deep (source, (GCopyFunc) facebook_image_copy, NULL);
103 }
104 
105 
106 static void
facebook_image_list_free(GList * images)107 facebook_image_list_free (GList *images)
108 {
109 	g_list_foreach (images, (GFunc) facebook_image_free, NULL);
110 	g_list_free (images);
111 }
112 
113 
114 GType facebook_image_list_get_type (void);
115 
G_DEFINE_BOXED_TYPE(GList,facebook_image_list,facebook_image_list_copy,facebook_image_list_free)116 G_DEFINE_BOXED_TYPE (GList, facebook_image_list, facebook_image_list_copy, facebook_image_list_free)
117 
118 
119 /* -- facebook_photo -- */
120 
121 
122 static void
123 facebook_photo_set_property (GObject      *object,
124 			     guint         property_id,
125 			     const GValue *value,
126 			     GParamSpec   *pspec)
127 {
128 	FacebookPhoto *self;
129 
130 	self = FACEBOOK_PHOTO (object);
131 
132 	switch (property_id) {
133 	case PROP_ID:
134 		_g_str_set (&self->id, g_value_get_string (value));
135 		break;
136 	case PROP_PICTURE:
137 		_g_str_set (&self->picture, g_value_get_string (value));
138 		break;
139 	case PROP_SOURCE:
140 		_g_str_set (&self->source, g_value_get_string (value));
141 		break;
142 	case PROP_WIDTH:
143 		self->width = g_value_get_int (value);
144 		break;
145 	case PROP_HEIGHT:
146 		self->height = g_value_get_int (value);
147 		break;
148 	case PROP_LINK:
149 		_g_str_set (&self->link, g_value_get_string (value));
150 		break;
151 	case PROP_CREATED_TIME:
152 		gth_datetime_free (self->created_time);
153 		self->created_time = g_value_dup_boxed (value);
154 		break;
155 	case PROP_UPDATED_TIME:
156 		gth_datetime_free (self->updated_time);
157 		self->updated_time = g_value_dup_boxed (value);
158 		break;
159 	case PROP_IMAGES:
160 		facebook_image_list_free (self->images);
161 		self->images = g_value_dup_boxed (value);
162 		break;
163 	default:
164 		break;
165 	}
166 }
167 
168 
169 static void
facebook_photo_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)170 facebook_photo_get_property (GObject    *object,
171 			     guint       property_id,
172 			     GValue     *value,
173 			     GParamSpec *pspec)
174 {
175 	FacebookPhoto *self;
176 
177 	self = FACEBOOK_PHOTO (object);
178 
179 	switch (property_id) {
180 	case PROP_ID:
181 		g_value_set_string (value, self->id);
182 		break;
183 	case PROP_PICTURE:
184 		g_value_set_string (value, self->picture);
185 		break;
186 	case PROP_SOURCE:
187 		g_value_set_string (value, self->source);
188 		break;
189 	case PROP_WIDTH:
190 		g_value_set_int (value, self->width);
191 		break;
192 	case PROP_HEIGHT:
193 		g_value_set_int (value, self->height);
194 		break;
195 	case PROP_LINK:
196 		g_value_set_string (value, self->link);
197 		break;
198 	case PROP_CREATED_TIME:
199 		g_value_set_boxed (value, self->created_time);
200 		break;
201 	case PROP_UPDATED_TIME:
202 		g_value_set_boxed (value, self->updated_time);
203 		break;
204 	case PROP_IMAGES:
205 		g_value_set_boxed (value, self->images);
206 		break;
207 	default:
208 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
209 		break;
210 	}
211 }
212 
213 
214 static void
facebook_photo_finalize(GObject * obj)215 facebook_photo_finalize (GObject *obj)
216 {
217 	FacebookPhoto *self;
218 
219 	self = FACEBOOK_PHOTO (obj);
220 
221 	g_free (self->id);
222 	g_free (self->picture);
223 	g_free (self->source);
224 	g_free (self->link);
225 	gth_datetime_free (self->created_time);
226 	gth_datetime_free (self->updated_time);
227 	facebook_image_list_free (self->images);
228 
229 	G_OBJECT_CLASS (facebook_photo_parent_class)->finalize (obj);
230 }
231 
232 
233 static void
facebook_photo_class_init(FacebookPhotoClass * klass)234 facebook_photo_class_init (FacebookPhotoClass *klass)
235 {
236 	GObjectClass *object_class;
237 
238 	object_class = G_OBJECT_CLASS (klass);
239 	object_class->finalize = facebook_photo_finalize;
240 	object_class->set_property = facebook_photo_set_property;
241 	object_class->get_property = facebook_photo_get_property;
242 
243 	/* properties */
244 
245 	g_object_class_install_property (object_class,
246 					 PROP_ID,
247 					 g_param_spec_string ("id",
248                                                               "ID",
249                                                               "",
250                                                               NULL,
251                                                               G_PARAM_READWRITE));
252 	g_object_class_install_property (object_class,
253 					 PROP_PICTURE,
254 					 g_param_spec_string ("picture",
255                                                               "Picture",
256                                                               "",
257                                                               NULL,
258                                                               G_PARAM_READWRITE));
259 	g_object_class_install_property (object_class,
260 				 	 PROP_SOURCE,
261 					 g_param_spec_string ("source",
262                                                               "Source",
263                                                               "",
264                                                               NULL,
265                                                               G_PARAM_READWRITE));
266 	g_object_class_install_property (object_class,
267 					 PROP_WIDTH,
268 					 g_param_spec_int ("width",
269                                                            "Width",
270                                                            "",
271                                                            0,
272                                                            G_MAXINT,
273                                                            0,
274                                                            G_PARAM_READWRITE));
275 	g_object_class_install_property (object_class,
276 					 PROP_HEIGHT,
277 					 g_param_spec_int ("height",
278                                                            "Height",
279                                                            "",
280                                                            0,
281                                                            G_MAXINT,
282                                                            0,
283                                                            G_PARAM_READWRITE));
284 	g_object_class_install_property (object_class,
285 				 	 PROP_LINK,
286 					 g_param_spec_string ("link",
287                                                               "Link",
288                                                               "",
289                                                               NULL,
290                                                               G_PARAM_READWRITE));
291 	g_object_class_install_property (object_class,
292 				 	 PROP_CREATED_TIME,
293 					 g_param_spec_boxed ("created-time",
294                                                              "Created time",
295                                                              "",
296                                                              GTH_TYPE_DATETIME,
297                                                              G_PARAM_READWRITE));
298 	g_object_class_install_property (object_class,
299 				 	 PROP_UPDATED_TIME,
300 				 	 g_param_spec_boxed ("updated-time",
301 				 			     "Updated time",
302 				 			     "",
303 				 			     GTH_TYPE_DATETIME,
304 				 			     G_PARAM_READWRITE));
305 	g_object_class_install_property (object_class,
306 				 	 PROP_IMAGES,
307 				 	 g_param_spec_boxed ("images",
308 				 			     "Images",
309 				 			     "",
310 				 			     FACEBOOK_TYPE_IMAGE_LIST,
311 				 			     G_PARAM_READWRITE));
312 }
313 
314 
315 static gboolean
facebook_photo_deserialize_property(JsonSerializable * serializable,const gchar * property_name,GValue * value,GParamSpec * pspec,JsonNode * property_node)316 facebook_photo_deserialize_property (JsonSerializable *serializable,
317                                      const gchar      *property_name,
318                                      GValue           *value,
319                                      GParamSpec       *pspec,
320                                      JsonNode         *property_node)
321 {
322 	FacebookPhoto *self = FACEBOOK_PHOTO (serializable);
323 
324 	if (pspec->value_type == GTH_TYPE_DATETIME) {
325 		GTimeVal timeval;
326 
327 		if (g_time_val_from_iso8601 (json_node_get_string (property_node), &timeval)) {
328 			GthDateTime *datetime;
329 
330 			datetime = gth_datetime_new ();
331 			gth_datetime_from_timeval (datetime, &timeval);
332 			g_object_set (self, property_name, datetime, NULL);
333 
334 			gth_datetime_free (datetime);
335 
336 			return TRUE;
337 		}
338 
339 		return FALSE;
340 	}
341 
342 	if (pspec->value_type == FACEBOOK_TYPE_IMAGE_LIST) {
343 		GList     *images = NULL;
344 		JsonArray *array;
345 		int        i;
346 
347 		array = json_node_get_array (property_node);
348 		for (i = 0; i < json_array_get_length (array); i++) {
349 			JsonObject *image_obj;
350 
351 			image_obj = json_array_get_object_element (array, i);
352 			if (image_obj != NULL) {
353 				FacebookImage *image;
354 
355 				image = facebook_image_new ();
356 				_g_str_set (&image->source, json_object_get_string_member (image_obj, "source"));
357 				image->width = json_object_get_int_member (image_obj, "width");
358 				image->height = json_object_get_int_member (image_obj, "height");
359 
360 				images = g_list_prepend (images, image);
361 			}
362 		}
363 
364 		images = g_list_reverse (images);
365 		g_object_set (self, property_name, images, NULL);
366 
367 		facebook_image_list_free (images);
368 
369 		return TRUE;
370 	}
371 
372 	return json_serializable_default_deserialize_property (serializable,
373 							       property_name,
374 							       value,
375 							       pspec,
376 							       property_node);
377 }
378 
379 
380 static void
facebook_photo_json_serializable_interface_init(JsonSerializableIface * iface)381 facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface)
382 {
383 	iface->deserialize_property = facebook_photo_deserialize_property;
384 }
385 
386 
387 static void
facebook_photo_init(FacebookPhoto * self)388 facebook_photo_init (FacebookPhoto *self)
389 {
390 	self->id = NULL;
391 	self->picture = NULL;
392 	self->source = NULL;
393 	self->width = 0;
394 	self->height = 0;
395 	self->link = NULL;
396 	self->created_time = NULL;
397 	self->updated_time = NULL;
398 	self->images = NULL;
399 }
400 
401 
402 FacebookPhoto *
facebook_photo_new(void)403 facebook_photo_new (void)
404 {
405 	return g_object_new (FACEBOOK_TYPE_PHOTO, NULL);
406 }
407 
408 
409 const char *
facebook_photo_get_original_url(FacebookPhoto * photo)410 facebook_photo_get_original_url	(FacebookPhoto *photo)
411 {
412 	char   *url;
413 	GList  *scan;
414 	glong   max_size;
415 
416 	url = photo->source;
417 	max_size = photo->width * photo->height;
418 
419 	for (scan = photo->images; scan; scan = scan->next) {
420 		FacebookImage *image = scan->data;
421 		glong          image_size;
422 
423 		image_size = image->width * image->height;
424 		if (image_size > max_size) {
425 			max_size = image_size;
426 			url = image->source;
427 		}
428 	}
429 
430 	return url;
431 }
432 
433 
434 const char *
facebook_photo_get_thumbnail_url(FacebookPhoto * photo,int requested_size)435 facebook_photo_get_thumbnail_url (FacebookPhoto *photo,
436 				  int            requested_size)
437 {
438 	char   *url;
439 	GList  *scan;
440 	glong   min_delta;
441 
442 	url = photo->picture;
443 	requested_size = requested_size * requested_size;
444 	min_delta = 0;
445 
446 	for (scan = photo->images; scan; scan = scan->next) {
447 		FacebookImage *image = scan->data;
448 		glong          image_delta;
449 
450 		image_delta = labs ((image->width * image->height) - requested_size);
451 		if ((scan == photo->images) || (image_delta < min_delta)) {
452 			min_delta = image_delta;
453 			url = image->source;
454 		}
455 	}
456 
457 	return url;
458 }
459