// (C)1999-2007 Aleksander Malinowski, Bradley University, Peoria, Illinois //
// olekmali at bradley dot edu   http://gdansk.bradley.edu/olekmali/        //
// The source code is released for free under GNU Public License            //

import java.util.GregorianCalendar;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.applet.Applet;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;

public class tbViewer extends Applet implements ActionListener, WindowListener {

    public static void main(String[] args) {
        Frame F=new Frame("WebCam Monitor");
        tbViewer C=new tbViewer();
        F.setSize(800, 600);
        F.setResizable(false);
        F.addWindowListener(C);
        F.add(C);
        C.init();
        C.start();
        F.setVisible(true);
    }

    // parameters (these values are discarded later)
    final String  imgLocDefault = "http://gdansk.bradley.edu/webcam/";

    // GUI
    tbImage WC;
    Button BUT;
    Label  LA1;
    Label  LA2;

    private int getIntParameter(String ParamName, int defVal) {
        try {
            return(Integer.parseInt(getParameter(ParamName),10));
        } catch (Exception e) {
            return(defVal);
        }
    }

    private String getStrParameter(String ParamName, String defVal) {
        try {
            String t=getParameter(ParamName);
            if (t==null) throw new Exception("missing applet parameter");
            return(t);
        } catch (Exception e) {
            return(defVal);
        }
    }

    public void init() {
        Panel ControlPanel = new Panel();
        ControlPanel.setLayout(new BorderLayout(1, 3));
        BUT=new Button("pause");
        BUT.addActionListener(this);
        LA1 = new Label("");
        LA2 = new Label("");
        ControlPanel.add("Center", LA1);
        ControlPanel.add("East",   BUT);

        // Image canvas
        WC=new tbImage(
                getStrParameter("image-location", imgLocDefault), 
                getIntParameter("image-refresh",  1000), 
                getIntParameter("image-w-scale",  1), 
                getIntParameter("image-h-scale",  1),
                LA1, LA2
            );

        setLayout(new BorderLayout());
        add("Center", WC);
        add("South", ControlPanel);
        setVisible(true);
    }

    public void start() {
        WC.start();

        // Transmitted image canvas
    }

    public void stop() {
        WC.stop();
    }

    private void pause() {
        WC.pause();
        BUT.setLabel("resume");
    }

    private void resume() {
        WC.resume();
        BUT.setLabel("pause");
    }


// INTERFACE ActionListener -------
    public void actionPerformed(ActionEvent e) {
        if (e.getSource()==BUT) {
            if (BUT.getLabel().equals("pause")) {
                pause();
            } else {
                resume();
            }
                        
        }
        else ;
    }

// INTERFACE WindowListener -------
    public void windowClosing(WindowEvent e)      { stop(); WC.stop(); System.exit(0); }
    public void windowClosed(WindowEvent e)       {  }
    public void windowOpened(WindowEvent e)       {  }
    public void windowIconified(WindowEvent e)    { pause();  }
    public void windowDeiconified(WindowEvent e)  { resume(); }
    public void windowActivated(WindowEvent e)    { resume(); }
    public void windowDeactivated(WindowEvent e)  { pause();  }
}









class tbImage extends Canvas implements Runnable, MouseListener, MouseMotionListener {
// WARNING: this double buffering is not set up
//          to handle canvas sesiving - disable it!

    // parameters
    private String  imgLoc;
    private int     tmSlMs;
    private int     Wscale = 1;
    private int     Hscale = 1;

    // variables
    private MediaTracker MT     = null;
    private Image   webimg      = null;
    private Image   bufimg      = null;
    private Thread  process     = null;
    private boolean pause       = false;
    private boolean rapid       = false;
    private Label   status      = null;
    private Label   label       = null;

    tbImage(String loc, int wait, int wsc, int hsc, Label stat, Label lab) {
        super();
        imgLoc=loc;
        tmSlMs=wait;
        Wscale=wsc;
        Hscale=hsc;
        status=stat;
        label =lab;
        MT=new MediaTracker(this);
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void start() {
        status.setText("starting");
        if (process!=null) return;
        process=new Thread(this,"Image Update");
        process.start();
        status.setText("started");
    }

    public void pause() {
        pause=true;
    }

    public void resume() {
        pause=false;
        process.interrupt();
    }

    public void stop() {
        status.setText("stop");
        if (process==null) return;
        Thread tokill=process;
        process=null;
        tokill.interrupt();
        try {
            tokill.join(100);
        } catch (Exception e) {
        }
        status.setText("stopped");
    }

    public void run() {
        while(Thread.currentThread()==process) {
            if (pause) {
                try {
                    Thread.currentThread().sleep(60000);
                    // can sleep long because resume interrupts this sleep
                } catch (Exception e) { }
            } else {
                try {
                    status.setText("preparing");
                    // remove the previous image from cache
                    if (webimg!=null) webimg.flush();
                    // get a new image by location
                    String strimg = imgLoc+"/"+GregorianCalendar.getInstance().getTimeInMillis()+".jpg";
                    webimg = getToolkit().getImage(new URL(strimg));
                    // wait for downloading the image
                    // -- extra time added to thread.sleep()
                    MT.addImage(webimg,0);
                    status.setText("get "+ strimg);
                    MT.waitForAll();
                    MT.removeImage(webimg,0);
                } catch(Exception e) {
                    webimg=null;
                }
                status.setText("display");
                RefreshAll();
                if (rapid) {
                    status.setText("rapid");
                } else {
                    status.setText("sleep");
                    try {
                        Thread.currentThread().sleep(tmSlMs);
                    } catch (Exception e) { }
                }
            }
        }
    }

    public void RefreshAll() {
        if (bufimg!=null) {
            DrawAll(bufimg.getGraphics());
            repaint();
        } else {
            DrawAll(this.getGraphics());
        }
    }

    public void DrawAll(Graphics g) {
        if (webimg!=null) {
            final Rectangle r=getBounds();
            int wi=Wscale*webimg.getWidth(this);
            int hi=Hscale*webimg.getHeight(this);
            int w1=(r.width -wi)/2;
            int h1=(r.height-hi)/2;
            int w2=w1+wi;
            int h2=h1+hi;
            g.clearRect(2, 2, r.width-3,h1-3);
            g.clearRect(2, h1,w1-3,hi);
            g.clearRect(w2,h1,w1-3,hi);
            g.clearRect(2,h2+1,r.width-3,h1-3);
            g.drawImage(webimg, w1, h1, wi, hi, this);
        }
    }

    public void paint(Graphics g) {
        if (bufimg!=null)
            g.drawImage(bufimg,0,0,this);
        else {
            // bufimg = createImage(getWidth(),getHeight()); // Works in Java2 from Sun only !!!
            bufimg = createImage(getSize().width,getSize().height); // inefficient but works since Java 1.1 and in non-Sun Java2
        }
   }

    public void update(Graphics g) {
        paint(g);
    }


    // INTERFACE MouseListener
    public void mouseClicked(MouseEvent e)        { Graphics g=this.getGraphics(); g.drawRect(e.getX(),e.getY(), 1,1); }
    public void mousePressed(MouseEvent e)        { rapid=true;  }
    public void mouseReleased(MouseEvent e)       { rapid=false; }
    public void mouseEntered(MouseEvent e)        {}
    public void mouseExited(MouseEvent e)         {}


    // INTERFACE MouseMotionListener
    public void mouseMoved(MouseEvent e)          {}
    public void mouseDragged(MouseEvent e)        {}

}