package org.jabref.logic.citationstyle;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.event.EntryRemovedEvent;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.event.EntryChangedEvent;

import com.google.common.eventbus.Subscribe;


/**
 * Caches the generated Citations for quicker access
 * {@link CitationStyleGenerator} generates the citaiton with JavaScript which may take some time
 */
public class CitationStyleCache {

    private CitationStyle citationStyle = CitationStyle.getDefault();
    private Map<BibEntry, String> citationStylesCache = new HashMap<>();


    public CitationStyleCache(BibDatabaseContext bibDatabaseContext) {
        this(bibDatabaseContext, CitationStyle.getDefault());
    }

    public CitationStyleCache(BibDatabaseContext bibDatabaseContext, CitationStyle citationStyle) {
        this.setCitationStyle(citationStyle);
        bibDatabaseContext.getDatabase().registerListener(new BibDatabaseEntryListener());
    }

    /**
     * returns the citation for the given BibEntry and the set CitationStyle
     */
    public String getCitationFor(BibEntry entry) {
        String citation = citationStylesCache.get(entry);
        if (citation == null) {
            citation = CitationStyleGenerator.generateCitation(entry, this.citationStyle.getSource(), CitationStyleOutputFormat.HTML);
            citationStylesCache.put(entry, citation);
        }
        return citation;
    }

    public void setCitationStyle(CitationStyle citationStyle) {
        Objects.requireNonNull(citationStyle);
        if (!this.citationStyle.equals(citationStyle)) {
            this.citationStyle = citationStyle;
            this.citationStylesCache.clear();
        }
    }

    public CitationStyle getCitationStyle() {
        return citationStyle;
    }

    private class BibDatabaseEntryListener {
        /**
         * removes the outdated citation of the changed entry
         */
        @Subscribe
        public void listen(EntryChangedEvent entryChangedEvent) {
            citationStylesCache.remove(entryChangedEvent.getBibEntry());
        }

        /**
         * removes the citation of the removed entry as it's not needed anymore
         */
        @Subscribe
        public void listen(EntryRemovedEvent entryRemovedEvent) {
            citationStylesCache.remove(entryRemovedEvent.getBibEntry());
        }
    }

}

@@ -38,56 +38,8 @@
 e;%0A%0A
-import java.util.HashMap;%0Aimport java.util.Map;%0A
 impo
@@ -268,16 +268,150 @@
 Event;%0A%0A
+import com.google.common.cache.CacheBuilder;%0Aimport com.google.common.cache.CacheLoader;%0Aimport com.google.common.cache.LoadingCache;%0A
 import c
@@ -558,18 +558,18 @@
 the cita
-i
 t
+i
 on with 
@@ -655,31 +655,65 @@
 private 
-Ci
+s
 tati
-onStyle c
+c final int CACHE_SIZE = 1024;%0A    private C
 itationS
@@ -717,19 +717,17 @@
 onStyle 
-= C
+c
 itationS
@@ -730,29 +730,16 @@
 ionStyle
-.getDefault()
 ;%0A    pr
@@ -744,19 +744,28 @@
 private 
-Map
+LoadingCache
 %3CBibEntr
@@ -792,32 +792,13 @@
 tyle
-s
 Cache
- = new HashMap%3C%3E()
 ;%0A%0A%0A
@@ -1050,20 +1050,17 @@
    this.
-setC
+c
 itationS
@@ -1063,17 +1063,19 @@
 ionStyle
-(
+ = 
 citation
@@ -1071,33 +1071,32 @@
  = citationStyle
-)
 ;%0A        bibDat
@@ -1093,191 +1093,153 @@
     
-bibDatabaseContext.getDatabase().registerListener(new BibDatabaseEntryListener());%0A    %7D%0A
+citationStyleCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).build(new CacheLoader%3CBibEntry, String%3E() %7B
 %0A    
-/**%0A
      
-* returns the citation for the given BibEntry and the set CitationStyle%0A
+   @Override%0A   
      
-*/%0A
     
@@ -1256,22 +1256,12 @@
 ing 
-getCitationFor
+load
 (Bib
@@ -1277,122 +1277,49 @@
 ry) 
-%7B%0A        String citation = citationStylesCache.get(entry);%0A        if (citation == null) %7B%0A            citation =
+throws Exception %7B%0A                return
  Cit
@@ -1362,22 +1362,20 @@
 (entry, 
-this.c
+getC
 itationS
@@ -1374,24 +1374,26 @@
 itationStyle
+()
 .getSource()
@@ -1443,83 +1443,317 @@
     
-citationStylesCache.put(entry, citation);%0A        %7D%0A        return citation
+%7D%0A        %7D);%0A        bibDatabaseContext.getDatabase().registerListener(new BibDatabaseEntryListener());%0A    %7D%0A%0A    /**%0A     * returns the citation for the given BibEntry and the set CitationStyle%0A     */%0A    public String getCitationFor(BibEntry entry) %7B%0A        return citationStyleCache.getUnchecked(entry)
 ;%0A  
@@ -2007,20 +2007,27 @@
 tyle
-s
 Cache.
-clear
+invalidateAll
 ();%0A
@@ -2096,32 +2096,37 @@
 %0A        return 
+this.
 citationStyle;%0A 
@@ -2368,36 +2368,39 @@
 itationStyle
-s
 Cache.
-remov
+invalidat
 e(entryChang
@@ -2652,20 +2652,23 @@
 tyle
-s
 Cache.
-remov
+invalidat
 e(en
@@ -2715,11 +2715,10 @@
 %7D%0A    %7D%0A
-%0A
 %7D%0A

Add Guava Cache to CitationStyleCache (#3089)