/******************************************************************************
This is the basic applet suitable for image understanding demo.

There are two methods could be override to provide the information about
which method could be demoed, and which images could be used for demo,
respectively.

String[] getMethodNames()
String[] getImageNames()

The default implementation of these two methods is reading the information from
two files, methods.ini and images.ini, respectivly.

You can change the content of these two files, but for applet, it can't read
files, so it is better to add those methods and images in a overriding method

******************************************************************************/
package yi.iu.ui;

/*
	A basic extension of the java.applet.Applet class
 */

import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.applet.*;
import java.beans.*;
import java.io.*;
import symantec.itools.multimedia.ImageViewer;
import yi.util.io.ReadArgu;
import yi.iu.processor.ImageProcessor;
import Acme.JPM.Decoders.*;
import yi.util.config.*;

public class IUDemoApplet extends Applet
{
	private Image origImage;
	private Image processedImage;
	private int origPixels[];
	private int processedPixels[]=null;
	private int width, height;
	private int processedWidth, processedHeight;

        /**
         * Define whether open a new window to display the result
         */
        protected boolean open_new_window = false;

	//read file methods.ini to initialize the available method
	public String[] getMethodNames() {
	    //return ReadArgu.readStrings("methods.ini");
	    return null;
	}
	// read file images.ini to initialize the available image
	public String[] getImageNames() {
	    //return ReadArgu.readStrings("images.ini");
	    return null;
	}

	public void init()
	{
		// Take out this line if you don't use symantec.itools.net.RelativeURL or symantec.itools.awt.util.StatusScroller
		symantec.itools.lang.Context.setApplet(this);

		// This code is automatically generated by Visual Cafe when you add
		// components to the visual environment. It instantiates and initializes
		// the components. To modify the code, only use code syntax that matches
		// what Visual Cafe can generate, or Visual Cafe may be unable to back
		// parse your Java file into its visual environment.
		//{{INIT_CONTROLS
		setLayout(null);
		setSize(956,354);
		leftImagePanel.setLayout(null);
		add(leftImagePanel);
		leftImagePanel.setBounds(12,48,378,252);
		leftImagePanel.add(origImageViewer);
		origImageViewer.setBounds(0,0,378,252);
		processButton.setLabel("process>>");
		add(processButton);
		processButton.setBackground(java.awt.Color.lightGray);
		processButton.setBounds(816,12,80,24);
		rightImagePanel.setLayout(null);
		add(rightImagePanel);
		rightImagePanel.setBounds(564,48,378,252);
		try {
			procImageViewer.setStyle(symantec.itools.multimedia.ImageViewer.IMAGE_SCALED_TO_FIT);
		}
		catch(java.beans.PropertyVetoException e) { }
		rightImagePanel.add(procImageViewer);
		procImageViewer.setBounds(0,0,378,252);
		add(methodChoice);
		methodChoice.setBounds(552,12,192,25);
		label1.setText("2. Select a processor:");
		add(label1);
		label1.setFont(new Font("Dialog", Font.BOLD, 12));
		label1.setBounds(420,12,125,24);
		add(imageChoice);
		imageChoice.setBounds(128,12,280,24);
		label2.setText("1. Select an image:");
		add(label2);
		label2.setFont(new Font("Dialog", Font.BOLD, 12));
		label2.setBounds(12,12,110,24);
		statusLabel.setText("Welcome to Yi\'s world !");
		statusLabel.setAlignment(java.awt.Label.CENTER);
		add(statusLabel);
		statusLabel.setBounds(336,312,273,24);
		add(informationLabel);
		informationLabel.setBounds(12,312,84,24);
		add(ldetailLabel);
		ldetailLabel.setBounds(120,312,180,24);
		add(rdetailLabel);
		rdetailLabel.setBounds(696,312,180,24);
		label3.setText("3. Click");
		add(label3);
		label3.setFont(new Font("Dialog", Font.BOLD, 12));
		label3.setBounds(756,12,48,24);
		argumentPanel.setLayout(null);
		add(argumentPanel);
		argumentPanel.setBounds(396,48,162,252);
		label4.setText("Options:");
		argumentPanel.add(label4);
		label4.setBounds(48,0,72,24);
		//}}

		// read file methods.ini to initialize the available method
		setMethodChoice();
		// read file images.ini to initialize the available image
		setImageChoice();
		// set the correct argument information
		java.awt.event.ItemEvent event=null;
	    methodChoice_ItemStateChanged(event);


		//{{REGISTER_LISTENERS
		SymMouse aSymMouse = new SymMouse();
		processButton.addMouseListener(aSymMouse);
		SymItem lSymItem = new SymItem();
		methodChoice.addItemListener(lSymItem);
		imageChoice.addItemListener(lSymItem);
		SymMouseMotion aSymMouseMotion = new SymMouseMotion();
		origImageViewer.addMouseMotionListener(aSymMouseMotion);
		rdetailLabel.addMouseMotionListener(aSymMouseMotion);
		procImageViewer.addMouseMotionListener(aSymMouseMotion);
		//}}

		java.awt.event.ItemEvent e=null;
		imageChoice_ItemStateChanged(e);
	}

