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/64x64/images.png"); } public static String GetLoadImage() { return ("pack://application:,,,/Pictures/64x64/html.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() { Int32 a, b; ThreadPool.GetMaxThreads(out a, out b); if (a>20) a = 20; ThreadPool.SetMaxThreads(a, b); } 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 { }; internal class ServerDictionnaryItem { internal DirectoryInfo BasePath; internal CategoryDictionnary Categories; internal Uri ServeurUrl; }; internal class ServerDictionnary : SortedDictionary { }; 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.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.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 strImageType) { String retImgSrc = GetDefaultImage(); if (aImageWPF == null) { return retImgSrc; } if (_currentCategory != null) { String localDir = Path.Combine(_currentCategory.BasePath.FullName, strImageType); if (!Directory.Exists(localDir)) { Directory.CreateDirectory(localDir); } String localFile = Path.Combine(localDir, String.Format("{0}-{1}", aImageWPF.Id, aImageWPF.File)); if (!File.Exists(localFile)) { retImgSrc = GetLoadImage(); 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); switch (strImageType) { case "Thumb" : aImageWPF.ImgSourceThumb = localFile; break; case "LowRes": aImageWPF.ImgSource = localFile; break; } }); } else { retImgSrc = localFile; } return retImgSrc; } else { throw new ApplicationException("Current category not set before using image cache."); } } public void Dispose() { if (_aServerDictionnary != null) { WriteServerDictionnaryToDisk(_aServerDictionnary); } } } #endregion singleton base class } }