package ip.gui.frames;


import futils.Futil;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import ip.gui.Timer;
import ip.gui.StreamSniffer;
import ip.gui.UByte;

public class OpenFrame extends SaveFrame {
    private boolean fileIsPPM = false;

    MenuItem openImage_mi = addMenuItem(getOpenMenu(), "[o]pen image...");
    MenuItem openPPM_mi = addMenuItem(getOpenMenu(), "open ppm...");
    MenuItem sniff_mi = addMenuItem(getOpenMenu(), "sniff...");
    MenuItem getAsShortgz_mi = addMenuItem(getOpenMenu(),
            "[z]openAsShortgz");
    MenuItem getShortImageZip_mi =
            addMenuItem(getOpenMenu(),
                    "getShortImageZip");

    public void actionPerformed(ActionEvent e) {

        if (match(e, getShortImageZip_mi)) {
            getShortImageZip();
            return;
        }

        if (match(e, getAsShortgz_mi)) {
            getAsShortgz();
            return;
        }
        if (match(e, openImage_mi)) {
            openImage();
            return;
        }
        if (match(e, sniff_mi)) {
            System.out.println("sniffer!");
            openAndSniffFile();
            return;
        }
        if (match(e, openPPM_mi)) {
            openPPM();
            return;
        }
        super.actionPerformed(e);

    }

    public OpenFrame(String title) {
        super(title);
    }

    public void getAsShortgz() {
        String fn = Futil.getReadFileName();
        if (fn == null) return;
        Timer t = new Timer();
        t.start();
        try {
            FileInputStream fis = new FileInputStream(fn);
            GZIPInputStream gis = new GZIPInputStream(fis);
            ObjectInputStream ois = new ObjectInputStream(gis);
            setR((short[][]) ois.readObject());
            setG((short[][]) ois.readObject());
            setB((short[][]) ois.readObject());
            ois.close();

        } catch (Exception e) {
            System.out.println("Open getAsShortgz Exception:" + e);
        }
        t.stop();
        t.print(" getAsShortgz in ");
        setImageWidth(getR().length);
        setImageHeight(getR()[0].length);
        setSize(getImageWidth(), getImageHeight());

        short2Image();
    }

