Updated kn translations
[gcalctool.git] / src / currency.vala
blobeb38232f82003533264344ca88baf836da5f13ac
1 /*
2 * Copyright (C) 2008-2012 Robert Ancell.
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 * license.
9 */
11 static bool downloading_imf_rates = false;
12 static bool downloading_ecb_rates = false;
13 static bool loaded_rates = false;
14 private static CurrencyManager? default_currency_manager = null;
16 public class CurrencyManager : Object
18 private List<Currency> currencies;
19 public signal void updated ();
21 public static CurrencyManager get_default ()
23 if (default_currency_manager != null)
24 return default_currency_manager;
26 default_currency_manager = new CurrencyManager ();
28 default_currency_manager.currencies.append (new Currency ("AED", _("UAE Dirham"), "إ.د"));
29 default_currency_manager.currencies.append (new Currency ("AUD", _("Australian Dollar"), "$"));
30 default_currency_manager.currencies.append (new Currency ("BGN", _("Bulgarian Lev"), "лв"));
31 default_currency_manager.currencies.append (new Currency ("BHD", _("Bahraini Dinar"), ".ب.د"));
32 default_currency_manager.currencies.append (new Currency ("BND", _("Brunei Dollar"), "$"));
33 default_currency_manager.currencies.append (new Currency ("BRL", _("Brazilian Real"), "R$"));
34 default_currency_manager.currencies.append (new Currency ("BWP", _("Botswana Pula"), "P"));
35 default_currency_manager.currencies.append (new Currency ("CAD", _("Canadian Dollar"), "$"));
36 default_currency_manager.currencies.append (new Currency ("CFA", _("CFA Franc"), "Fr"));
37 default_currency_manager.currencies.append (new Currency ("CHF", _("Swiss Franc"), "Fr"));
38 default_currency_manager.currencies.append (new Currency ("CLP", _("Chilean Peso"), "$"));
39 default_currency_manager.currencies.append (new Currency ("CNY", _("Chinese Yuan"), "元"));
40 default_currency_manager.currencies.append (new Currency ("COP", _("Colombian Peso"), "$"));
41 default_currency_manager.currencies.append (new Currency ("CZK", _("Czech Koruna"), "Kč"));
42 default_currency_manager.currencies.append (new Currency ("DKK", _("Danish Krone"), "kr"));
43 default_currency_manager.currencies.append (new Currency ("DZD", _("Algerian Dinar"), "ج.د"));
44 default_currency_manager.currencies.append (new Currency ("EEK", _("Estonian Kroon"), "KR"));
45 default_currency_manager.currencies.append (new Currency ("EUR", _("Euro"), "€"));
46 default_currency_manager.currencies.append (new Currency ("GBP", _("Pound Sterling"), "£"));
47 default_currency_manager.currencies.append (new Currency ("HKD", _("Hong Kong Dollar"), "$"));
48 default_currency_manager.currencies.append (new Currency ("HRK", _("Croatian Kuna"), "kn"));
49 default_currency_manager.currencies.append (new Currency ("HUF", _("Hungarian Forint"), "Ft"));
50 default_currency_manager.currencies.append (new Currency ("IDR", _("Indonesian Rupiah"), "Rp"));
51 default_currency_manager.currencies.append (new Currency ("ILS", _("Israeli New Shekel"), "₪"));
52 default_currency_manager.currencies.append (new Currency ("INR", _("Indian Rupee"), "₹"));
53 default_currency_manager.currencies.append (new Currency ("IRR", _("Iranian Rial"), "﷼"));
54 default_currency_manager.currencies.append (new Currency ("ISK", _("Icelandic Krona"), "kr"));
55 default_currency_manager.currencies.append (new Currency ("JPY", _("Japanese Yen"), "¥"));
56 default_currency_manager.currencies.append (new Currency ("KRW", _("South Korean Won"), "₩"));
57 default_currency_manager.currencies.append (new Currency ("KWD", _("Kuwaiti Dinar"), "ك.د"));
58 default_currency_manager.currencies.append (new Currency ("KZT", _("Kazakhstani Tenge"), "₸"));
59 default_currency_manager.currencies.append (new Currency ("LKR", _("Sri Lankan Rupee"), "Rs"));
60 default_currency_manager.currencies.append (new Currency ("LTL", _("Lithuanian Litas"), "Lt"));
61 default_currency_manager.currencies.append (new Currency ("LVL", _("Latvian Lats"), "Ls"));
62 default_currency_manager.currencies.append (new Currency ("LYD", _("Libyan Dinar"), "د.ل"));
63 default_currency_manager.currencies.append (new Currency ("MUR", _("Mauritian Rupee"), "Rs"));
64 default_currency_manager.currencies.append (new Currency ("MXN", _("Mexican Peso"), "$"));
65 default_currency_manager.currencies.append (new Currency ("MYR", _("Malaysian Ringgit"), "RM"));
66 default_currency_manager.currencies.append (new Currency ("NOK", _("Norwegian Krone"), "kr"));
67 default_currency_manager.currencies.append (new Currency ("NPR", _("Nepalese Rupee"), "Rs"));
68 default_currency_manager.currencies.append (new Currency ("NZD", _("New Zealand Dollar"), "$"));
69 default_currency_manager.currencies.append (new Currency ("OMR", _("Omani Rial"), "ع.ر."));
70 default_currency_manager.currencies.append (new Currency ("PEN", _("Peruvian Nuevo Sol"), "S/."));
71 default_currency_manager.currencies.append (new Currency ("PHP", _("Philippine Peso"), "₱"));
72 default_currency_manager.currencies.append (new Currency ("PKR", _("Pakistani Rupee"), "Rs"));
73 default_currency_manager.currencies.append (new Currency ("PLN", _("Polish Zloty"), "zł"));
74 default_currency_manager.currencies.append (new Currency ("QAR", _("Qatari Riyal"), "ق.ر"));
75 default_currency_manager.currencies.append (new Currency ("RON", _("New Romanian Leu"), "L"));
76 default_currency_manager.currencies.append (new Currency ("RUB", _("Russian Rouble"), "руб."));
77 default_currency_manager.currencies.append (new Currency ("SAR", _("Saudi Riyal"), "س.ر"));
78 default_currency_manager.currencies.append (new Currency ("SEK", _("Swedish Krona"), "kr"));
79 default_currency_manager.currencies.append (new Currency ("SGD", _("Singapore Dollar"), "$"));
80 default_currency_manager.currencies.append (new Currency ("THB", _("Thai Baht"), "฿"));
81 default_currency_manager.currencies.append (new Currency ("TND", _("Tunisian Dinar"), "ت.د"));
82 default_currency_manager.currencies.append (new Currency ("TRY", _("New Turkish Lira"), "TL"));
83 default_currency_manager.currencies.append (new Currency ("TTD", _("T&T Dollar (TTD)"), "$"));
84 default_currency_manager.currencies.append (new Currency ("USD", _("US Dollar"), "$"));
85 default_currency_manager.currencies.append (new Currency ("UYU", _("Uruguayan Peso"), "$"));
86 default_currency_manager.currencies.append (new Currency ("VEF", _("Venezuelan Bolívar"), "Bs F"));
87 default_currency_manager.currencies.append (new Currency ("ZAR", _("South African Rand"), "R"));
89 return default_currency_manager;
92 public List<Currency> get_currencies ()
94 var r = new List<Currency> ();
95 foreach (var c in currencies)
96 r.append (c);
97 return r;
100 public Currency? get_currency (string name)
102 foreach (var c in currencies)
104 if (name == c.name)
106 var value = c.get_value ();
107 if (value == null || value.is_negative () || value.is_zero ())
108 return null;
109 else
110 return c;
114 return null;
117 private string get_imf_rate_filepath ()
119 return Path.build_filename (Environment.get_user_cache_dir (), "gcalctool", "rms_five.xls");
122 private string get_ecb_rate_filepath ()
124 return Path.build_filename (Environment.get_user_cache_dir (), "gcalctool", "eurofxref-daily.xml");
127 private Currency add_currency (string short_name)
129 foreach (var c in currencies)
130 if (c.name == short_name)
131 return c;
133 warning ("Currency %s is not in the currency table", short_name);
134 var c = new Currency (short_name, short_name, short_name);
135 currencies.append (c);
137 return c;
140 /* A file needs to be redownloaded if it doesn't exist, or is too old.
141 * When an error occur, it probably won't hurt to try to download again.
143 private bool file_needs_update (string filename, double max_age)
145 if (!FileUtils.test (filename, FileTest.IS_REGULAR))
146 return true;
148 var buf = Posix.Stat ();
149 if (Posix.stat (filename, out buf) == -1)
150 return true;
152 var modify_time = buf.st_mtime;
153 var now = time_t ();
154 if (now - modify_time > max_age)
155 return true;
157 return false;
160 private void load_imf_rates ()
162 var name_map = new HashTable <string, string> (str_hash, str_equal);
163 name_map.insert ("Euro", "EUR");
164 name_map.insert ("Japanese Yen", "JPY");
165 name_map.insert ("U.K. Pound Sterling", "GBP");
166 name_map.insert ("U.S. Dollar", "USD");
167 name_map.insert ("Algerian Dinar", "DZD");
168 name_map.insert ("Australian Dollar", "AUD");
169 name_map.insert ("Bahrain Dinar", "BHD");
170 name_map.insert ("Botswana Pula", "BWP");
171 name_map.insert ("Brazilian Real", "BRL");
172 name_map.insert ("Brunei Dollar", "BND");
173 name_map.insert ("Canadian Dollar", "CAD");
174 name_map.insert ("Chilean Peso", "CLP");
175 name_map.insert ("Chinese Yuan", "CNY");
176 name_map.insert ("Colombian Peso", "COP");
177 name_map.insert ("Czech Koruna", "CZK");
178 name_map.insert ("Danish Krone", "DKK");
179 name_map.insert ("Hungarian Forint", "HUF");
180 name_map.insert ("Icelandic Krona", "ISK");
181 name_map.insert ("Indian Rupee", "INR");
182 name_map.insert ("Indonesian Rupiah", "IDR");
183 name_map.insert ("Iranian Rial", "IRR");
184 name_map.insert ("Israeli New Sheqel", "ILS");
185 name_map.insert ("Kazakhstani Tenge", "KZT");
186 name_map.insert ("Korean Won", "KRW");
187 name_map.insert ("Kuwaiti Dinar", "KWD");
188 name_map.insert ("Libyan Dinar", "LYD");
189 name_map.insert ("Malaysian Ringgit", "MYR");
190 name_map.insert ("Mauritian Rupee", "MUR");
191 name_map.insert ("Mexican Peso", "MXN");
192 name_map.insert ("Nepalese Rupee", "NPR");
193 name_map.insert ("New Zealand Dollar", "NZD");
194 name_map.insert ("Norwegian Krone", "NOK");
195 name_map.insert ("Rial Omani", "OMR");
196 name_map.insert ("Pakistani Rupee", "PKR");
197 name_map.insert ("Nuevo Sol", "PEN");
198 name_map.insert ("Philippine Peso", "PHP");
199 name_map.insert ("Polish Zloty", "PLN");
200 name_map.insert ("Qatar Riyal", "QAR");
201 name_map.insert ("Russian Ruble", "RUB");
202 name_map.insert ("Saudi Arabian Riyal", "SAR");
203 name_map.insert ("Singapore Dollar", "SGD");
204 name_map.insert ("South African Rand", "ZAR");
205 name_map.insert ("Sri Lanka Rupee", "LKR");
206 name_map.insert ("Swedish Krona", "SEK");
207 name_map.insert ("Swiss Franc", "CHF");
208 name_map.insert ("Thai Baht", "THB");
209 name_map.insert ("Trinidad And Tobago Dollar", "TTD");
210 name_map.insert ("Tunisian Dinar", "TND");
211 name_map.insert ("U.A.E. Dirham", "AED");
212 name_map.insert ("Peso Uruguayo", "UYU");
213 name_map.insert ("Bolivar Fuerte", "VEF");
215 var filename = get_imf_rate_filepath ();
216 string data;
219 FileUtils.get_contents (filename, out data);
221 catch (Error e)
223 warning ("Failed to read exchange rates: %s", e.message);
224 return;
227 var lines = data.split ("\n", 0);
229 var in_data = false;
230 foreach (var line in lines)
232 line = line.chug ();
234 /* Start after first blank line, stop on next */
235 if (line == "")
237 if (!in_data)
239 in_data = true;
240 continue;
242 else
243 break;
245 if (!in_data)
246 continue;
248 var tokens = line.split ("\t", 0);
249 if (tokens[0] != "Currency")
251 int value_index;
252 for (value_index = 1; value_index < tokens.length; value_index++)
254 var value = tokens[value_index].chug ();
255 if (value != "")
256 break;
259 if (value_index < tokens.length)
261 var symbol = name_map.lookup (tokens[0]);
262 if (symbol != null)
264 var c = get_currency (symbol);
265 if (c == null)
267 debug ("Using IMF rate of %s for %s", tokens[value_index], symbol);
268 c = add_currency (symbol);
270 var value = mp_set_from_string (tokens[value_index]);
271 value = value.reciprocal ();
272 c.set_value (value);
274 else
275 warning ("Unknown currency '%s'", tokens[0]);
281 private void set_ecb_rate (Xml.Node node, Currency eur_rate)
283 string? name = null, value = null;
285 for (var attribute = node.properties; attribute != null; attribute = attribute->next)
287 var n = (Xml.Node*) attribute;
288 if (attribute->name == "currency")
289 name = n->get_content ();
290 else if (attribute->name == "rate")
291 value = n->get_content ();
294 /* Use data if value and no rate currently defined */
295 if (name != null && value != null && get_currency (name) == null)
297 debug ("Using ECB rate of %s for %s", value, name);
298 var c = add_currency (name);
299 var r = mp_set_from_string (value);
300 var v = eur_rate.get_value ();
301 v = v.multiply (r);
302 c.set_value (v);
306 private void set_ecb_fixed_rate (string name, string value, Currency eur_rate)
308 debug ("Using ECB fixed rate of %s for %s", value, name);
309 var c = add_currency (name);
310 var r = mp_set_from_string (value);
311 var v = eur_rate.get_value ();
312 v = v.divide (r);
313 c.set_value (v);
316 private void load_ecb_rates ()
318 /* Scale rates to the EUR value */
319 var eur_rate = get_currency ("EUR");
320 if (eur_rate == null)
322 warning ("Cannot use ECB rates as don't have EUR rate");
323 return;
326 /* Set some fixed rates */
327 set_ecb_fixed_rate ("EEK", "0.06391", eur_rate);
328 set_ecb_fixed_rate ("CFA", "0.152449", eur_rate);
330 Xml.Parser.init ();
331 var filename = get_ecb_rate_filepath ();
332 var document = Xml.Parser.read_file (filename);
333 if (document == null)
335 warning ("Couldn't parse ECB rate file %s", filename);
336 return;
339 var xpath_ctx = new Xml.XPath.Context (document);
340 if (xpath_ctx == null)
342 warning ("Couldn't create XPath context");
343 return;
346 xpath_ctx.register_ns ("xref", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
347 var xpath_obj = xpath_ctx.eval_expression ("//xref:Cube[@currency][@rate]");
348 if (xpath_obj == null)
350 warning ("Couldn't create XPath object");
351 return;
353 var len = (xpath_obj->nodesetval != null) ? xpath_obj->nodesetval->length () : 0;
354 for (var i = 0; i < len; i++)
356 var node = xpath_obj->nodesetval->item (i);
358 if (node->type == Xml.ElementType.ELEMENT_NODE)
359 set_ecb_rate (node, eur_rate);
361 /* Avoid accessing removed elements */
362 if (node->type != Xml.ElementType.NAMESPACE_DECL)
363 node = null;
366 Xml.Parser.cleanup ();
369 private bool load_rates ()
371 /* Already loaded */
372 if (loaded_rates)
373 return true;
375 /* In process */
376 if (downloading_imf_rates || downloading_ecb_rates)
377 return false;
379 /* Use the IMF provided values and top up with currencies tracked by the ECB and not the IMF */
380 load_imf_rates ();
381 load_ecb_rates ();
383 /* Check if we couldn't find out a currency */
384 foreach (var c in currencies)
385 if (c.get_value ().is_zero ())
386 warning ("Currency %s is not provided by IMF or ECB", c.name);
388 debug ("Rates loaded");
389 loaded_rates = true;
391 updated ();
393 return true;
396 public Number? get_value (string currency)
398 /* Update rates if necessary */
399 var path = get_imf_rate_filepath ();
400 if (!downloading_imf_rates && file_needs_update (path, 60 * 60 * 24 * 7))
402 downloading_imf_rates = true;
403 debug ("Downloading rates from the IMF...");
404 download_file ("http://www.imf.org/external/np/fin/data/rms_five.aspx?tsvflag=Y", path, download_imf_cb);
406 path = get_ecb_rate_filepath ();
407 if (!downloading_ecb_rates && file_needs_update (path, 60 * 60 * 24 * 7))
409 downloading_ecb_rates = true;
410 debug ("Downloading rates from the ECB...");
411 download_file ("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml", path, download_ecb_cb);
414 if (!load_rates ())
415 return null;
417 var c = get_currency (currency);
418 if (c != null)
419 return c.get_value ();
420 else
421 return null;
424 private void download_file (string uri, string filename, AsyncReadyCallback callback)
426 var directory = Path.get_dirname (filename);
427 DirUtils.create_with_parents (directory, 0755);
429 var source = File.new_for_uri (uri);
430 var dest = File.new_for_path (filename);
432 source.copy_async.begin (dest, FileCopyFlags.OVERWRITE, GLib.Priority.DEFAULT, null, null, callback);
435 private void download_imf_cb (Object? object, AsyncResult result)
437 var f = object as File;
441 f.copy_async.end (result);
442 debug ("IMF rates updated");
444 catch (Error e)
446 warning ("Couldn't download IMF currency rate file: %s", e.message);
449 downloading_imf_rates = false;
450 load_rates ();
453 private void download_ecb_cb (Object? object, AsyncResult result)
455 var f = object as File;
458 f.copy_async.end (result);
459 debug ("ECB rates updated");
461 catch (Error e)
463 warning ("Couldn't download ECB currency rate file: %s", e.message);
465 downloading_ecb_rates = false;
466 load_rates ();
470 public class Currency : Object
472 private Number value;
474 private string _name;
475 public string name { owned get { return _name; } }
477 private string _display_name;
478 public string display_name { owned get { return _display_name; } }
480 private string _symbol;
481 public string symbol { owned get { return _symbol; } }
483 public Currency (string name, string display_name, string symbol)
485 _name = name;
486 _display_name = display_name;
487 _symbol = symbol;
490 public void set_value (Number value)
492 this.value = value;
495 public Number get_value ()
497 return value;