/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.micromanager.acquisition;

import org.micromanager.api.TaggedImageStorage;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import mmcorej.TaggedImage;
import org.micromanager.utils.MDUtils;
import org.micromanager.utils.MMException;
import org.micromanager.utils.ReportingUtils;

/**
 *
 * @author arthur
 */
public class MMImageCache implements TaggedImageStorage {

   private final int taggedImgQueueSize_ = 50;
   private TaggedImageStorage imageFileManager_;
   private String comment_ = "";
   private Map<String, String> summaryMetadata_;
   private Set<String> changingKeys_;
   private Map<String, String> firstTags_;
   private static ImageCollection coll_;

   MMImageCache(TaggedImageStorage imageFileManager) {
      imageFileManager_ = imageFileManager;
      changingKeys_ = new HashSet<String>();
      if (coll_ == null) {
         coll_ = new ImageCollection();
      }
   }

   public void finished() {
      imageFileManager_.finished();
   }

   public void setDisplaySettings(Map<String, String> settings) {
      throw new UnsupportedOperationException("Not supported yet.");
   }

   public Map<String, String> getDisplaySettings() {
      throw new UnsupportedOperationException("Not supported yet.");
   }

   private class ImageCollection {

      private ConcurrentLinkedQueue<String> LabelQueue_;
      private Set<String> LabelSet_;
      private HashMap<String, TaggedImage> taggedImgTable_;

      public ImageCollection() {
         LabelQueue_ = new ConcurrentLinkedQueue<String>();
         taggedImgTable_ = new HashMap<String, TaggedImage>();
         LabelSet_ = new HashSet<String>();
      }

      public void add(MMImageCache cache, TaggedImage taggedImage) {
         String label = MDUtils.getLabel(taggedImage.tags) + "/" + cache.hashCode();
         taggedImgTable_.put(label, taggedImage);
         LabelQueue_.add(label);
         int n = (LabelQueue_.size() - taggedImgQueueSize_);
         for (int i = 0; i < n; ++i) {
            dropOne();
         }
         LabelSet_.add(label);
      }

      private void dropOne() {
         String label = LabelQueue_.poll();
         taggedImgTable_.remove(label);
      }

      public TaggedImage get(MMImageCache cache, String label) {
         label += "/" + cache.hashCode();
         LabelQueue_.remove(label);
         LabelQueue_.add(label);
         return taggedImgTable_.get(label);
      }

      public Set<String> getLabels(MMImageCache cache) {
         String hashCode = Long.toString(cache.hashCode());
         Set labelSubSet = new HashSet<String>();
         for (String label: LabelSet_) {
            if (label.endsWith(hashCode)) {
               labelSubSet.add(label.split("/")[0]);
            }
         }
         return labelSubSet;
      }
   }

   public void saveAs(TaggedImageStorage newImageFileManager) {
      if (newImageFileManager == null) {
         return;
      }
      for (String label : coll_.getLabels(this)) {
         int pos[] = MDUtils.getIndices(label);
         try {
            newImageFileManager.putImage(getImage(pos[0], pos[1], pos[2], pos[3]));
         } catch (MMException ex) {
            ReportingUtils.logError(ex);
         }
      }
      newImageFileManager.setComment(this.getComment());
      newImageFileManager.finished();
      imageFileManager_ = newImageFileManager;
   }

   public String putImage(TaggedImage taggedImg) {
      try {
         coll_.add(this, taggedImg);
         checkForChangingTags(taggedImg);
         return imageFileManager_.putImage(taggedImg);
      } catch (Exception ex) {
         ReportingUtils.logError(ex);
         return null;
      }
   }

   public TaggedImage getImage(int channel, int slice, int frame, int position) {
      String label = MDUtils.generateLabel(channel, slice, frame, position);
      TaggedImage taggedImg = coll_.get(this, label);
      if (taggedImg == null) {
         taggedImg = imageFileManager_.getImage(channel, slice, frame, position);
         if (taggedImg != null) {
            checkForChangingTags(taggedImg);
         }
      }
      return taggedImg;
   }

   private void checkForChangingTags(TaggedImage taggedImg) {
      if (firstTags_ == null) {
         firstTags_ = taggedImg.tags;
      } else {
         for (String key : taggedImg.tags.keySet()) {
            if (!firstTags_.containsKey(key) || !firstTags_.get(key).contentEquals(taggedImg.tags.get(key))) {
               changingKeys_.add(key);
            }
         }
      }
   }

   public void setComment(String text) {
      if (comment_==null || !comment_.contentEquals(text)) {
         imageFileManager_.setComment(text);
         comment_ = text;
      }
   }

   public String getComment() {
      if (comment_ == null || comment_.contentEquals("")) {
         comment_ = imageFileManager_.getComment();
      }
      return comment_;
   }

   public Map<String, String> getSummaryMetadata() {
      return imageFileManager_.getSummaryMetadata();
   }

   public void setSummaryMetadata(Map<String, String> tags) {
      imageFileManager_.setSummaryMetadata(tags);
   }

   public Set<String> getChangingKeys() {
      return changingKeys_;
   }
}

@@ -132,16 +132,52 @@
 ition;%0A%0A
+import java.lang.ref.SoftReference;%0A
 import o
@@ -612,55 +612,8 @@
  %7B%0A%0A
-   private final int taggedImgQueueSize_ = 50;%0A
    p
@@ -694,57 +694,8 @@
 %22%22;%0A
-   private Map%3CString, String%3E summaryMetadata_;%0A
    p
@@ -1412,17 +1412,16 @@
 ction %7B%0A
-%0A
       pr
@@ -1536,26 +1536,28 @@
 String, 
-TaggedImag
+SoftReferenc
 e%3E tagge
@@ -1709,26 +1709,28 @@
 String, 
-TaggedImag
+SoftReferenc
 e%3E();%0A  
@@ -1974,188 +1974,40 @@
 el, 
-taggedImage);%0A         LabelQueue_.add(label);%0A         int n = (LabelQueue_.size() - taggedImgQueueSize_);%0A         for (int i = 0; i %3C n; ++i) %7B%0A            dropOne();%0A         %7D
+new SoftReference(taggedImage));
 %0A   
@@ -2017,19 +2017,21 @@
    Label
-Set
+Queue
 _.add(la
@@ -2046,117 +2046,24 @@
     
-%7D%0A%0A      private void dropOne() %7B%0A         String label = LabelQueue_.poll();%0A         taggedImgTable_.remove
+   LabelSet_.add
 (lab
@@ -2259,32 +2259,46 @@
 %0A         return
+ (TaggedImage)
  taggedImgTable_
@@ -2304,24 +2304,30 @@
 _.get(label)
+.get()
 ;%0A      %7D%0A%0A 

Use SoftReference for caching TaggedImages.