    public void openImage() {
        String fn = Futil.getReadFileName();
        if (fn == null) return;
        File f = new File(fn);
        if (!f.exists()) return;
        setFileName(fn);
        InputStream is = null;
        try {
            is = new FileInputStream(fn);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        StreamSniffer ss = new StreamSniffer(is);
        int id = ss.classifyStream();
        switch (id) {
            case StreamSniffer.PPM:
                setFileName(fn);
                openPPM(fn);
                break;
            case StreamSniffer.PPM_RAWBITS:
                setFileName(fn);
                openPPM(fn);
                break;
            case StreamSniffer.GIF87a:
                openGif(fn);
                break;
            case StreamSniffer.GIF89a:
                openGif(fn);
                break;
            case StreamSniffer.JPEG:
                setImageResize(
                        Toolkit.getDefaultToolkit().getImage(
                                fn));
                setFileName(fn);

                break;
            case StreamSniffer.GZIP:
                openPPMgz(fn);
                break;
            case StreamSniffer.ZIP_ARCHIVE:
                getShortImageZip(fn);
                break;
            default:
                {
                    System.out.println("Can not open " + ss + " as image");
                }

        }
    }


    public void getShortImageZip() {
        String fn = Futil.getReadFileName();
        if (fn == null) return;
        getShortImageZip(fn);
    }

    public void getShortImageZip(String fn) {
        Timer t = new Timer();
        t.start();
        try {
            FileInputStream fis = new FileInputStream(fn);
            ZipInputStream zis = new ZipInputStream(fis);
            ZipEntry ze;
            ze = zis.getNextEntry();
            ObjectInputStream ois =
                    new ObjectInputStream(zis);
            setR((short[][])
                    ois.readObject());
            setG(getR());
            setB(getR());
            setImageWidth(getR().length);
            setImageHeight(getR()[0].length);
            setSize(getImageWidth(), getImageHeight());
            short2Image();
            ze = zis.getNextEntry();
            setG((short[][])
                    ois.readObject());
            ze = zis.getNextEntry();
            short2Image();
            setB((short[][])
                    ois.readObject());
            zis.close();

        } catch (Exception e) {
            System.out.println("Open getShortImageZip:" + e);
        }
        t.stop();
        t.print(" getShortObjectZip in ");
        short2Image();
    }

    public void getShortImageZip2(String fn) {
        Timer t = new Timer();
        t.start();
        try {
            FileInputStream fis = new FileInputStream(fn);
            ZipInputStream zis = new ZipInputStream(fis);
            DataInputStream dis = new DataInputStream(zis);
            ZipEntry ze;
            ze = zis.getNextEntry();
            readHeader(dis);
            readArray(getR(), dis);
            readArray(getG(), dis);
            readArray(getB(), dis);
            zis.close();

        } catch (Exception e) {
            System.out.println("Open getShortImageZip:" + e);
        }
        t.stop();
        t.print(" getShortImageZip in ");
        short2Image();
    }

    public void readArray(short a[][], DataInputStream dis)
            throws IOException {
        for (int x = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++)
                a[x][y] = dis.readShort();
    }

    public void readHeader(DataInputStream dis)
            throws IOException {
        int width1 = dis.readInt();
        setImageWidth(width1);
        int height1 = dis.read();
        setImageHeight(height1);
    }

    public static void main(String args[]) {
        OpenFrame f = new OpenFrame("OpenFrame");
        f.show();
    }

    public void openPPMgz(String fn) {
        setFileName(fn);
        Timer t = new Timer();
        try {
            t.start();
            readShortsGz(fn);
            setImageWidth(getR().length);
            setImageHeight(getR()[0].length);
            fileIsPPM = true;
            short2Image();
            t.print("Time to read and display the ppm");
        } catch (Exception e) {
            System.out.println("Read PPM Exception:" + e);
        }

    }

    public void openPPM(String fn) {
        Timer t = new Timer();
        try {
            t.start();
            readShorts(fn);
            setSize(getImageWidth(), getImageHeight());
            fileIsPPM = true;
            short2Image();
            t.print("Time to read and display the ppm");
        } catch (Exception e) {
            System.out.println("Read PPM Exception:" + e);
        }
        repaint();

    }

    private void readShorts(String fn) {
        Timer t = new Timer();
        t.start();
        InputStream in = null;
        try {
            in = new FileInputStream(fn);
        } catch (Exception e) {
            e.printStackTrace();
        }
        getShortImage(in);
        t.print("End ReadShorts");
    }

    private void readShortsGz(String fn) {
        Timer t = new Timer();
        t.start();
        GZIPInputStream in = null;

        try {
            in = new GZIPInputStream(
                    new FileInputStream(fn));
        } catch (Exception e) {
            e.printStackTrace();
        }
        getShortImageGz(in);
        t.print("End ReadShorts");
    }

    private static String getReadName(String prompt) {
        FileDialog fd = new
                FileDialog(new Frame(), prompt);
        fd.setVisible(true);
        fd.setVisible(false);
        String fn = fd.getFile();
        if (fd.getFile() == null) return null; //usr canceled
        return fn;
    }


    private void readHeader(InputStream in) throws IOException {
        char c1, c2;

        c1 = (char) readByte(in);
        c2 = (char) readByte(in);

        if (c1 != 'P') {
            throw new IOException("not a PPM file");
        }
        if (c2 != '6') {
            throw new IOException("not a PPM file");
        }

        int width1 = readInt(in);
        setImageWidth(width1);
        int height1 = readInt(in);
        setImageHeight(height1);
        System.out.println("ReadPPM:" + getImageWidth() + "x" + getImageHeight());

        // Read maximum value of each color, and ignore it.
        // In PPM_RAW we know r,g,b use full range (0-255).
        readInt(in);
    }

    private static int readInt(InputStream in)
            throws IOException {
        char c;
        int i;

        c = readNonwhiteChar(in);
        if ((c < '0') || (c > '9')) {
            throw new IOException(
                    "Invalid integer when reading PPM image file.");
        }

        i = 0;
        do {
            i = i * 10 + c - '0';
            c = readChar(in);
        } while ((c >= '0') && (c <= '9'));

        return (i);
    }

    private static int readByte(InputStream in)
            throws IOException {
        int b = in.read();

        // if end of file
        if (b == -1) {
            throw new EOFException();
        }
        return b;
    }

    private static char readNonwhiteChar(InputStream in)
            throws IOException {
        char c;

        do {
            c = readChar(in);
        } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));

