1/*
2 * This file is part of gitg
3 *
4 * Copyright (C) 2013 - Jesse van den Kieboom
5 *
6 * gitg is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * gitg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with gitg. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20public class Gitg.AvatarCache : Object
21{
22	private Gee.HashMap<string, Gdk.Pixbuf?> d_cache;
23	private static AvatarCache? s_instance;
24
25	construct
26	{
27		d_cache = new Gee.HashMap<string, Gdk.Pixbuf>();
28	}
29
30	private AvatarCache()
31	{
32		Object();
33	}
34
35	public static AvatarCache @default()
36	{
37		if (s_instance == null)
38		{
39			s_instance = new AvatarCache();
40		}
41
42		return s_instance;
43	}
44
45	public async Gdk.Pixbuf? load(string email, int size = 50, Cancellable? cancellable = null)
46	{
47		var id = Checksum.compute_for_string(ChecksumType.MD5, email.down());
48
49		var ckey = @"$id $size";
50
51		if (d_cache.has_key(ckey))
52		{
53			return d_cache[ckey];
54		}
55
56		var gravatar = @"https://www.gravatar.com/avatar/$(id)?d=404&s=$(size)";
57		var gfile = File.new_for_uri(gravatar);
58
59		var pixbuf = yield read_avatar_from_file(id, gfile, size, cancellable);
60
61		d_cache[ckey] = pixbuf;
62		return pixbuf;
63	}
64
65	private async Gdk.Pixbuf? read_avatar_from_file(string       id,
66	                                                File         file,
67	                                                int          size,
68	                                                Cancellable? cancellable)
69	{
70		InputStream stream;
71
72		try
73		{
74			stream = yield Gitg.PlatformSupport.http_get(file, cancellable);
75		}
76		catch(Error e)
77		{
78			warning("Can not retrieve avatar from %s: %s", file.get_path(), e.message);
79			return null;
80		}
81
82		uint8[] buffer = new uint8[4096];
83		var loader = new Gdk.PixbufLoader();
84
85		loader.set_size(size, size);
86
87		return yield read_avatar(id, stream, buffer, loader, cancellable);
88	}
89
90	private async Gdk.Pixbuf? read_avatar(string           id,
91	                                      InputStream      stream,
92	                                      uint8[]          buffer,
93	                                      Gdk.PixbufLoader loader,
94	                                      Cancellable?     cancellable)
95	{
96		ssize_t n;
97
98		try
99		{
100			n = yield stream.read_async(buffer, Priority.LOW, cancellable);
101		}
102		catch { return null; }
103
104		if (n != 0)
105		{
106			try
107			{
108				loader.write(buffer[0:n]);
109			}
110			catch { return null; }
111
112			return yield read_avatar(id, stream, buffer, loader, cancellable);
113		}
114		else
115		{
116			// Finished reading
117			try
118			{
119				loader.close();
120			} catch { return null; }
121
122			return loader.get_pixbuf();
123		}
124	}
125}
126
127// ex: ts=4 noet
128