/* Autor:           Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm
   Firma:           HS Harz, FB AI
   Version:         1.1
   Ersterstellung:  09.11.2010
   Letzte Änderung: 09.11.2010
   Beispiel fuer die Verwendung von zwei Pipes
   Hier stuertzt das Programm ab, da der AWT-Thread bei der Aenderung dazwischen funkt
   Abhilfe: invokeLate, siehe Pipe_01
*/


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;  // Exception





import java.io.*;

public class Pipe_02 extends JFrame {
  JButton BnBsp1 = new JButton("Bsp1 ohne Pause");
  JButton BnBsp2 = new JButton("Bsp2 Writer langsam");
  JButton BnBsp3 = new JButton("Bsp3 Reader langsam");
  JButton BnEsc = new JButton("Abbruch");
  JCheckBox chkWithJoin = new JCheckBox("Mit Warten");

  private JTextArea jtextareaL;
  private JTextArea jtextareaR;

   // Konstruktor
  public Pipe_02() {
    this.setSize(new Dimension(800, 400));
    setTitle("Pipe Beispiel ohne InvokeLater");
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    setGUI();
  }

  public void setGUI() {
    BnBsp1.setFont( new Font("Arial", Font.BOLD,18)  );
    BnBsp2.setFont( new Font("Arial", Font.BOLD,18)  );
    BnBsp3.setFont( new Font("Arial", Font.BOLD,18)  );
    BnEsc.setFont( new Font("Arial", Font.BOLD,18)  );
    chkWithJoin.setFont( new Font("Arial", Font.BOLD,22)  );

    this.getContentPane().setLayout( new BorderLayout() );
    jtextareaL = new JTextArea("1. Thread\n");
    jtextareaR = new JTextArea("2. Thread\n");
    jtextareaL.setFont( new Font("Arial", Font.BOLD,18)  );
    jtextareaR.setFont( new Font("Arial", Font.BOLD,18)  );

    JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,false,
      new JScrollPane(jtextareaL) , new JScrollPane(jtextareaR));
    split.setDividerLocation(400);
    this.getContentPane().add(split, BorderLayout.CENTER);

	JPanel pnButtonTop = new JPanel();
	pnButtonTop.setLayout( new FlowLayout() );
	pnButtonTop.add(chkWithJoin);
      this.getContentPane().add(pnButtonTop, BorderLayout.NORTH);

	JPanel pnButton = new JPanel();
	//pnButton.setBackground(Color.red);
	pnButton.setLayout( new FlowLayout() );
	pnButton.add(BnBsp1);
	pnButton.add(BnBsp2);
	pnButton.add(BnBsp3);
	pnButton.add(BnEsc);
      this.getContentPane().add(pnButton, BorderLayout.SOUTH);

      BnBsp1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
              BnBsp1_Click();
            }
      });
      BnBsp2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
              BnBsp2_Click();
            }
      });
      BnBsp3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
              BnBsp3_Click();
            }
      });


       BnEsc.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
              BnEsc_Click();
            }
       });
  }  // setGUI


  private void BnBsp1_Click() {
    WriteThread thread1;
    ReadThread thread2;
    thread1 = new WriteThread(jtextareaL, 100, 0);
    thread2 = new ReadThread(jtextareaR, 100, 0);
    thread1.connect( thread2.getPipe() );    
    jtextareaL.setText("1. Beispiel\n");
    jtextareaR.setText("1. Beispiel\n");
    thread1.start();
    thread2.start();
     // wenn mit Join kommen die Updates erst spaeter, dann kein Absturz
    if ( chkWithJoin.isSelected() ) {
      try {
        thread1.join();
        thread2.join();
      }
      catch (InterruptedException e) {
      }
      thread1.closePipes();  // muessen NACH dem Join beendet werden, sonst kann eine Pipe schon zu sein
      thread2.closePipes();
    }
  }  // BnBsp1

  private void BnBsp2_Click() {
    WriteThread thread1;
    ReadThread thread2;
    thread1 = new WriteThread(jtextareaL,100, 1);
    thread2 = new ReadThread(jtextareaR, 100, 100);
    thread1.connect( thread2.getPipe() );    
    jtextareaL.setText("2. Beispiel\n");
    jtextareaR.setText("2. Beispiel\n");
    thread1.start();
    thread2.start();
     // wenn mit Join kommen die Updates erst spaeter, dann kein Absturz
    if ( chkWithJoin.isSelected() ) {
      try {
        thread1.join();
        thread2.join();
      }
      catch (InterruptedException e) {
      }
      thread1.closePipes();  // muessen NACH dem Join beendet werden, sonst kann eine Pipe schon zu sein
      thread2.closePipes();
    }
  }  // BnBsp2

  private void BnBsp3_Click() {
    WriteThread thread1;
    ReadThread thread2;
    thread1 = new WriteThread(jtextareaL, 100, 100);
    thread2 = new ReadThread(jtextareaR, 100, 1);
    thread1.connect( thread2.getPipe() );    
    jtextareaL.setText("3. Beispiel\n");
    jtextareaR.setText("3. Beispiel\n");
    thread1.start();
    thread2.start();
     // wenn mit Join kommen die Updates erst spaeter, dann kein Absturz
    if ( chkWithJoin.isSelected() ) {
      try {
        thread1.join();
        thread2.join();
      }
      catch (InterruptedException e) {
      }
      thread1.closePipes();  // muessen NACH dem Join beendet werden, sonst kann eine Pipe schon zu sein
      thread2.closePipes();
    }
  }  // BnBsp3

  private void BnEsc_Click() {
     System.exit(0);  
  }

  static public void main(String[] args) {
    Pipe_02 frame = new Pipe_02();
    frame.setVisible(true);
  }

}  // Pipe_02



