package ij.io;
import ij.VirtualStack;
import ij.IJ;
import java.io.*;
import java.util.Properties;

/** This class consists of public fields that describe an image file. */
public class FileInfo implements Cloneable {

    /** 8-bit unsigned integer (0-255). */
    public static final int GRAY8 = 0;
    
    /** 16-bit signed integer (-32768-32767). Imported signed images
        are converted to unsigned by adding 32768. */
    public static final int GRAY16_SIGNED = 1;
    
    /** 16-bit unsigned integer (0-65535). */
    public static final int GRAY16_UNSIGNED = 2;
    
    /** 32-bit signed integer. Imported 32-bit integer images are
        converted to floating-point. */
    public static final int GRAY32_INT = 3;
    
    /** 32-bit floating-point. */
    public static final int GRAY32_FLOAT = 4;
    
    /** 8-bit unsigned integer with color lookup table. */
    public static final int COLOR8 = 5;
    
    /** 24-bit interleaved RGB. Import/export only. */
    public static final int RGB = 6;    
    
    /** 24-bit planer RGB. Import only. */
    public static final int RGB_PLANAR = 7;
    
    /** 1-bit black and white. Import only. */
    public static final int BITMAP = 8;
    
    /** 32-bit interleaved ARGB. Import only. */
    public static final int ARGB = 9;
    
    /** 24-bit interleaved BGR. Import only. */
    public static final int BGR = 10;
    
    /** 32-bit unsigned integer. Imported 32-bit integer images are
        converted to floating-point. */
    public static final int GRAY32_UNSIGNED = 11;
    
    /** 48-bit interleaved RGB. */
    public static final int RGB48 = 12; 

    /** 12-bit unsigned integer (0-4095). Import only. */
    public static final int GRAY12_UNSIGNED = 13;   

    /** 24-bit unsigned integer. Import only. */
    public static final int GRAY24_UNSIGNED = 14;   

    /** 32-bit interleaved BARG (MCID). Import only. */
    public static final int BARG  = 15; 

    /** 64-bit floating-point. Import only.*/
    public static final int GRAY64_FLOAT  = 16; 

    /** 48-bit planar RGB. Import only. */
    public static final int RGB48_PLANAR = 17;  

    /** 32-bit interleaved ABGR. Import only. */
    public static final int ABGR = 18;

    /** 32-bit interleaved CMYK. Import only. */
    public static final int CMYK = 19;

    // File formats
    public static final int UNKNOWN = 0;
    public static final int RAW = 1;
    public static final int TIFF = 2;
    public static final int GIF_OR_JPG = 3;
    public static final int FITS = 4;
    public static final int BMP = 5;
    public static final int DICOM = 6;
    public static final int ZIP_ARCHIVE = 7;
    public static final int PGM = 8;
    public static final int IMAGEIO = 9;

    // Compression modes
    public static final int COMPRESSION_UNKNOWN = 0;
    public static final int COMPRESSION_NONE= 1;
    public static final int LZW = 2;
    public static final int LZW_WITH_DIFFERENCING = 3;
    public static final int JPEG = 4;
    public static final int PACK_BITS = 5;
    public static final int ZIP = 6;
    
    /* File format (TIFF, GIF_OR_JPG, BMP, etc.). Used by the File/Revert command */
    public int fileFormat;
    
    /* File type (GRAY8, GRAY_16_UNSIGNED, RGB, etc.) */
    public int fileType;    
    public String fileName;
    public String directory;
    public String url;
    public int width;
    public int height;
    public int offset=0;  // Use getOffset() to read
    public int nImages;
    public int gapBetweenImages;   // Use getGap() to read
    public boolean whiteIsZero;
    public boolean intelByteOrder;
    public int compression;
    public int[] stripOffsets;  
    public int[] stripLengths;
    public int rowsPerStrip;
    public int lutSize;
    public byte[] reds;
    public byte[] greens;
    public byte[] blues;
    public Object pixels;   
    public String debugInfo;
    public String[] sliceLabels;
    public String info;
    public InputStream inputStream;
    public VirtualStack virtualStack;
    public int sliceNumber; // used by FileInfoVirtualStack
    
    public double pixelWidth=1.0;
    public double pixelHeight=1.0;
    public double pixelDepth=1.0;
    public String unit;
    public int calibrationFunction;
    public double[] coefficients;
    public String valueUnit;
    public double frameInterval;
    public String description;
    // Use <i>longOffset</i> instead of <i>offset</i> when offset>2147483647.
    public long longOffset;  // Use getOffset() to read
    // Use <i>longGap</i> instead of <i>gapBetweenImages</i> when gap>2147483647.
    public long longGap;  // Use getGap() to read
    // Extra metadata to be stored in the TIFF header
    public int[] metaDataTypes; // must be < 0xffffff
    public byte[][] metaData;
    public double[] displayRanges;
    public byte[][] channelLuts;
    public byte[] plot;         // serialized plot
    public byte[] roi;          // serialized roi
    public byte[][] overlay;    // serialized overlay objects
    public int samplesPerPixel;
    public String openNextDir, openNextName;
    public String[] properties; // {key,value,key,value,...}
    public boolean imageSaved;
    
