import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.net.*;
import com.sun.image.codec.jpeg.*;
import javax.swing.*;
import java.io.*;

class WebCamViewer extends WindowAdapter implements ImageObserver, Runnable {
    private URL url;
    private InputStream In;
    private byte[] Block;
    private int Offset, Length, Done;
    private byte[] Key = {
	(byte)'-', (byte)'-', (byte)'T', (byte)'h', (byte)'i', (byte)'s', (byte)'R', (byte)'a', (byte)'n', (byte)'d', (byte)'o', (byte)'m', (byte)'S',
	(byte)'t', (byte)'r', (byte)'i', (byte)'n', (byte)'g', (byte)'\n', (byte)'C', (byte)'o', (byte)'n', (byte)'t', (byte)'e', (byte)'n', (byte)'t',
	(byte)'-', (byte)'t', (byte)'y', (byte)'p', (byte)'e', (byte)':', (byte)' ', (byte)'i', (byte)'m', (byte)'a', (byte)'g', (byte)'e', (byte)'/',
	(byte)'j', (byte)'p', (byte)'e', (byte)'g', (byte)'\n', (byte)'\n'
    };
    private JFrame j;
    private URL u;
    private JComponent comp;

    WebCamViewer(String s) {
	URLConnection c;
	JLabel p;
	JPanel fish;
	
	Block = new byte[0];
	Offset = Length = 0;
	Done = Key.length;
	j = new JFrame("WebCamViewer");
	p = new JLabel();
 	p.setPreferredSize(new Dimension(320, 140));
	j.getContentPane().add(p);
 	j.pack();
	j.setVisible(true);
	j.addWindowListener(this);
	try {
	    url = new URL(s);
	} catch(MalformedURLException ex) {
	    ex.printStackTrace();
	    System.exit(1);
	}
	u = url;
	comp = p;
  	new Thread(this).start();
    }

    public void windowClosing(WindowEvent e) {
	System.exit(0);
    }

    public void run() {
	URLConnection c;
	JPEGImageDecoder j;
	BufferedImage i;
	Graphics g;
	
	g = comp.getGraphics();
	try {
	    In = u.openConnection().getInputStream();
	} catch(Exception ex) {
	    ex.printStackTrace();
	}
	while(true) {
	    j = JPEGCodec.createJPEGDecoder(getNextStream());
	    try {
		int lastx = 0, lasty = 0;
		
		i = j.decodeAsBufferedImage();
		if((lastx != i.getWidth()) || (lasty != i.getHeight())) {
		    lastx = i.getWidth();
		    lasty = i.getHeight();
		    comp.setPreferredSize(new Dimension(lastx, lasty));
		    this.j.pack();
		    g = comp.getGraphics();
		}
		g.drawImage(i, 0, 0, this);
	    } catch(Exception ex) {
		ex.printStackTrace();
	    }
	}
    }

    public boolean imageUpdate(Image i, int info, int x, int y, int w, int h) {
	System.err.println("imageUpdate( " + info + ", (" + x + ", " + y +
			   "), " + w + ", " + h + ")");
	return true;
    }
	    
    public static void main(String args[]) {
	if(args.length == 0) {
	    new WebCamViewer("http://fish.mpx.com.au:9192/");
	} else {
	    new WebCamViewer(args[0]);
	}
    }
    
    public ByteArrayInputStream getNextStream() {
	int bo, ko, io;
	byte[] newblock;
	int tmp, keyp, newp, oldp;
	
	while(true) {
	    while(Done < (Length - Key.length)) {
		if(Block[Done] == Key[0]) {
		    tmp = Done;
		    keyp = 0;
		    while((keyp < Key.length) && (Block[tmp++] == Key[keyp++]));
		    if(keyp == Key.length) {
			int offset, length;

			offset = Offset + Key.length;
			length = Done - offset;
			Offset = Done;
			Done += Key.length;
			return new ByteArrayInputStream(Block, offset, length);
		    }
 		}
		Done++;
	    }
	    if((Block.length - Length) < 32000) {
		newblock = new byte[Block.length + 64000];
		newp = 0;
		oldp = Offset;
		while(oldp < Length)
		    newblock[newp++] = Block[oldp++];
		Length -= Offset;
		Done -= Offset;
		Offset = 0;
		Block = newblock;
	    }
	    try {
		io = In.read(Block, Length, Block.length - Length);
	    } catch(IOException ex) {
		ex.printStackTrace();
		return null;
	    }
	    if(io < 0)
		return null;
	    Length += io;
	}
    }
}
