/***************************************************************
 * Copyright (c) 2014 - 2015 , gurkenlabs, All rights reserved *
 ***************************************************************/
package de.gurkenlabs.litiengine.graphics;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;

import de.gurkenlabs.util.image.ImageSerializer;
import de.gurkenlabs.util.io.FileUtilities;
import de.gurkenlabs.util.zip.CompressionUtilities;

/**
 * The Class ImageCache.
 */
public class ImageCache {
  /** The Constant CACHE_DIRECTORY. */
  public static final String CACHE_DIRECTORY = "cache/";

  public static final String CACHE_DUMP_NAME = "imagecache.dump";

  public static final ImageCache IMAGES = new ImageCache("images");
  public static final String IMAGES_DIRECTORY = "images";

  public static final String MAP_DIRECTORY = "map";

  public static final ImageCache MAPS = new ImageCache("map");

  public static final ImageCache SPRITES = new ImageCache("sprites");

  public static final String SPRITES_DIRECTORY = "sprites";

  /** The cache. */
  private final ConcurrentHashMap<String, BufferedImage> cache;

  /** The sub folder. */
  private final String subFolder;

  /**
   * Instantiates a new image cache.
   *
   * @param subfolder
   *          the subfolder
   */
  private ImageCache(final String subfolder) {
    this.cache = new ConcurrentHashMap<>();
    this.subFolder = subfolder;
  }

  public static void loadCache() {
    if (new File(CACHE_DIRECTORY).exists()) {
      System.out.println("Cache dump '" + CACHE_DUMP_NAME + "' was not loaded because the cache folder'" + CACHE_DIRECTORY + "' already exists.");
      return;
    }

    final InputStream in = FileUtilities.getGameResource(CACHE_DUMP_NAME);
    if (in == null) {
      System.out.println("loading cache dump from '" + CACHE_DUMP_NAME + "' failed!");
      return;
    }

    try {
      CompressionUtilities.unzip(in, new File(CACHE_DIRECTORY));
      System.out.println("cache loaded from '" + CACHE_DUMP_NAME + "'");
    } catch (final IOException e) {
      e.printStackTrace();
    }
  }

  public static void saveCache(final String path) {
    final File cacheFile = new File(path, CACHE_DUMP_NAME);
    try {
      if (cacheFile.exists()) {
        cacheFile.delete();
      }

      CompressionUtilities.zip(new File(CACHE_DIRECTORY), cacheFile);
      System.out.println("cache dumped to " + cacheFile.toPath());
    } catch (final IOException e) {
      e.printStackTrace();
    }
  }

  public void clearPersistent() {
    final File dir = new File(this.getSubFolderName());
    if (!dir.exists() || !dir.isDirectory()) {
      return;
    }

    System.out.println("deleted '" + dir.toString() + "'");
    FileUtilities.deleteDir(dir);
    this.cache.clear();
  }

  /**
   * Contains key.
   *
   * @param key
   *          the key
   * @return true, if successful
   */
  public boolean containsKey(final String key) {
    return this.cache.containsKey(key) || new File(this.getFileName(key)).exists();
  }

  /**
   * Gets the.
   *
   * @param key
   *          the key
   * @return the buffered image
   */
  public BufferedImage get(final String key) {
    if (this.cache.containsKey(key)) {
      return this.cache.get(key);
    }

    return this.loadImage(key);
  }

  /**
   * Load all.
   */
  public void loadAll() {
    final File dir = new File(this.getSubFolderName());
    if (!dir.exists() || !dir.isDirectory()) {
      return;
    }
    final File[] directoryListing = dir.listFiles();
    if (directoryListing != null) {
      for (final File child : directoryListing) {
        if (!child.isFile()) {
          continue;
        }

        final BufferedImage img = this.loadImage(child.getName());

        // clean up cached file if the image is null
        if (img == null) {
          child.delete();
        }
      }
    }
  }

  /**
   * Put.
   *
   * @param key
   *          the key
   * @param value
   *          the value
   * @return the buffered image
   */
  public BufferedImage put(final String key, final BufferedImage value) {
    return this.cache.put(key, value);
  }

  /**
   * Put persistent.
   *
   * @param key
   *          the key
   * @param value
   *          the value
   * @return the buffered image
   */
  public BufferedImage putPersistent(final String key, final BufferedImage value) {
    if (key == null || key.isEmpty() || value == null) {
      return null;
    }

    this.cache.put(key, value);
    this.saveImage(key, value);
    return value;
  }

  /**
   * Gets the file name.
   *
   * @param key
   *          the key
   * @return the file name
   */
  private String getFileName(final String key) {
    return this.getSubFolderName() + "\\" + key;
  }

  /**
   * Gets the sub folder name.
   *
   * @return the sub folder name
   */
  private String getSubFolderName() {
    return CACHE_DIRECTORY + this.subFolder;
  }

  /**
   * Load image.
   *
   * @param key
   *          the key
   * @return the buffered image
   */
  private synchronized BufferedImage loadImage(final String key) {
    final BufferedImage img = ImageSerializer.loadImage(this.getFileName(key));
    if (img == null) {
      return null;
    }

    this.cache.put(key, img);
    return img;
  }

  /**
   * Save image.
   *
   * @param key
   *          the key
   * @param value
   *          the value
   */
  private void saveImage(final String key, final BufferedImage value) {
    ImageSerializer.saveImage(this.getFileName(key), value);
  }
}

@@ -356,16 +356,69 @@
 tream;%0D%0A
+import java.util.ArrayList;%0D%0Aimport java.util.List;%0D%0A
 import j
@@ -3018,32 +3018,379 @@
 lear();%0D%0A  %7D%0D%0A%0D%0A
+  public void clear() %7B%0D%0A    this.cache.clear();%0D%0A  %7D%0D%0A%0D%0A  public void clear(final String regex) %7B%0D%0A    List%3CString%3E remove = new ArrayList%3C%3E();%0D%0A    for (String key : this.cache.keySet()) %7B%0D%0A      if (key.matches(regex)) %7B%0D%0A        remove.add(key);%0D%0A      %7D%0D%0A    %7D%0D%0A%0D%0A    for (String key : remove) %7B%0D%0A      this.cache.remove(key);%0D%0A    %7D%0D%0A  %7D%0D%0A%0D%0A
   /**%0D%0A   * Cont

Implement possiblitly to remove images from the cache by regex.