Index: /extensions/PiwigoLib/PiwigoWpf/Services/ImageCacheManager.cs
===================================================================
--- /extensions/PiwigoLib/PiwigoWpf/Services/ImageCacheManager.cs	(revision 11919)
+++ /extensions/PiwigoLib/PiwigoWpf/Services/ImageCacheManager.cs	(revision 11919)
@@ -0,0 +1,266 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Com.Piwigo.Wpf.DTO;
+using System.Threading;
+using System.IO;
+using System.Net;
+using System.Drawing;
+using Com.Piwigo.Wpf.Helper;
+
+namespace Com.Piwigo.Wpf.Service
+{
+    public class ImageCacheManager
+    {
+        #region WPF Converter
+        static readonly ImageUrlCachedConverter _imageUrlCachedConverter = new ImageUrlCachedConverter();
+
+        public static ImageUrlCachedConverter ImageUrlCachedConverter
+        {
+            get
+            {
+                return _imageUrlCachedConverter;
+            }
+        }
+
+        public static String GetDefaultImage()
+        {
+            return ("pack://application:,,,/Pictures/Globe.png");
+        }
+
+        #endregion WPF Converter
+
+        #region Singleton
+        static readonly ImageCacheManagerBase _instance = new ImageCacheManagerBase();
+
+        // Explicit static constructor to tell C# compiler
+        // not to mark type as beforefieldinit
+        static ImageCacheManager()
+        {
+        }
+
+        public static ImageCacheManagerBase Instance
+        {
+            get
+            {
+                return _instance;
+            }
+        }
+        #endregion Singleton
+
+        #region singleton base class
+        public class ImageCacheManagerBase : IDisposable
+        {
+            #region DTO
+            // local DTO
+            internal class CategoryDictionnaryItem
+            {
+                internal DirectoryInfo BasePath;
+                internal String CategorieId;
+            };
+
+            internal class CategoryDictionnary : SortedDictionary<String, CategoryDictionnaryItem> { };
+
+            internal class ServerDictionnaryItem
+            {
+                internal DirectoryInfo BasePath;
+                internal CategoryDictionnary Categories;
+                internal Uri ServeurUrl;
+            };
+
+            internal class ServerDictionnary : SortedDictionary<String, ServerDictionnaryItem> { };
+
+            internal static DirectoryInfo AppCachedDataDirectory = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),"PiwigoWpf", "cache"));
+
+            internal Object _lock = new Object();
+            internal ServerDictionnary _aServerDictionnary;
+            internal ServerDictionnaryItem _currentServer;
+            internal CategoryDictionnaryItem _currentCategory;
+
+            #endregion DTO
+
+            #region local helper
+            // local helper
+            static private String BuildServerDirCache(String serveurUri)
+            {
+                String ServerDirCache = Path.Combine(AppCachedDataDirectory.FullName, serveurUri.Replace("http://", "_").Replace("/", "_"));
+                System.Diagnostics.Debug.Print(ServerDirCache);
+
+                return ServerDirCache;
+            }
+            
+            static private String BuildCategoryDirCache(ServerDictionnaryItem server, String CatgeoryId)
+            {
+                String CategoryDirCache = String.Empty;
+                if (server != null)
+                {
+                    CategoryDirCache = Path.Combine(server.BasePath.FullName, CatgeoryId.Replace("/", "_")); 
+                }
+                else
+                {
+                    throw new ApplicationException ("Current server not set before using category");
+                }
+
+                return CategoryDirCache;
+            }
+
+            static private ServerDictionnary BuildServerDictionnaryFromCache()
+            {
+                ServerDictionnary retLstServerDictionnary = new ServerDictionnary();
+
+                if (AppCachedDataDirectory.Exists)
+                {
+                    foreach (DirectoryInfo Dir in AppCachedDataDirectory.GetDirectories())
+                    {
+                        FileInfo xmlData = new FileInfo(Path.Combine(Dir.FullName, "serverdictionnaryitem.xml"));
+                        if (xmlData.Exists)
+                        {
+                            ServerDictionnaryItem item = XMLHelper<ServerDictionnaryItem>.DeserializeObjectFromFile(xmlData);
+                            retLstServerDictionnary.Add(item.ServeurUrl.ToString(), item);
+                        }
+                    }
+                }
+
+                return retLstServerDictionnary;
+            }
+
+            static void WriteServerDictionnaryToDisk(ServerDictionnary dcServer)
+            {
+                foreach (ServerDictionnaryItem Item in dcServer.Values)
+                {
+                    FileInfo xmlData = new FileInfo(Path.Combine(Item.BasePath.FullName, "serverdictionnaryitem.xml"));
+                    XMLHelper<ServerDictionnaryItem>.SerializeToXMLFile(Item, xmlData);
+                }
+            }
+            #endregion local helper
+
+            public void UnsetCurrentServer()
+            { 
+                _currentCategory = null;
+                _currentServer = null;
+            }
+
+            public void SetCurrentServer(String serveurUri)
+            {
+                String currentserverDir = BuildServerDirCache(serveurUri);
+                lock (_lock)
+                {
+                    // load data from disk on first access
+                    if (_aServerDictionnary == null)
+                    {
+                        _aServerDictionnary = BuildServerDictionnaryFromCache();
+                    }
+
+                    if (_aServerDictionnary.ContainsKey(serveurUri))
+                    {
+                        _currentServer = _aServerDictionnary[serveurUri];
+                    }
+                    else
+                    {
+                        ServerDictionnaryItem server = new ServerDictionnaryItem();
+                        server.ServeurUrl = new Uri(serveurUri);
+                        server.BasePath = new DirectoryInfo(currentserverDir);
+                        server.Categories = new CategoryDictionnary();
+                        _aServerDictionnary.Add(serveurUri, server);
+                        _currentServer = server;
+                    }
+
+                    if (!Directory.Exists(currentserverDir))
+                    {
+                        //Create it
+                        Directory.CreateDirectory(currentserverDir);
+                        _currentServer.Categories.Clear();
+                    }
+                }
+            }
+
+            public void SetCurrentCategory(String CategorieId)
+            {
+                if (_currentServer != null)
+                {
+                    lock (_lock)
+                    {
+                        String currentsCategoryDir = BuildCategoryDirCache(_currentServer, CategorieId);
+                        if (_currentServer.Categories.ContainsKey(CategorieId))
+                        {
+                            _currentCategory = _currentServer.Categories[CategorieId];
+                        }
+                        else
+                        {
+                            CategoryDictionnaryItem category = new CategoryDictionnaryItem();
+                            category.BasePath = new DirectoryInfo(currentsCategoryDir);
+                            category.CategorieId = CategorieId;
+                            _currentServer.Categories.Add(CategorieId, category);
+                            _currentCategory = category;
+                        }
+
+                        if (!Directory.Exists(currentsCategoryDir))
+                        {
+                            //Create it
+                            Directory.CreateDirectory(currentsCategoryDir);
+                        }
+                    }
+                }
+                else
+                {
+                    throw new ApplicationException("Current server not set before using category");
+                }
+            }
+
+            public String GetImageFilename(PwgImageWPF aImageWPF)
+                {
+                    String retValue = String.Empty;
+                    if (aImageWPF == null)
+                    {
+                        return retValue;
+                    }
+
+                    if (_currentCategory != null)
+                    {
+                        String localFile = Path.Combine(_currentCategory.BasePath.FullName, String.Format("{0}-{1}", aImageWPF.Id, aImageWPF.File));
+
+                        if (!File.Exists(localFile))
+                        {
+                            ThreadPool.QueueUserWorkItem((WaitCallback)delegate
+                            {
+                                WebRequest request = HttpWebRequest.Create(aImageWPF.UrlElement);
+                                WebResponse response = request.GetResponse();
+
+                                //check the content type to assert that the file in the uri is an image
+                                if (!response.ContentType.StartsWith("image"))
+                                {
+                                    throw new FileFormatException(aImageWPF.UrlElement, String.Format("Uri passed to ImageCacher does not return an image. Content is of type {0}.", response.ContentType));
+                                }
+
+                                //load the image from the stream
+                                Image image = Image.FromStream(response.GetResponseStream());
+
+                                //save it
+                                image.Save(localFile);
+
+                            });
+
+                            retValue = localFile;
+                        }
+                    }
+                    else
+                    {
+                        throw new ApplicationException("Current category not set before using image cache.");
+                    }
+                    return retValue;
+                }
+
+            public void Dispose()
+            {
+                if (_aServerDictionnary != null)
+                {
+                    WriteServerDictionnaryToDisk(_aServerDictionnary);
+                }
+            }
+        }
+
+        #endregion singleton base class
+}
+
+}
