// Path: library/src/main/java/com/danikula/videocache/file/FileCache.java
// public class FileCache implements Cache {
// 
//     private static final String TEMP_POSTFIX = ".download";
// 
//     private final DiskUsage diskUsage;
//     public File file;
//     private RandomAccessFile dataFile;
// 
//     public FileCache(File file) throws ProxyCacheException {
//         this(file, new UnlimitedDiskUsage());
//     }
// 
//     public FileCache(File file, DiskUsage diskUsage) throws ProxyCacheException {
//         try {
//             if (diskUsage == null) {
//                 throw new NullPointerException();
//             }
//             this.diskUsage = diskUsage;
//             File directory = file.getParentFile();
//             Files.makeDir(directory);
//             boolean completed = file.exists();
//             this.file = completed ? file : new File(file.getParentFile(), file.getName() + TEMP_POSTFIX);
//             this.dataFile = new RandomAccessFile(this.file, completed ? "r" : "rw");
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error using file " + file + " as disc cache", e);
//         }
//     }
// 
//     @Override
//     public synchronized long available() throws ProxyCacheException {
//         try {
//             return (int) dataFile.length();
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error reading length of file " + file, e);
//         }
//     }
// 
//     @Override
//     public synchronized int read(byte[] buffer, long offset, int length) throws ProxyCacheException {
//         try {
//             dataFile.seek(offset);
//             return dataFile.read(buffer, 0, length);
//         } catch (IOException e) {
//             String format = "Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]";
//             throw new ProxyCacheException(String.format(format, length, offset, available(), buffer.length), e);
//         }
//     }
// 
//     @Override
//     public synchronized void append(byte[] data, int length) throws ProxyCacheException {
//         try {
//             if (isCompleted()) {
//                 throw new ProxyCacheException("Error append cache: cache file " + file + " is completed!");
//             }
//             dataFile.seek(available());
//             dataFile.write(data, 0, length);
//         } catch (IOException e) {
//             String format = "Error writing %d bytes to %s from buffer with size %d";
//             throw new ProxyCacheException(String.format(format, length, dataFile, data.length), e);
//         }
//     }
// 
//     @Override
//     public synchronized void close() throws ProxyCacheException {
//         try {
//             dataFile.close();
//             diskUsage.touch(file);
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error closing file " + file, e);
//         }
//     }
// 
//     @Override
//     public synchronized void complete() throws ProxyCacheException {
//         if (isCompleted()) {
//             return;
//         }
// 
//         close();
//         String fileName = file.getName().substring(0, file.getName().length() - TEMP_POSTFIX.length());
//         File completedFile = new File(file.getParentFile(), fileName);
//         boolean renamed = file.renameTo(completedFile);
//         if (!renamed) {
//             throw new ProxyCacheException("Error renaming file " + file + " to " + completedFile + " for completion!");
//         }
//         file = completedFile;
//         try {
//             dataFile = new RandomAccessFile(file, "r");
//             diskUsage.touch(file);
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error opening " + file + " as disc cache", e);
//         }
//     }
// 
//     @Override
//     public synchronized boolean isCompleted() {
//         return !isTempFile(file);
//     }
// 
//     /**
//      * Returns file to be used fo caching. It may as original file passed in constructor as some temp file for not completed cache.
//      *
//      * @return file for caching.
//      */
//     public File getFile() {
//         return file;
//     }
// 
//     private boolean isTempFile(File file) {
//         return file.getName().endsWith(TEMP_POSTFIX);
//     }
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static <T> T checkNotNull(T reference) {
//     if (reference == null) {
//         throw new NullPointerException();
//     }
//     return reference;
// }


import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.danikula.videocache.file.FileCache;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import static com.danikula.videocache.Preconditions.checkNotNull;
            proxyCache = null;
        }
    }

    public void registerCacheListener(CacheListener cacheListener) {
        listeners.add(cacheListener);
    }

    public void unregisterCacheListener(CacheListener cacheListener) {
        listeners.remove(cacheListener);
    }

    public void shutdown() {
        listeners.clear();
        if (proxyCache != null) {
            proxyCache.registerCacheListener(null);
            proxyCache.shutdown();
            proxyCache = null;
        }
        clientsCount.set(0);
    }

    public int getClientsCount() {
        return clientsCount.get();
    }

    private HttpProxyCache newHttpProxyCache() throws ProxyCacheException {
        HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage, config.headerInjector);
        FileCache cache = new FileCache(config.generateCacheFile(url), config.diskUsage);
        HttpProxyCache httpProxyCache = new HttpProxyCache(source, cache);