class ReadThread extends Thread {
 private PipedInputStream _pipein;
 private DataInputStream _din;   
 private int _n;
 private JTextArea _editor;
 private int _pause;

 public ReadThread(JTextArea editor, int n, int pause){ 
   _editor = editor;
   _n = n;  // Anzahl der Datensaetze
   _pause = pause;
   _pipein = new PipedInputStream();             // Stream Objekt zum Lesen
  _din = new DataInputStream(_pipein);
 };                             


 public PipedInputStream getPipe() {
   return _pipein;
 }

  // muss extra am Ende, nach dem JOIN aufgerufen werden, sonst ist die Pipe geschlossen
  // fuer den anderen Thread
 public void closePipes() {
  try {
    _pipein.close();
    _din.close();
  }
  catch (IOException e) {
         System.err.println("IOException: " + e);
  }
 }

 public void delay(int pause) {
    try {
           Thread.sleep(pause);
        } catch (InterruptedException e) {
    }
  }  // delay

 public void run(){
  int i;
  double dValue;
   String  s=_editor.getText();
  try {
    for (i=0; i<_n; i++) {
      dValue = _din.readDouble();
      // _editor.append(" i: "+(i+1)+"    Wert: "+dValue+"\n");
      System.out.println(" Reader:    i: "+(i+1)+"    Wert: "+dValue);
      s+=" i: "+(i+1)+"    Wert: "+dValue+"\n";
      _editor.setText(s);
      _editor.updateUI();
      _editor.invalidate();
      if (_pause>0) delay(_pause);
      delay(10);
    }
  }
  catch (IOException e) {
     System.err.println("IOException: " + e);
  }
 } // run

}  // readThread



class WriteThread extends Thread {
 private PipedOutputStream _pipeout;
 private DataOutputStream _dout;   
 private int _n;
 private JTextArea _editor;
 private int _pause;

 public WriteThread(JTextArea editor, int n, int pause){ 
   _editor = editor;
   _n = n;  // Anzahl der Datensaetze
   _pause = pause;
   _pipeout = new PipedOutputStream();             // Stream Objekt zum Lesen
  _dout = new DataOutputStream(_pipeout);  
 };         


  // muss extra am Ende, nach dem JOIN aufgerufen werden, sonst ist die Pipe geschlossen
  // fuer den anderen Thread
 public void closePipes() {
  try {
    _pipeout.close();
    _dout.close();
  }
  catch (IOException e) {
         System.err.println("IOException: " + e);
  }
 }

 public void connect(PipedInputStream pipein) {
  try {
    _pipeout.connect(pipein);   // Kopplung der Streams 
  }
  catch (IOException e) {
         System.err.println("IOException: " + e);
  }
 }
                   
 public void delay(int pause) {
    try {
           Thread.sleep(pause);
        } catch (InterruptedException e) {
    }
  }  // delay


 public void run(){
  int i;
  double dValue;
  java.util.Random random = new java.util.Random();
  try {
    for (i=0; i<_n; i++) {
      dValue = random.nextDouble()*10000;
     _dout.writeDouble(dValue);
      System.out.println(" Writer:   i: "+(i+1)+"    Wert: "+dValue);
      _editor.append(" i: "+(i+1)+"    Wert: "+dValue+"\n");
      _editor.updateUI();
     _editor.invalidate();
     if (_pause>0) delay(_pause);
     delay(10);
    }
  }
  catch (IOException e) {
         System.err.println("IOException: " + e);
  }
 } // run

}  // writeThread



