001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.sequence;
020
021import java.util.ArrayList;
022import java.util.Map.Entry;
023import java.util.TreeMap;
024
025import icy.image.IcyBufferedImage;
026
027/**
028 * @author Fabrice de Chaumont
029 */
030public class VolumetricImage
031{
032    protected final Sequence sequence;
033    protected final TreeMap<Integer, IcyBufferedImage> images;
034
035    public VolumetricImage(Sequence seq)
036    {
037        sequence = seq;
038        images = new TreeMap<Integer, IcyBufferedImage>();
039    }
040
041    public VolumetricImage()
042    {
043        this(null);
044    }
045
046    /**
047     * Return number of loaded image
048     */
049    public int getNumImage()
050    {
051        int result = 0;
052
053        synchronized (images)
054        {
055            for (Entry<Integer, IcyBufferedImage> entry : images.entrySet())
056                if (entry.getValue() != null)
057                    result++;
058        }
059
060        return result;
061    }
062
063    /**
064     * Return the size of list
065     */
066    public int getSize()
067    {
068        synchronized (images)
069        {
070            if (images.isEmpty())
071                return 0;
072
073            return images.lastKey().intValue() + 1;
074        }
075    }
076
077    /**
078     * Return true if the volumetricImage doesn't contains any image
079     */
080    public boolean isEmpty()
081    {
082        return (getSize() == 0);
083    }
084
085    /**
086     * Return the first image
087     */
088    public IcyBufferedImage getFirstImage()
089    {
090        final Entry<Integer, IcyBufferedImage> entry;
091
092        synchronized (images)
093        {
094            entry = images.firstEntry();
095        }
096
097        if (entry != null)
098            return entry.getValue();
099
100        return null;
101    }
102
103    public IcyBufferedImage getFirstNonNullImage()
104    {
105        synchronized (images)
106        {
107            for (IcyBufferedImage img : images.values())
108            {
109                if (img != null)
110                    return img;
111            }
112        }
113
114        return null;
115    }
116
117    /**
118     * Return the last image
119     */
120    public IcyBufferedImage getLastImage()
121    {
122        final Entry<Integer, IcyBufferedImage> entry;
123
124        synchronized (images)
125        {
126            entry = images.lastEntry();
127        }
128
129        if (entry != null)
130            return entry.getValue();
131
132        return null;
133    }
134
135    /**
136     * Return image at position z
137     */
138    public IcyBufferedImage getImage(int z)
139    {
140        synchronized (images)
141        {
142            return images.get(Integer.valueOf(z));
143        }
144    }
145
146    /**
147     * Remove all image
148     */
149    public void clear()
150    {
151        if (sequence != null)
152            sequence.beginUpdate();
153
154        try
155        {
156            synchronized (images)
157            {
158                while (!images.isEmpty())
159                {
160                    final IcyBufferedImage image = images.pollFirstEntry().getValue();
161                    // raise event on sequence
162                    if ((image != null) && (sequence != null))
163                        sequence.onImageRemoved(image);
164                }
165            }
166        }
167        finally
168        {
169            if (sequence != null)
170                sequence.endUpdate();
171        }
172    }
173
174    /**
175     * Remove image at position z
176     */
177    public boolean removeImage(int z)
178    {
179        final IcyBufferedImage image;
180
181        synchronized (images)
182        {
183            image = images.remove(Integer.valueOf(z));
184        }
185
186        // raise event on sequence
187        if ((image != null) && (sequence != null))
188            sequence.onImageRemoved(image);
189
190        return image != null;
191    }
192
193    /**
194     * Set an image at the specified position
195     * 
196     * @param image
197     */
198    public void setImage(int z, IcyBufferedImage image)
199    {
200        final IcyBufferedImage oldImg = getImage(z);
201
202        if (sequence != null)
203            sequence.beginUpdate();
204        try
205        {
206            // set the new image
207            synchronized (images)
208            {
209                images.put(Integer.valueOf(z), image);
210            }
211
212            // raise event on sequence
213            if (sequence != null)
214            {
215                // we are replacing a previous image ?
216                if (oldImg != null)
217                    sequence.onImageReplaced(oldImg, image);
218                else
219                    sequence.onImageAdded(image);
220            }
221        }
222        finally
223        {
224            if (sequence != null)
225                sequence.endUpdate();
226        }
227    }
228
229    /**
230     * Return all images of volume image as TreeMap (contains z position)
231     */
232    public TreeMap<Integer, IcyBufferedImage> getImages()
233    {
234        synchronized (images)
235        {
236            return new TreeMap<Integer, IcyBufferedImage>(images);
237        }
238    }
239
240    /**
241     * Return all images of volume image
242     */
243    public ArrayList<IcyBufferedImage> getAllImage()
244    {
245        synchronized (images)
246        {
247            return new ArrayList<IcyBufferedImage>(images.values());
248        }
249    }
250
251    /**
252     * Remove empty element of image list
253     */
254    public void pack()
255    {
256        if (sequence != null)
257            sequence.beginUpdate();
258        try
259        {
260            synchronized (images)
261            {
262                for (Entry<Integer, IcyBufferedImage> entry : images.entrySet())
263                {
264                    final IcyBufferedImage image = entry.getValue();
265
266                    if (image == null)
267                        removeImage(entry.getKey().intValue());
268                }
269            }
270        }
271        finally
272        {
273            if (sequence != null)
274                sequence.endUpdate();
275        }
276    }
277
278}