         super.init()
     }
     
-    
-    fileprivate func cacheKeyForURL(_ url: URL) -> String {
-        guard let host = url.host, let imageName = WMFParseImageNameFromSourceURL(url) else {
-            return url.absoluteString.precomposedStringWithCanonicalMapping
-        }
-        return (host + "__" + imageName).precomposedStringWithCanonicalMapping
-    }
-    
-    fileprivate func variantForURL(_ url: URL) -> Int64 { // A return value of 0 indicates the original size
-        let sizePrefix = WMFParseSizePrefixFromSourceURL(url)
-        return Int64(sizePrefix == NSNotFound ? 0 : sizePrefix)
-    }
-    
-    fileprivate func identifierForURL(_ url: URL) -> String {
-        let key = cacheKeyForURL(url)
-        let variant = variantForURL(url)
-        return "\(key)__\(variant)".precomposedStringWithCanonicalMapping
-    }
-    
-    fileprivate func identifierForKey(_ key: String, variant: Int64) -> String {
-        return "\(key)__\(variant)".precomposedStringWithCanonicalMapping
-    }
-    
-//    fileprivate func legacyPermanentCacheFileURL(key: String, variant: Int64) -> URL {
-//        let identifier = identifierForKey(key, variant: variant)
-//        return self.permanentStorageDirectory.appendingPathComponent(identifier, isDirectory: false)
-//    }
-    
-    fileprivate func permanentCacheFileURL(key: String, variant: Int64) -> URL {
-        let identifier = identifierForKey(key, variant: variant)
-        let component = identifier.sha256 ?? identifier
-        return self.permanentStorageDirectory.appendingPathComponent(component, isDirectory: false)
-    }
-    
-    fileprivate func fetchCacheItem(key: String, variant: Int64, moc: NSManagedObjectContext) -> CacheItem? {
-        let itemRequest: NSFetchRequest<CacheItem> = CacheItem.fetchRequest()
-        itemRequest.predicate = NSPredicate(format: "key == %@ && variant == %lli", key, variant)
-        itemRequest.fetchLimit = 1
-        do {
-            let items = try moc.fetch(itemRequest)
-            return items.first
-        } catch let error {
-            DDLogError("Error fetching cache item: \(error)")
-        }
-        return nil
-    }
-    
-    fileprivate func fetchCacheGroup(key: String, moc: NSManagedObjectContext) -> CacheGroup? {
-        let groupRequest: NSFetchRequest<CacheGroup> = CacheGroup.fetchRequest()
-        groupRequest.predicate = NSPredicate(format: "key == %@", key)
-        groupRequest.fetchLimit = 1
-        do {
-            let groups = try moc.fetch(groupRequest)
-            return groups.first
-        } catch let error {
-            DDLogError("Error fetching cache group: \(error)")
-        }
-        return nil
-    }
-    
-    fileprivate func createCacheItem(key: String, variant: Int64, moc: NSManagedObjectContext) -> CacheItem? {
-        guard let entity = NSEntityDescription.entity(forEntityName: "CacheItem", in: moc) else {
-            return nil
-        }
-        let item = CacheItem(entity: entity, insertInto: moc)
-        item.key = key
-        item.variant = variant
-        item.date = NSDate()
-        return item
-    }
-    
-    fileprivate func createCacheGroup(key: String, moc: NSManagedObjectContext) -> CacheGroup? {
-        guard let entity = NSEntityDescription.entity(forEntityName: "CacheGroup", in: moc) else {
-            return nil
-        }
-        let group = CacheGroup(entity: entity, insertInto: moc)
-        group.key = key
-        return group
-    }
-    
-    fileprivate func fetchOrCreateCacheItem(key: String, variant: Int64, moc: NSManagedObjectContext) -> CacheItem? {
-        return fetchCacheItem(key: key, variant: variant, moc:moc) ?? createCacheItem(key: key, variant: variant, moc: moc)
-    }
-    
-    fileprivate func fetchOrCreateCacheGroup(key: String, moc: NSManagedObjectContext) -> CacheGroup? {
-        return fetchCacheGroup(key: key, moc: moc) ?? createCacheGroup(key: key, moc: moc)
-    }
-    
-    
-    fileprivate func save(moc: NSManagedObjectContext) {
-        guard moc.hasChanges else {
-            return
-        }
-        do {
-            try moc.save()
-        } catch let error {
-            DDLogError("Error saving cache moc: \(error)")
-        }
-    }
-    
-    fileprivate func updateCachedFileMimeTypeAtPath(_ path: String, toMIMEType MIMEType: String?) {
-        if let MIMEType = MIMEType {
-            do {
-                try self.fileManager.wmf_setValue(MIMEType, forExtendedFileAttributeNamed: WMFExtendedFileAttributeNameMIMEType, forFileAtPath: path)
-            } catch let error {
-                DDLogError("Error setting extended file attribute for MIME Type: \(error)")
-            }
-        }
-    }
-    
-    @objc public func cancelPermanentCacheRequests() {
-        permanentCacheCompletionManager.cancelAll()
-    }
-    
+    // MARK: Cache
+    
+    /// Gets the cached image for a given URL from either the session cache or the permanent cache
+    @objc public func cachedImage(withURL url: URL?) -> Image? {
+        guard let url = url else {
+            return nil
+        }
+        return sessionCachedImage(withURL: url) ?? permanentlyCachedImage(withURL: url)
+    }
+    
+    @objc public func data(withURL url: URL) -> TypedImageData? {
+        return sessionCachedData(withURL: url) ?? permanentlyCachedTypedDiskDataForImage(withURL: url)
+    }
+    
+    // MARK: Permanent Cache
+    
+    /// Adds an image with a given URL to the permanent cache. Coalesces multiple requests so the image is only downloaded once.
+    /// - Parameter url: The image URL
+    /// - Parameter groupKey: The group to associate this image with (the article key)
+    /// - Parameter priority
+    /// - Parameter failure block
+    /// - Parameter success block
     @objc public func permanentlyCache(url: URL, groupKey: String, priority: Float = URLSessionTask.lowPriority, failure: @escaping (Error) -> Void, success: @escaping () -> Void) {
         let key = self.cacheKeyForURL(url)
         let variant = self.variantForURL(url)

        
    }
    
    @objc public func permanentlyCacheInBackground(urls: [URL], groupKey: String,  failure: @escaping (Error) -> Void, success: @escaping () -> Void) {
        let cacheGroup = WMFTaskGroup()
        var errors = [NSError]()

import ImageIO
import FLAnimatedImage

@objc(WMFImageControllerError)
public enum ImageControllerError: Int, Error {
    case dataNotFound
    case invalidOrEmptyURL
    case invalidImageCache