        return c;
    }

    private static char readChar(InputStream in)
            throws IOException {
        char c;

        c = (char) readByte(in);
        if (c == '#') {
            do {
                c = (char) readByte(in);
            } while ((c != '\n') && (c != '\r'));
        }

        return c;
    }

    public void getShortImage(InputStream in) {
        Timer t = new Timer();
        try {
            readHeader(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        setR(new short[getImageWidth()][getImageHeight()]);
        setG(new short[getImageWidth()][getImageHeight()]);
        setB(new short[getImageWidth()][getImageHeight()]);
        byte buf[] = new byte[getImageWidth() * getImageHeight() * 3];
        int offset = 0;
        int count = buf.length;
        int n = 0;
        t.start();
        try {
            n = in.read(buf, offset, count);
        } catch (IOException e) {
            e.printStackTrace();
        }
        t.print("Read in " + n + " bytes");
        try {
            t.start();
            int j = 0;
            for (int col = 0; col < getImageHeight(); col++)
                for (int row = 0; row < getImageWidth(); row++) {
                    getR()[row][col] = UByte.us(buf[j++]);
                    getG()[row][col] = UByte.us(buf[j++]);
                    getB()[row][col] = UByte.us(buf[j++]);
                }
            t.print("r[row][col] = buf[j++]");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    private void getShortImageGz(GZIPInputStream in) {
        Timer t = new Timer();
        try {
            readHeader(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        setR(new short[getImageWidth()][getImageHeight()]);
        setG(new short[getImageWidth()][getImageHeight()]);
        setB(new short[getImageWidth()][getImageHeight()]);
        byte buf[] = new byte[getImageWidth() * getImageHeight() * 3];
        int len = 0;
        byte bufgz[] = new byte[1024];

        int n = 0;
        t.start();
        try {
            while ((len = in.read(bufgz)) > 0) {
                System.arraycopy(bufgz, 0, buf, n, len);
                n = n + len;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        t.print("Read in " + n + " bytes");
        try {
            t.start();
            int j = 0;
            for (int col = 0; col < getImageHeight(); col++)
                for (int row = 0; row < getImageWidth(); row++) {
                    getR()[row][col] = UByte.us(buf[j++]);
                    getG()[row][col] = UByte.us(buf[j++]);
                    getB()[row][col] = UByte.us(buf[j++]);
                }
            t.print("r[row][col] = buf[j++]");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public void openPPM() {
        String fn = Futil.getReadFileName();
        if (fn == null) return;
        File f = new File(fn);
        if (!f.exists()) return;
        setFileName(fn);
        openPPM(fn);
    }

    public StreamSniffer openAndSniffFile() {
        String fn = Futil.getReadFileName();
        InputStream is;
        if (fn == null) return null;
        try {
            is = new FileInputStream(fn);
        } catch (FileNotFoundException e) {
            return null;
        }
        StreamSniffer ss = new StreamSniffer(is);
        System.out.println("Hmm, this smells like a " + ss);
        System.out.println("The id is :" + ss.classifyStream());
        return ss;
    }

}