package de.duehl.swing.ui.elements.pictures;

/*
 * Copyright 2023 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Diese Klasse speichert eingelesene Bilder.
 *
 * Vorteile:
 *  - Ein neues Betrachten des Bildes geht schneller.
 *
 * Nachteile:
 *  - Ändert sich das Bild zwischendurch, sieht man dann noch das alte Bild.
 *  - Außerdem könnte beim Betrachten sehr vieler Bilder der Speicher recht voll werden.
 *
 * Um den zweiten Punkt zu vermeiden, kann man dem Cache eine Obergrenze der gespeicherten Inhalte
 * übergeben. Tut man das nicht, werden beliebig viele Bilder gespeichert.
 * Begrenzt man die Größe, fallen die ältesten Bilder aus dem Cache, sobald dieser voll ist.
 *
 * @version 1.01     2023-12-15
 * @author Christian Dühl
 */

class PictureCache {

    /** Die Standard-Größe des Caches. */
    private static final int DEFAULT_CACHE_SIZE = Integer.MAX_VALUE;

    /** Die Größe des Caches. */
    private final int cacheSize;

    /**
     * Die Liste mit den Dateinamen der gespeicherten Bilder.
     *
     * Um die ältesten Bildinhalte rausschmeißen zu können, brauchen wir auch diese Liste.
     */
    private final List<String> knownFilenames;

    /** Das Verzeichnis der Bildinhalte nach den Dateinamen. */
    private final Map<String, BufferedImage> imageByFilename;

    /** Konstruktor für einen Cache, der beliebig viele Bilder speichert. */
    public PictureCache() {
        this(DEFAULT_CACHE_SIZE);
    }

    /**
     * Konstruktor.
     *
     * @param cacheSize
     *            Die Größe des Caches.
     */
    public PictureCache(int cacheSize) {
        this.cacheSize = cacheSize;
        knownFilenames = new ArrayList<>();
        imageByFilename = new HashMap<>();
    }

    /**
     * Gibt an, ob zum übergebenen Dateinamen der Bildinhalt gespeichert ist.
     *
     * @param pictureFilename
     *            Der Name des Bildes.
     * @return Wahrheitswert: true genau dann, wenn der Bildinhalt zum Dateiname im Cache
     *         gespeichert ist.
     */
    public boolean isFilenameKnown(String pictureFilename) {
        return knownFilenames.contains(pictureFilename);
    }

    /**
     * Gibt zum übergebenen Dateinamen den gespeicherten Bildinhalt zurück.
     *
     * Ist der Dateiname nicht bekannt, wird eine Ausnahme geworfen, hier sollte man zuerst mit
     * isFilenameKnown() prüfen.
     *
     * @param pictureFilename
     *            Der Name des Bildes.
     * @return Der gespeicherte Bildinhalt.
     */
    public BufferedImage load(String pictureFilename) {
        return imageByFilename.get(pictureFilename);
    }

    /**
     * Legt den Bildinhalt zum Dateinamen im Cache ab.
     *
     * @param pictureFilename
     *            Der Name des Bildes.
     * @param image
     *            Der zu speichernde Bildinhalt.
     */
    public void store(String pictureFilename, BufferedImage image) {
        if (knownFilenames.size() > cacheSize) {
            removeOldestPictureFromCache();
        }

        knownFilenames.add(pictureFilename);
        imageByFilename.put(pictureFilename, image);
    }

    private void removeOldestPictureFromCache() {
        String filenameToRemove = knownFilenames.remove(0);
        imageByFilename.remove(filenameToRemove);
    }

}