	void setMethodChoice()
	{
	    String methods[]= getMethodNames();
	    if (methods==null) return;
	    if (methods.length==0) return;
		for (int i=0;i<methods.length;i++)
		    methodChoice.addItem(methods[i]);
	}

	void setImageChoice()
	{
	    String images[]= getImageNames();
		if (images==null) return;
	    if (images.length==0) return;
		for (int i=0;i<images.length;i++)
		    imageChoice.addItem(images[i]);
	}

	//{{DECLARE_CONTROLS
	java.awt.Panel leftImagePanel = new java.awt.Panel();
	symantec.itools.multimedia.ImageViewer origImageViewer = new symantec.itools.multimedia.ImageViewer();
	java.awt.Button processButton = new java.awt.Button();
	java.awt.Panel rightImagePanel = new java.awt.Panel();
	symantec.itools.multimedia.ImageViewer procImageViewer = new symantec.itools.multimedia.ImageViewer();
	java.awt.Choice methodChoice = new java.awt.Choice();
	java.awt.Label label1 = new java.awt.Label();
	java.awt.Choice imageChoice = new java.awt.Choice();
	java.awt.Label label2 = new java.awt.Label();
	java.awt.Label statusLabel = new java.awt.Label();
	java.awt.Label informationLabel = new java.awt.Label();
	java.awt.Label ldetailLabel = new java.awt.Label();
	java.awt.Label rdetailLabel = new java.awt.Label();
	java.awt.Label label3 = new java.awt.Label();
	java.awt.Panel argumentPanel = new java.awt.Panel();
	java.awt.Label label4 = new java.awt.Label();
	//}}
	java.awt.TextField arguTextFields[] = null;
	java.awt.Label arguLabels[] = null;

	void readOrigPixels()
	{
	    PixelGrabber pg = new PixelGrabber(origImage,0,0,-1,-1,true);
	    boolean result=false;
	    try {
	        result = pg.grabPixels();
	    }
	    catch (InterruptedException e) {
	        System.err.println("Interrupted pixel grabbing!");
	        e.printStackTrace();
	    }

	    if (result==false) {
	        System.err.println("Couldn't Grab the Pixels!");
		    statusLabel.setText("Couldn't Grab the Pixels!");
		    origPixels=null;
		    return;
	    }

	    origPixels= (int[]) pg.getPixels();
	    width = pg.getWidth();
	    height = pg.getHeight();
	    pg = null;
	    System.gc();
	}

	void paintProcessedImage()
	{
	    try {
		    //procImageViewer.setStyle(ImageViewer.IMAGE_SCALED_TO_FIT);
		    procImageViewer.setImage(processedImage);
		}
		catch (PropertyVetoException e) {
		    System.err.println("can't set image to viewer!");
		}
		procImageViewer.repaint();

	}

