import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class MuPADConsole extends WindowAdapter implements WindowListener,  ActionListener, Runnable
{
private JFrame frame = new JFrame("MuPAD - Java Console");
private JTextArea textArea;
private Thread reader;
private Thread reader2;
private boolean quit;
private boolean toFile;

private final PipedInputStream pin=new PipedInputStream();
private final PipedInputStream pin2=new PipedInputStream();

public MuPADConsole(boolean writeInFile)
{
  // create all components and add them
  //frame = new JFrame("MuPAD - Java Console");
  toFile = writeInFile;
	Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
	Dimension frameSize=new Dimension((int)(screenSize.width/3),(int)(screenSize.height/3));
	int x=(int)(frameSize.width/4);
	int y=(int)(frameSize.height/3);
	frame.setBounds(x,y,frameSize.width,frameSize.height);

	textArea=new JTextArea();
	textArea.setEditable(true);
  textArea.setText(getJavaVersion());
	JButton button=new JButton("clear");

	frame.getContentPane().setLayout(new BorderLayout());
	frame.getContentPane().add(new JScrollPane(textArea),BorderLayout.CENTER);
	frame.getContentPane().add(button,BorderLayout.SOUTH);
	//frame.setVisible(true);

	frame.addWindowListener(this);
	button.addActionListener(this);


	try
	{
   PipedOutputStream pout=new PipedOutputStream(this.pin);
   if (toFile)
     System.setOut(new PrintStream(new FileOutputStream("MuPADout.log")));
	 else
	   System.setOut(new PrintStream(pout,true));

	}
	catch (java.io.IOException io)
	{
    if (!toFile)
		  textArea.append("Couldn't redirect STDOUT to this console\n"+io.getMessage());
	}
	catch (SecurityException se)
	{
    if (!toFile)
		  textArea.append("Couldn't redirect STDOUT to this console\n"+se.getMessage());
  }

	try
	{
		PipedOutputStream pout2=new PipedOutputStream(this.pin2);
		if (toFile)
      System.setErr(new PrintStream(new FileOutputStream("MuPADerr.log")));
    else
		  System.setErr(new PrintStream(pout2,true));

	}
	catch (java.io.IOException io)
	{
    if (!toFile)
      textArea.append("Couldn't redirect STDERR to this console\n"+io.getMessage());
	}
	catch (SecurityException se)
	{
    if (!toFile)
		  textArea.append("Couldn't redirect STDERR to this console\n"+se.getMessage());
	}

	quit=false; // signals the Threads that they should exit

	// For STDOUT
	reader=new Thread(this);
	reader.setDaemon(true);
	reader.start();

	// For STDERR
	reader2=new Thread(this);
	reader2.setDaemon(true);
	reader2.start();

	}

	public void showWindow() {
	  frame.setVisible(true);
	  frame.toFront();
  }

  public void killWindow() {
    frame.setVisible(false);
    this.notifyAll(); // stop all threads
    try { reader.join(1000);pin.close();   } catch (Exception e){}
    try { reader2.join(1000);pin2.close(); } catch (Exception e){}
    frame.dispose();
  }


	public synchronized void windowClosed(WindowEvent evt)
	{
		//quit=true;
		//this.notifyAll(); // stop all threads
		//try { reader.join(1000);pin.close();   } catch (Exception e){}
		//try { reader2.join(1000);pin2.close(); } catch (Exception e){}
		//System.exit(0);
    frame.setVisible(false); // default behaviour of JFrame
    //frame.dispose();

	}
	public synchronized void windowClosing(WindowEvent evt)
	{
		frame.setVisible(false); // default behaviour of JFrame
		//frame.dispose();
	}

	public synchronized void actionPerformed(ActionEvent evt)
	{
		textArea.setText(getJavaVersion());
	}

	private String getJavaVersion() {
    // For example : Sun Microsystems Inc.
    // System.getProperties().getProperty("java.vm.vendor");

    // For example : Java(TM) 2 Runtime Environment
    // System.getProperties().getProperty("java.runtime.name");

    // For example : 1.4.2-beta-b19
    // System.getProperties().getProperty("java.vm.version");

   return "Used Java Version:\n" +
          System.getProperties().getProperty("java.vm.vendor") + "\n" +
          System.getProperties().getProperty("java.runtime.name") + "\n" +
          System.getProperties().getProperty("java.vm.name") + "\n" +
          System.getProperties().getProperty("java.vm.version") + "\n" +
          "====================================================================\n";
  }

	public synchronized void run()
	{
		try
		{
			while (Thread.currentThread()==reader)
			{
				try {
				  this.wait(100);
				}
				catch(InterruptedException ie) {}
				if (pin.available()!=0)
				{
					String input=this.readLine(pin);
          if (!toFile)
					  textArea.append(input);
				}
				if (quit) return;
			}
			while (Thread.currentThread()==reader2)
			{
				try {
				  this.wait(100);
				}
				catch(InterruptedException ie) {}
				if (pin2.available()!=0)
				{
					String input=this.readLine(pin2);
          if (!toFile)
					  textArea.append(input);
				}
				if (quit) return;
			}
		} catch (Exception e)
		{
      if (!toFile) {
        textArea.append("\nMuPAD Console reports an Internal error.");
			  textArea.append("The error is: "+e);
			}
		}

	}

	public synchronized String readLine(PipedInputStream in) throws IOException
	{
		String input="";
		do
		{
			int available=in.available();
			if (available==0) break;
			byte b[]=new byte[available];
			in.read(b);
			input=input+new String(b,0,b.length);
		} while( !input.endsWith("\n") &&  !input.endsWith("\r\n") && !quit);
		return input;
	}

	public static void main(String[] arg)
	{
    new MuPADConsole(true);
	}
}