// Path: library/src/main/java/com/danikula/videocache/file/FileCache.java
// public class FileCache implements Cache {
// 
//     private static final String TEMP_POSTFIX = ".download";
// 
//     private final DiskUsage diskUsage;
//     public File file;
//     private RandomAccessFile dataFile;
// 
//     public FileCache(File file) throws ProxyCacheException {
//         this(file, new UnlimitedDiskUsage());
//     }
// 
//     public FileCache(File file, DiskUsage diskUsage) throws ProxyCacheException {
//         try {
//             if (diskUsage == null) {
//                 throw new NullPointerException();
//             }
//             this.diskUsage = diskUsage;
//             File directory = file.getParentFile();
//             Files.makeDir(directory);
//             boolean completed = file.exists();
//             this.file = completed ? file : new File(file.getParentFile(), file.getName() + TEMP_POSTFIX);
//             this.dataFile = new RandomAccessFile(this.file, completed ? "r" : "rw");
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error using file " + file + " as disc cache", e);
//         }
//     }
// 
//     @Override
//     public synchronized long available() throws ProxyCacheException {
//         try {
//             return (int) dataFile.length();
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error reading length of file " + file, e);
//         }
//     }
// 
//     @Override
//     public synchronized int read(byte[] buffer, long offset, int length) throws ProxyCacheException {
//         try {
//             dataFile.seek(offset);
//             return dataFile.read(buffer, 0, length);
//         } catch (IOException e) {
//             String format = "Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]";
//             throw new ProxyCacheException(String.format(format, length, offset, available(), buffer.length), e);
//         }
//     }
// 
//     @Override
//     public synchronized void append(byte[] data, int length) throws ProxyCacheException {
//         try {
//             if (isCompleted()) {
//                 throw new ProxyCacheException("Error append cache: cache file " + file + " is completed!");
//             }
//             dataFile.seek(available());
//             dataFile.write(data, 0, length);
//         } catch (IOException e) {
//             String format = "Error writing %d bytes to %s from buffer with size %d";
//             throw new ProxyCacheException(String.format(format, length, dataFile, data.length), e);
//         }
//     }
// 
//     @Override
//     public synchronized void close() throws ProxyCacheException {
//         try {
//             dataFile.close();
//             diskUsage.touch(file);
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error closing file " + file, e);
//         }
//     }
// 
//     @Override
//     public synchronized void complete() throws ProxyCacheException {
//         if (isCompleted()) {
//             return;
//         }
// 
//         close();
//         String fileName = file.getName().substring(0, file.getName().length() - TEMP_POSTFIX.length());
//         File completedFile = new File(file.getParentFile(), fileName);
//         boolean renamed = file.renameTo(completedFile);
//         if (!renamed) {
//             throw new ProxyCacheException("Error renaming file " + file + " to " + completedFile + " for completion!");
//         }
//         file = completedFile;
//         try {
//             dataFile = new RandomAccessFile(file, "r");
//             diskUsage.touch(file);
//         } catch (IOException e) {
//             throw new ProxyCacheException("Error opening " + file + " as disc cache", e);
//         }
//     }
// 
//     @Override
//     public synchronized boolean isCompleted() {
//         return !isTempFile(file);
//     }
// 
//     /**
//      * Returns file to be used fo caching. It may as original file passed in constructor as some temp file for not completed cache.
//      *
//      * @return file for caching.
//      */
//     public File getFile() {
//         return file;
//     }
// 
//     private boolean isTempFile(File file) {
//         return file.getName().endsWith(TEMP_POSTFIX);
//     }
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static <T> T checkNotNull(T reference) {
//     if (reference == null) {
//         throw new NullPointerException();
//     }
//     return reference;
// }


// Path: library/src/main/java/com/danikula/videocache/HttpProxyCacheServerClients.java
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.danikula.videocache.file.FileCache;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import static com.danikula.videocache.Preconditions.checkNotNull;

            proxyCache = null;
        }
    }

    public void registerCacheListener(CacheListener cacheListener) {
        listeners.add(cacheListener);
    }

    public void unregisterCacheListener(CacheListener cacheListener) {
        listeners.remove(cacheListener);
    }

    public void shutdown() {
        listeners.clear();
        if (proxyCache != null) {
            proxyCache.registerCacheListener(null);
            proxyCache.shutdown();
            proxyCache = null;
        }
        clientsCount.set(0);
    }

    public int getClientsCount() {
        return clientsCount.get();
    }

    private HttpProxyCache newHttpProxyCache() throws ProxyCacheException {
        HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage, config.headerInjector);
        FileCache cache = new FileCache(config.generateCacheFile(url), config.diskUsage);
        HttpProxyCache httpProxyCache = new HttpProxyCache(source, cache);
        httpProxyCache.registerCacheListener(uiCacheListener);