	class SymMouse extends java.awt.event.MouseAdapter
	{
		public void mousePressed(java.awt.event.MouseEvent event)
		{
			Object object = event.getSource();
			if (object == processButton)
				processButton_MousePressed(event);
		}
	}

	public String[] getPackageNames() {
	    String[] ss={"yi.iu.processor"};
	    return ss;
	}

	ImageProcessor getProcessor()
	{
		String methodName= methodChoice.getSelectedItem();
		//find the first part of the name (seperated by space)
		int space= methodName.indexOf(" ");
		if (space!=-1) methodName= methodName.substring(0,space);

		// try to find the method according to it's name in the current directory
		ImageProcessor ip=null;
	    try {
	        Class ipc= Class.forName(methodName);
	        ip= (ImageProcessor)ipc.newInstance();
	    } catch (Exception e) {
	    }
	    if (ip!=null) return ip;

	    String[] package_names=getPackageNames();
	    for (int i=0;i<package_names.length;i++) {
	        // try to find the method according to it's name in the lib directory
	        try {
	            Class ipc= Class.forName(package_names[i]+"."+methodName);
	            ip= (ImageProcessor)ipc.newInstance();
	            return ip;

	        } catch (Exception e) {
	            //System.err.println("not found the procssor in "+package_names[i]);
	        }
	    }

	    System.err.println("Can't find that image processor!");
	    return null;
	}

	//set the arguments of the image processor according to the set of user
	void setArguments(ImageProcessor ip) {
	    int arguNum= ip.getArguNum();
	    if (arguNum==0) return;
	    for (int i=0;i<arguNum;i++) {
	        String value= arguTextFields[i].getText();
            ip.setArgument(i,value);
	    }

	}

	//get the default argument settings, and display them on the screen
	void getArguments(ImageProcessor ip) {
        int arguNum= ip.getArguNum();
        argumentPanel.removeAll();
        argumentPanel.add(label4);
        if (arguNum<=0) {argumentPanel.repaint(); return;}

        arguTextFields= new java.awt.TextField[arguNum];
	    arguLabels = new java.awt.Label[arguNum];

        for (int i=0;i<arguNum;i++) {
	        arguLabels[i]= new java.awt.Label(ip.getArguName(i));
	        arguLabels[i].setBounds(12,36+30*i,80,24);
	        arguLabels[i].setAlignment(java.awt.Label.RIGHT);
	        argumentPanel.add(arguLabels[i]);

	        arguTextFields[i]= new TextField(ip.getArgument(i));
	        arguTextFields[i].setBounds(100,36+30*i,60,24);
	        argumentPanel.add(arguTextFields[i]);
	    }
	    argumentPanel.repaint();
	}

	void processButton_MousePressed(java.awt.event.MouseEvent event)
	{
		//get the processor
		ImageProcessor ip= getProcessor();
		if (ip==null) {
		    statusLabel.setText("Can't find that image processor!");
		    return;
		}
		//set the arguments
		setArguments(ip);
		String methodName= methodChoice.getSelectedItem();
		statusLabel.setText(methodName+ " is running ...");

	    //running & display the result
	    Dimension d= new Dimension(width,height);
	    processedPixels= ip.getProcessedPseudoColor(origPixels, d);
	    processedWidth= d.width;
	    processedHeight= d.height;
            if (open_new_window) {
              DisplayFrame f= new DisplayFrame("final result", processedPixels, d.width, d.height);
              f.show();

            }
	    processedImage = createImage(
	        new MemoryImageSource(processedWidth,processedHeight,
	            processedPixels, 0, processedWidth));
	    paintProcessedImage();
	    statusLabel.setText("Process done !");
	    ip=null;
	    System.gc();
	}

