/**
 *Class opens a QuickTime image stream using QuickTime for Java methods.
 *Class presents the stream on screen in a java.awt.Frame and 
 *provides access to the image stream through grabFrame().
 *
 *This class is modified from Wayne Rasband's QT_Capture.java available from
 *<a href="http://rsb.info.nih.gov/ij/plugins/index.html">ImageJ Plugins</a>
 *<p><a href="http://developer.apple.com/quicktime/qtjava/">QuickTime for
 *Java</a>. <p> <a href="http://developer.apple.com/documentation/Java/Reference/1.3.1/Java131API_QTJ/">QT for Java Javadoc</a>
 *<p> This code must use QuickTime Java versions below 6.0 becuase the 
 *SequenceGrabber and QTCanvas were deprecated
 *in 6.0 and above without an equivalent replacement.
 *It also requires Java 1.3.1.
 *<p>Note: The image update in the window stops when frame grabbing begins.
 *@version 1.0
 */
import ij.*;
import ij.plugin.PlugIn;
import ij.text.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;

import quicktime.qd.*;
import quicktime.*;
import quicktime.util.*;
import quicktime.io.*;
import quicktime.std.StdQTConstants;
import quicktime.std.sg.*;
import quicktime.app.sg.SGDrawer;
import quicktime.std.movies.*;
import quicktime.std.movies.media.UserData;
import quicktime.app.display.QTCanvas;
import quicktime.app.image.QTImageProducer;
import quicktime.app.image.ImagePresenter;

