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

import ij.ImagePlus;
import ij.process.ImageProcessor;
import java.awt.image.ColorModel;
import mmcorej.TaggedImage;
import org.json.JSONObject;
import org.micromanager.api.TaggedImageStorage;
import org.micromanager.utils.ImageUtils;
import org.micromanager.utils.MDUtils;
import org.micromanager.utils.ReportingUtils;

/**
 * This stack class provides the ImagePlus with images from the MMImageCache.
 * 
 */
public class AcquisitionVirtualStack extends ij.VirtualStack {
   final private TaggedImageStorage imageCache_;
   final private VirtualAcquisitionDisplay acq_;
   final protected int width_, height_, type_;
   private int nSlices_;
   private int positionIndex_ = 0;

   public AcquisitionVirtualStack(int width, int height, int type,
           ColorModel cm, TaggedImageStorage imageCache, int nSlices,
           VirtualAcquisitionDisplay acq) {
      super(width, height, cm, "");
      imageCache_ = imageCache;
      width_ = width;
      height_ = height;
      nSlices_ = nSlices;
      
      acq_ = acq;
      type_ = type;
   }

   public void setPositionIndex(int pos) {
      positionIndex_ = pos;
   }

   public int getPositionIndex() {
      return positionIndex_;
   }

   public VirtualAcquisitionDisplay getVirtualAcquisitionDisplay() {
      return acq_;
   }

   public void setSize(int size) {
      nSlices_ = size;
   }

   public TaggedImageStorage getCache() {
      return imageCache_;
   }

   public TaggedImage getTaggedImage(int flatIndex) {
      try {
         int[] pos;
         // If we don't have the ImagePlus yet, then we need to assume
         // we are on the very first image.
            ImagePlus imagePlus = acq_.getImagePlus();
         int nSlices;
         if (imagePlus == null) {
            pos = new int [] {1, 1, 1};
            nSlices = 1;
         } else {
            pos = imagePlus.convertIndexToPosition(flatIndex);
            nSlices = imagePlus.getNSlices();
         }
         int chanIndex = acq_.grayToRGBChannel(pos[0]-1);
         TaggedImage img ;
         int frame = pos[2] - 1;
         int slice = pos[1] - 1;
         
         do {
            int sliceSearchIndex = 0;
            do {
               img = imageCache_.getImage(chanIndex,
                       (nSlices + slice - sliceSearchIndex) % nSlices,
                       frame, positionIndex_);
               ++sliceSearchIndex;
            } while (img == null && sliceSearchIndex < nSlices && frame < imageCache_.lastAcquiredFrame());
            --frame;
         } while (img == null && frame >= 0  && frame < (imageCache_.lastAcquiredFrame()-1));
         return img;
      } catch (Exception e) {
         ReportingUtils.logError(e);
         return null;
      }
   }

   @Override
   public Object getPixels(int flatIndex) {
      Object pixels = null;
      try {
         TaggedImage image = getTaggedImage(flatIndex);
         if (image == null)
            pixels = ImageUtils.makeProcessor(type_, width_, height_).getPixels();
         else if(MDUtils.isGRAY(image)) {
            pixels = image.pix;
         } else if (MDUtils.isRGB32(image)) {
            pixels = ImageUtils.singleChannelFromRGB32((byte []) image.pix, (flatIndex-1) % 3);
         } else if (MDUtils.isRGB64(image)) {
            pixels = ImageUtils.singleChannelFromRGB64((short []) image.pix, (flatIndex-1) % 3);
         }
      } catch (Exception ex) {
         ReportingUtils.logError(ex);
      }

      return pixels;
   }

   @Override
   public ImageProcessor getProcessor(int flatIndex) {
      return ImageUtils.makeProcessor(type_, width_, height_, getPixels(flatIndex));
   }

   
   @Override
   public int getSize() {
      // returns the stack size of VirtualAcquisitionDisplay unless this size is -1
      // which occurs in constructor while hyperImage_ is still null. In this case
      // returns the number of slices speciefiec in AcquisitionVirtualStack constructor
      int size = acq_.getStackSize();
      if (size == -1)
          return nSlices_;
      return size;
   }

   @Override
   public String getSliceLabel(int n) {
      TaggedImage img = getTaggedImage(n);
      if (img == null)
         return "";
      JSONObject md = img.tags;
      try {
         return md.get("Acquisition-PixelSizeUm") + " um/px";
         //return MDUtils.getChannelName(md) + ", " + md.get("Acquisition-ZPositionUm") + " um(z), " + md.get("Acquisition-TimeMs") + " s";
      } catch (Exception ex) {
         return "";
      }
   }



}

@@ -2074,24 +2074,51 @@
 %0A         %7D%0A
+         TaggedImage img ;%0A
          int
@@ -2167,35 +2167,8 @@
 1);%0A
-         TaggedImage img ;%0A
     
@@ -2252,190 +2252,429 @@
     
-do %7B%0A            int sliceSearchIndex = 0;%0A            do %7B%0A               img = imageCache_.getImage(chanIndex,%0A                       (nSlices + slice - sliceSearch
+img = imageCache_.getImage(chanIndex, slice, frame, positionIndex_);%0A         int backIndex = slice - 1, forwardIndex = slice + 1;%0A         while (img == null) %7B%0A            if (backIndex %3E= 0) %7B%0A               img = imageCache_.getImage(chanIndex, backIndex, frame, positionIndex_);%0A               if (img != null)%0A                  break;%0A               backIndex--;%0A            %7D%0A            if (forward
 Index
-) %25
+ %3C
  nSlices
 ,%0A  
@@ -2661,33 +2661,35 @@
 dIndex %3C nSlices
-,
+) %7B
 %0A               
@@ -2692,73 +2692,170 @@
     
-        frame, positionIndex_);%0A               ++sliceSearch
+img = imageCache_.getImage(chanIndex, forwardIndex, frame, positionIndex_);%0A               if (img != null)%0A                  break;%0A               forward
 Index
+++
 ;%0A  
@@ -2869,217 +2869,126 @@
    %7D
- while (img == null && sliceSearchIndex %3C nSlices && frame %3C imageCache_.lastAcquiredFrame());%0A            --frame;%0A         %7D while (img == null && frame %3E= 0  && frame %3C (imageCache_.lastAcquiredFrame()-1));
+%0A            if (backIndex %3C 0 && forwardIndex %3E= nSlices)%0A               break;               %0A         %7D%0A           
 %0A   

Correct behavior for multiple channels, some of which skip z stacks