package ij.plugin;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.io.*;
import java.awt.*;
import java.io.*;
import java.util.Properties;

/** This plugin opens a multi-page TIFF file as a virtual stack. It
    implements the File/Import/TIFF Virtual Stack command. */
public class FileInfoVirtualStack extends VirtualStack implements PlugIn {
    FileInfo[] info;
    int nImages;
    
    /* Default constructor. */
    public FileInfoVirtualStack() {}

    /* Constructs a FileInfoVirtualStack from a FileInfo object. */
    public FileInfoVirtualStack(FileInfo fi) {
        info = new FileInfo[1];
        info[0] = fi;
        open();
    }

    public void run(String arg) {
        OpenDialog  od = new OpenDialog("Open TIFF", arg);
        String name = od.getFileName();
        if (name==null) return;
        if (name.endsWith(".zip")) {
            IJ.error("Virtual Stack", "ZIP compressed stacks not supported");
            return;
        }
        String  dir = od.getDirectory();
        TiffDecoder td = new TiffDecoder(dir, name);
        if (IJ.debugMode) td.enableDebugging();
        try {info = td.getTiffInfo();}
        catch (IOException e) {
            String msg = e.getMessage();
            if (msg==null||msg.equals("")) msg = ""+e;
            IJ.error("TiffDecoder", msg);
            return;
        }
        if (info==null || info.length==0) {
            IJ.error("Virtual Stack", "This does not appear to be a TIFF stack");
            return;
        }
        open();
    }
    
    void open() {
        FileInfo fi = info[0];
        int n = fi.nImages;
        if (info.length==1 && n>1) {
            info = new FileInfo[n];
            long size = fi.width*fi.height*fi.getBytesPerPixel();
            for (int i=0; i<n; i++) {
                info[i] = (FileInfo)fi.clone();
                info[i].nImages = 1;
                info[i].longOffset = (long)fi.offset + i*(size + fi.gapBetweenImages);
            }
        }
        nImages = info.length;
        FileOpener fo = new FileOpener(info[0] );
        ImagePlus imp = fo.open(false);
        Properties props = fo.decodeDescriptionString(fi);
        ImagePlus imp2 = new ImagePlus(fi.fileName, this);
        imp2.setFileInfo(fi);
        if (imp!=null && props!=null) {
            imp2.setCalibration(imp.getCalibration());
            int channels = getInt(props,"channels");
            int slices = getInt(props,"slices");
            int frames = getInt(props,"frames");
            if (channels*slices*frames==nImages) {
                imp2.setDimensions(channels, slices, frames);
                if (getBoolean(props, "hyperstack"))
                    imp2.setOpenAsHyperStack(true);
            }
            if (channels>1 && fi.description!=null) {
                int mode = CompositeImage.COMPOSITE;
                if (fi.description.indexOf("mode=color")!=-1)
                    mode = CompositeImage.COLOR;
                else if (fi.description.indexOf("mode=gray")!=-1)
                    mode = CompositeImage.GRAYSCALE;
                imp2 = new CompositeImage(imp2, mode);
            }
        }
        imp2.show();
    }

    int getInt(Properties props, String key) {
        Double n = getNumber(props, key);
        return n!=null?(int)n.doubleValue():1;
    }

    Double getNumber(Properties props, String key) {
        String s = props.getProperty(key);
        if (s!=null) {
            try {
                return Double.valueOf(s);
            } catch (NumberFormatException e) {}
        }   
        return null;
    }

    boolean getBoolean(Properties props, String key) {
        String s = props.getProperty(key);
        return s!=null&&s.equals("true")?true:false;
    }

    /** Deletes the specified image, were 1<=n<=nImages. */
    public void deleteSlice(int n) {
        if (n<1 || n>nImages)
            throw new IllegalArgumentException("Argument out of range: "+n);
        if (nImages<1) return;
        for (int i=n; i<nImages; i++)
            info[i-1] = info[i];
        info[nImages-1] = null;
        nImages--;
    }
    
    /** Returns an ImageProcessor for the specified image,
        were 1<=n<=nImages. Returns null if the stack is empty.
    */
    public ImageProcessor getProcessor(int n) {
        if (n<1 || n>nImages)
            throw new IllegalArgumentException("Argument out of range: "+n);
        if (IJ.debugMode) IJ.log("FileInfoVirtualStack.getProcessor: "+n);
        info[n-1].nImages = 1; // why is this needed?
        FileOpener fo = new FileOpener(info[n-1]);
        ImagePlus imp = fo.open(false);
        if (imp!=null)
            return imp.getProcessor();
        else
            return null;
     }
 
     /** Returns the number of images in this stack. */
    public int getSize() {
        return nImages;
    }

    /** Returns null. */
    public String getSliceLabel(int n) {
         return null;
    }

    public int getWidth() {
        return info[0].width;
    }
    
    public int getHeight() {
        return info[0].height;
    }
    
}