    /** Creates a FileInfo object with all of its fields set to their default value. */
     public FileInfo() {
        // assign default values
        fileFormat = UNKNOWN;
        fileType = GRAY8;
        fileName = "Untitled";
        directory = "";
        url = "";
        nImages = 1;
        compression = COMPRESSION_NONE;
        samplesPerPixel = 1;
    }
    
     /** Returns the file path. */
    public String getFilePath() {
        String dir = directory;
        if (dir==null)
            dir = "";
        dir = IJ.addSeparator(dir);
        return dir + fileName;
    }

   /** Returns the offset as a long. */
    public final long getOffset() {
        return longOffset>0L?longOffset:((long)offset)&0xffffffffL;
    }
    
    /** Returns the gap between images as a long. */
    public final long getGap() {
        return longGap>0L?longGap:((long)gapBetweenImages)&0xffffffffL;
    }

    /** Returns the number of bytes used per pixel. */
    public int getBytesPerPixel() {
        switch (fileType) {
            case GRAY8: case COLOR8: case BITMAP: return 1;
            case GRAY16_SIGNED: case GRAY16_UNSIGNED: case GRAY12_UNSIGNED: return 2;
            case GRAY32_INT: case GRAY32_UNSIGNED: case GRAY32_FLOAT: case ARGB: case GRAY24_UNSIGNED: case BARG: case ABGR: case CMYK: return 4;
            case RGB: case RGB_PLANAR: case BGR: return 3;
            case RGB48: case RGB48_PLANAR: return 6;
            case GRAY64_FLOAT : return 8;
            default: return 0;
        }
    }

    public String toString() {
        return
            "name=" + fileName
            + ", dir=" + directory
            + ", width=" + width
            + ", height=" + height
            + ", nImages=" + nImages
            + ", offset=" + getOffset()
            + ", gap=" + getGap()
            + ", type=" + getType()
            + ", byteOrder=" + (intelByteOrder?"little":"big")
            + ", format=" + fileFormat
            + ", url=" + url
            + ", whiteIsZero=" + (whiteIsZero?"t":"f")
            + ", lutSize=" + lutSize
            + ", comp=" + compression
            + ", ranges=" + (displayRanges!=null?""+displayRanges.length/2:"null")
            + ", samples=" + samplesPerPixel;
    }
    
    /** Returns JavaScript code that can be used to recreate this FileInfo. */
    public String getCode() {
        String code = "fi = new FileInfo();\n";
        String type = null;
        if (fileType==GRAY8)
            type = "GRAY8";
        else if (fileType==GRAY16_UNSIGNED)
            type = "GRAY16_UNSIGNED";
        else if (fileType==GRAY32_FLOAT)
            type = "GRAY32_FLOAT";
        else if (fileType==RGB)
            type = "RGB";
        if (type!=null)
            code += "fi.fileType = FileInfo."+type+";\n"; 
        code += "fi.width = "+width+";\n";
        code += "fi.height = "+height+";\n";
        if (nImages>1)
            code += "fi.nImages = "+nImages+";\n";      
        if (getOffset()>0)
            code += "fi.longOffset = "+getOffset()+";\n";   
        if (intelByteOrder)
            code += "fi.intelByteOrder = true;\n";      
        return code;
    }

    private String getType() {
        switch (fileType) {
            case GRAY8: return "byte";
            case GRAY16_SIGNED: return "short";
            case GRAY16_UNSIGNED: return "ushort";
            case GRAY32_INT: return "int";
            case GRAY32_UNSIGNED: return "uint";
            case GRAY32_FLOAT: return "float";
            case COLOR8: return "byte(lut)";
            case RGB: return "RGB";
            case RGB_PLANAR: return "RGB(p)";
            case RGB48: return "RGB48";
            case BITMAP: return "bitmap";
            case ARGB: return "ARGB";
            case ABGR: return "ABGR";
            case BGR: return "BGR";
            case BARG: return "BARG";
            case CMYK: return "CMYK";
            case GRAY64_FLOAT: return "double";
            case RGB48_PLANAR: return "RGB48(p)";
            default: return "";
        }
    }

    public synchronized Object clone() {
        try {return super.clone();}
        catch (CloneNotSupportedException e) {return null;}
    }

}