	class SymItem implements java.awt.event.ItemListener
	{
		public void itemStateChanged(java.awt.event.ItemEvent event)
		{
			Object object = event.getSource();
			if (object == methodChoice)
				methodChoice_ItemStateChanged(event);
			else if (object == imageChoice)
				imageChoice_ItemStateChanged(event);
		}
	}

	void methodChoice_ItemStateChanged(java.awt.event.ItemEvent event)
	{
		ImageProcessor ip= getProcessor();
		if (ip==null) {
		    statusLabel.setText("Can't find that image processor!");
		    return;
		}
		//get the arguments
		getArguments(ip);
	}

	void imageChoice_ItemStateChanged(java.awt.event.ItemEvent event)
	{
		String imageName= imageChoice.getSelectedItem();
                Configuration.setParameter("SOURCE_NAME", imageName);

		if (imageName.endsWith(".ppm")) {
		    try {
		        DataInputStream in= new DataInputStream(new FileInputStream(imageName));
		        PpmDecoder ppmd= new PpmDecoder(in);
		        Toolkit tk= Toolkit.getDefaultToolkit();
		        origImage= tk.createImage(ppmd);

		    }
		    catch (Exception e) {
		        System.err.println("read ppm error!"+e);
		    }
		}
		else {
		    origImage= getImage(getDocumentBase(), imageName);
		}
		statusLabel.setText("Loading image: "+imageName+ " ...");
		try {
		    origImageViewer.setStyle(ImageViewer.IMAGE_SCALED_TO_FIT);
		    origImageViewer.setImage(origImage);
		}
		catch (PropertyVetoException e) {
		    System.err.println("can't set image to viewer!");
		}
		origImageViewer.repaint();
		readOrigPixels();

		if (origPixels!=null) {
		    statusLabel.setText("Image Loaded!");
		    informationLabel.setText(width+"*"+height );
		}
	}

	public void paint(Graphics g) {
	    Rectangle r=leftImagePanel.getBounds();
	    g.drawRect(r.x-1,r.y-1,r.width+1,r.height+1);
	    r=rightImagePanel.getBounds();
	    g.drawRect(r.x-1,r.y-1,r.width+1,r.height+1);
	}

	class SymMouseMotion extends java.awt.event.MouseMotionAdapter
	{
		public void mouseMoved(java.awt.event.MouseEvent event)
		{
			Object object = event.getSource();
			if (object == origImageViewer)
				origImageViewer_mouseMoved(event);
			else if (object == procImageViewer)
				procImageViewer_mouseMoved(event);
		}
	}

	void origImageViewer_mouseMoved(java.awt.event.MouseEvent event)
	{
		int x= event.getX(),y=event.getY();
		Dimension d= origImageViewer.getSize();
		int vw= d.width, vh= d.height;
		x= (int)((double)x/vw*width);
		y= (int)((double)y/vh*height);
		if (x>=width) x=width-1;
		if (y>=height) y=height-1;
		int rgb= origPixels[y*width+x];
		int r=rgb>>16&255,g=rgb>>8&255,b=rgb&255;
		ldetailLabel.setText("("+x+","+y+"): "+"RGB("+r+","+g+","+b+")");
	}

	void procImageViewer_mouseMoved(java.awt.event.MouseEvent event)
	{
		if (processedPixels==null) return;
		int x= event.getX(),y=event.getY();
		Dimension d= procImageViewer.getSize();
		int vw= d.width, vh= d.height;
		x= (int)((double)x/vw*processedWidth);
		y= (int)((double)y/vh*processedHeight);
		if (x>=processedWidth) x=processedWidth-1;
		if (y>=processedHeight) y=processedHeight-1;
		int rgb= processedPixels[y*processedWidth+x];
		int r=rgb>>16&255,g=rgb>>8&255,b=rgb&255;
		rdetailLabel.setText("("+x+","+y+"): "+"RGB("+r+","+g+","+b+")");
	}
}