public class MQTCapture extends Frame implements StdQTConstants, ActionListener, 
                            WindowListener {
 
    private int                 kWidth;
    private int                 kHeight;
    private QTCanvas            myQTCanvas;
    private SGVideoChannel      mVideo;
    private SGDrawer            mDrawable;
    private SequenceGrabber     mGrabber;
    private QTFile              mFile;
    private Movie               mMovie;
    private Carousel_Imaging    thePlugIn;
    private Button              cancelButton, startButton, cancelGrabButton;
    private ImageProducer       imgProducer;
    private Pict                pict;
    private ImagePresenter      imgPresenter;
    private int                 grabIndex, repeatIndex=0;
    private SequenceGrabber     GrabGrabber;
    private boolean             DEBUG;      //create a text area in the Frame
    private TextArea            textArea;   //text area created when DEBUG=true;
    
    /**
     *Opens QT Java stream and opens a java.awt.Frame.
     *@param title window title
     *@param the calling class. The actionListener() method calls 
     *methods thePlugIn in the calling class.
     *
     */
    public MQTCapture (String title, Carousel_Imaging thePlugIn) {
        super (title);
        this.thePlugIn = thePlugIn;
        DEBUG = true;
        try {
            QTSession.open();       
            mGrabber = new SequenceGrabber();
            mVideo = new SGVideoChannel(mGrabber);
            QDRect bounds = mVideo.getSrcVideoBounds();
            if (IJ.altKeyDown()) {
                kWidth = bounds.getWidth()/2; kHeight = bounds.getHeight()/2;
                myQTCanvas = new QTCanvas(QTCanvas.kPerformanceResize, 0.5f, 0.5f);
            } else {
                kWidth = bounds.getWidth(); kHeight = bounds.getHeight();
                myQTCanvas = new QTCanvas(QTCanvas.kPerformanceResize, 1f, 1f);
            }
            Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
            if (kHeight>(screen.height-40)) { // iSight camera claims to 1600x1200!
                kWidth =640;
                kHeight = 480;
            }
            kWidth =640;
            kHeight = 480;
            myQTCanvas.setMaximumSize (new Dimension (bounds.getWidth(), bounds.getHeight()));
            myQTCanvas.setPreferredSize (new Dimension (kWidth, kHeight));
            myQTCanvas.setSize (new Dimension (kWidth, kHeight));

            setLayout (new BorderLayout());
            add ("Center", myQTCanvas); 

            Panel buttons = new Panel();
                cancelButton = new Button(" Cancel Plugin ");
                buttons.add(cancelButton);
                cancelButton.addActionListener(this);
                startButton = new Button (" Start Grab ");
                cancelGrabButton = new Button (" Cancel Grab ");
                buttons.add(cancelGrabButton);
                cancelGrabButton.addActionListener(this);
                buttons.add(startButton);
                startButton.addActionListener(this);
                add("South", buttons);
                addWindowListener(this);
            if (DEBUG) {
                Panel p = new Panel();
                    textArea = new TextArea("Messages\n", 10, 60);
                    p.add(textArea);
                add("North", p);
            }
            //thePlugIn.finishSetUp();
        } catch (QTException e) {
            int errorCode = e.errorCode();
            String s = null;
            if (errorCode == -9405){
                s = "Is ADVC-100 swtiched on?\nShould be a blue light indicating power is on.\nQuit ImageJ and try again.\nIgnore all other errors.";
            } else {
                s = "Problem establishing the Image Stream from the camera.\nCheck all connections and make sure all components have power.\nQuit and restart ImageJ.\nIf this problem persists restart the computer.";
            }
        new TextWindow("Image Stream Error", s, 400, 300);  
        }
        IJ.register(MQTCapture.class);
        //thePlugIn.finishSetUp();
    } //closes constructor
    /**
     *Handles the action events by calling methods in thePlugIn.
     */
    public void actionPerformed (ActionEvent event) {
        if (event.getSource () == startButton) {
            thePlugIn.tap();
        }
        else if (event.getSource()==cancelButton) {
            thePlugIn.close();
        }
        else {
            thePlugIn.close();
        }
    }
    /**
     *Places a message in the textarea. Useful for debuging other parts of the 
     *program.
     *@param the message to report.
     */
    public void reportMessage(String message) {
        if(DEBUG) {
            textArea.append(message);
        }
    }
    
    /**
     *Called by the windowListener().
     */
    //from QT_Capture Wayne Rasband
    public void windowOpened(WindowEvent e) {
        try{
            mVideo.setBounds (new QDRect(kWidth, kHeight));
            mVideo.setUsage (seqGrabPreview); // seqGrabRecord
            //mVideo.setPlayFlags(channelPlayHighQuality);
            mDrawable = new SGDrawer(mVideo);           
            myQTCanvas.setClient(mDrawable,true);           
            mGrabber.prepare(true,true);
            mGrabber.startPreview();
            if (DEBUG) {textArea.append("QuickTime started just fine.\n");}
        } catch (Exception ee) {
            printStackTrace(ee);
            //shutDown();
        }
    } //windowOpened
    /**
     *Places a message in the textarea. Useful for debuging other parts of the 
     *program.
     *@param message the message to report.
     */
    public void addMessage(String message) {
    
        textArea.append(message + "\n");
    }
    void printStackTrace(Exception e) {
        CharArrayWriter caw = new CharArrayWriter();
        PrintWriter pw = new PrintWriter(caw);
        e.printStackTrace(pw);
        String s = caw.toString();
        //addMessage(s);
        new TextWindow("Exception", s, 400, 300);
    }
    
    /**
     *Takes an image from the image stream and returns it.
     *@return java.awt.image.Image if successful. 
     */
    public Image grabFrame() {
        Image img = null;
        try {
            pict = mGrabber.grabPict(new QDRect(kWidth, kHeight), 0, grabPictOffScreen);
            imgPresenter = ImagePresenter.fromPict(pict);
            QDRect rect = imgPresenter.getDisplayBounds();
            Dimension d = new Dimension(rect.getWidth(), rect.getHeight());
            imgProducer = new QTImageProducer (imgPresenter, d);
            img = createImage (imgProducer);
            //if (DEBUG) {textArea.append ("grabFrame(): "+ grabIndex +"\n");}
            grabIndex++;
        } catch (QTException qte) {qte.printStackTrace();}
        return img;
    } //closes grabFrame()
    /**
     *Called by plugin class to release the QuickTime stream. Doesn't work \
     *correctly.
     */
    public void shutDown() { //shuts down the QT resources and timer
        myQTCanvas.removeClient();
        QTSession.close();
        setVisible(false);
        dispose();
    }
    /**
     *Get a reference to the plugin.
     */
    public Carousel_Imaging getThePlugIn() {
        return thePlugIn;
    }
    //ignore all the other window action events.
    public void windowIconified (WindowEvent e) {}
    public void windowClosing (WindowEvent e) {
        shutDown ();}
    public void windowClosed (WindowEvent e) {
        shutDown ();}
    public void windowDeiconified (WindowEvent e) {}
    public void windowActivated (WindowEvent e) {}
    public void windowDeactivated (WindowEvent e) {}
} // closes MQTCapture class