//Titel:            Behaelter-Steuerung
//Version:          1.0
//Copyright:		Copyright (c) Oktober, 2011
//Autor:            Michael Wilhelm
//Organisation:     HS Harz, FB AI
//Beschreibung:     Dialog-Fenster zum Steuern eines Behaelters mittels Steuercode à la Assembler


import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

import java.util.Vector;  // benoetigt fuer Listen der Views und der Ventile


// ActionListener fuer onClick
// IBehaelterParent fuer CallBack aus dem Behaelter
public class Steuerung_behaelter1 extends JFrame implements ActionListener, IBehaelterParent {


  JToggleButton BnStart = new JToggleButton("Start");
  JButton BnClear = new JButton("Löschen");
  JToggleButton BnStartVentil1 = new JToggleButton("Start 1. Ventil");
  JToggleButton BnStartVentil2 = new JToggleButton("Start 2. Ventil");
  JToggleButton BnStartVentil3 = new JToggleButton("Start 3. Ventil");
  JButton BnNotHalt = new JButton("N O T   H A  L T");

  JSlider sliderBehaelter = new JSlider(1,30,1);  // int min, max, value
  JSlider sliderVentil1 = new JSlider(1,10,1);
  JSlider sliderVentil2 = new JSlider(1,5,1);
  JSlider sliderVentil3 = new JSlider(1,5,1);

  JLabel jLabelBehaelter = new JLabel("Behälter");

   // hilfspanel
  private JPanel jpanel;
  private JPanel jpanelVentile;

   // Steuerungs-Elemente
  private Behaelter behaelter;
  private GUIBehaelterPanel jpBehaelter;
  private GUIBehaelterTextField statusBits;
  private GUIBehaelterLabel statusLabel;
  private GUIBehaelterVolumen statusVolumen;

  private GUIVentil ventil1;
  private GUIVentil ventil2;
  private GUIVentil ventil3;


   // Konstruktor
  public Steuerung_behaelter1() {
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    setGUI();
  }

   // Aufbauen der GUI
  private void setGUI() {
    setSize(900, 600);
    setLocation(100,50);
    setTitle("Steuerung eines Behälters");

    BnStart.setFont( new Font("Arial", Font.BOLD,18)  );
    BnClear.setFont( new Font("Arial", Font.BOLD,18)  );
    BnNotHalt.setFont( new Font("Arial", Font.BOLD,18)  );
    BnStartVentil1.setFont( new Font("Arial", Font.BOLD,18)  );
    BnStartVentil2.setFont( new Font("Arial", Font.BOLD,18)  );
    BnStartVentil3.setFont( new Font("Arial", Font.BOLD,18)  );
    BnNotHalt.setEnabled(false);

    setVentileEnabled(false);

    JLabel jLabel1 = new JLabel("Ventile");
    JLabel jLabel3 = new JLabel("StatusBits");
    JLabel jLabel5 = new JLabel("Controller");

    statusLabel = new GUIBehaelterLabel("Remark");
    statusVolumen = new GUIBehaelterVolumen("Volumen: 0 m³/s");

    ventil1 = new GUIVentil("1. Ventil");
    ventil2 = new GUIVentil("2. Ventil");
    ventil3 = new GUIVentil("3. Ventil");

    statusBits = new GUIBehaelterTextField("0   0   0   0   0   0   0   0   0");
    statusBits.setFont( new Font("Courier New", Font.BOLD,18)  );


    jpBehaelter = new GUIBehaelterPanel();
    behaelter = new Behaelter(this);
     // tim ein Behaelter ist halb so groß
    jLabelBehaelter.setText("Behälter: Q="+Integer.toString(2*behaelter.getDurchfluss())+" m³/s" );


    behaelter.addView(jpBehaelter);
    behaelter.addView(statusBits);
    behaelter.addView(statusLabel);
    behaelter.addView(statusVolumen);


    behaelter.addVentil(ventil1);
    behaelter.addVentil(ventil2);
    behaelter.addVentil(ventil3);

    jLabel1.setFont( new Font("Arial", Font.BOLD,18)  );
    jLabelBehaelter.setFont( new Font("Arial", Font.BOLD,18)  );
    jLabel3.setFont( new Font("Arial", Font.BOLD,18)  );
    jLabel5.setFont( new Font("Arial", Font.BOLD,18)  );

    statusLabel.setFont( new Font("Arial", Font.BOLD,18)  );
    statusVolumen.setFont( new Font("Arial", Font.BOLD,18)  );
    statusBits.setFont( new Font("Arial", Font.BOLD,24)  );

    this.getContentPane().setLayout( new GridBagLayout() );

    getContentPane().add(jLabel1,
         new GridBagConstraints(
             0, 0, 1, 1, 0.0, 0.0    // x,y, AnzCol, AnzRows, weightx, weighty
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10,10,10,40), 0, 0));

    jpanelVentile = new JPanel();
    jpanelVentile.setLayout( new GridBagLayout() );
    getContentPane().add(jpanelVentile,
         new GridBagConstraints(
             0, 1, 1, 1, 60.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10,10,30,20), 0, 0));

      // Hilfspanel fuer die Ventile
    jpanelVentile.add(ventil1,
         new GridBagConstraints(
             0, 0, 1, 1, 70.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(0,0,0,0), 0, 0));


    jpanelVentile.add(ventil2,
         new GridBagConstraints(
             0, 1, 1, 1, 70.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10,0,0,0), 0, 0));

    jpanelVentile.add(ventil3,
         new GridBagConstraints(
             0, 2, 1, 1, 70.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10,0,0,0), 0, 0));
     

    getContentPane().add(jLabelBehaelter,
         new GridBagConstraints(
             1, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10,10,10,40), 0, 0));

    this.getContentPane().add(jpBehaelter,
         new GridBagConstraints(
             1, 1, 1, 1, 40.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10,10,30,40), 0, 0));

    getContentPane().add(jLabel3,
         new GridBagConstraints(
             1, 2, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10,10,10,40), 0, 0));

    this.getContentPane().add(statusBits,
         new GridBagConstraints(
             1, 3, 1, 1, 30.0, 0.0
            ,GridBagConstraints.NORTHWEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(00,10,10,40), 0, 0));

  this.getContentPane().add(statusLabel,
         new GridBagConstraints(
             1, 4, 1, 1, 30.0, 0.0
            ,GridBagConstraints.NORTHWEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,30,40), 0, 0));


  this.getContentPane().add(statusVolumen,
         new GridBagConstraints(
             1, 5, 1, 1, 30.0, 0.0
            ,GridBagConstraints.NORTHWEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,30,40), 0, 0));


    this.getContentPane().add(jLabel5,
         new GridBagConstraints(
             2, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10,10,0,0), 0, 0));


	JPanel pnButton = new JPanel();
	pnButton.setBackground( new Color(210,255,255) );  // RGB
	pnButton.setLayout( new GridBagLayout() );
	pnButton.add(BnStart,
         new GridBagConstraints(
             0, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));


	pnButton.add(sliderBehaelter,
         new GridBagConstraints(
             0, 1, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

	pnButton.add(BnClear,
         new GridBagConstraints(
             0, 2, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

	pnButton.add(BnStartVentil1,
         new GridBagConstraints(
             0, 3, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

     pnButton.add(sliderVentil1,
         new GridBagConstraints(
             0, 4, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

	pnButton.add(BnStartVentil2,
         new GridBagConstraints(
             0, 5, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

     pnButton.add(sliderVentil2,
         new GridBagConstraints(
             0, 6, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

	pnButton.add(BnStartVentil3,
         new GridBagConstraints(
             0, 7, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

     pnButton.add(sliderVentil3,
         new GridBagConstraints(
             0, 8, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,0,10), 0, 0));

	pnButton.add(BnNotHalt,
         new GridBagConstraints(
             0, 9, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,10,10), 0, 0));

      // Panel der rechten Buttons einfuegen
	this.getContentPane().add(pnButton,
         new GridBagConstraints(
             2, 1, 1, 5, 40.0, 10.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,30,20), 0, 0));

      // Verknuepfen mit ActionsPerformed  = onClick
     BnStart.addActionListener(this);
     BnClear.addActionListener(this);
     BnNotHalt.addActionListener(this);
     BnStartVentil1.addActionListener(this);
     BnStartVentil2.addActionListener(this);
     BnStartVentil3.addActionListener(this);

     sliderBehaelter.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderBehaelter_Click();
            }
     });

     sliderVentil1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderVentil1_Click();
            }
     });
     sliderVentil2.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderVentil2_Click();
            }
     });
     sliderVentil3.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderVentil3_Click();
            }
     });

  
  } // setGUI


   // gemeinsame Methode fuer alle Clicks
  public void actionPerformed(ActionEvent e) {
     if (e.getSource() == BnStart) {
       if (!BnStart.isSelected()) {
         behaelter.sendCommand(Behaelter.C_BEF_STOP);
         BnStart.setText("Start");
         BnStart.updateUI();
         BnNotHalt.setEnabled(true);
       }
       else {
         behaelter.sendCommand(Behaelter.C_BEF_START);
         BnNotHalt.setEnabled(true);
         BnStart.setText("Stop");
         BnStart.updateUI();
       }
     }
     else if (e.getSource()==BnNotHalt) {
       behaelter.sendCommand(Behaelter.C_BEF_NOTHALT);
       BnStart.setText("Start");
       BnStart.updateUI();
       BnStart.setSelected(false);
       BnNotHalt.setEnabled(true);
       setVentileEnabled(false);
     }
     else if (e.getSource() == BnClear ){
       behaelter.sendCommand(Behaelter.C_BEF_CLEAR);
       ventil1.setVolumen(0);
       ventil2.setVolumen(0);
       ventil3.setVolumen(0);
     }
     else if (e.getSource()==BnStartVentil1) {
          System.out.println("Ventil    1");
       if (BnStartVentil1.isSelected()) {
          System.out.println("Ventil1 start");
          behaelter.sendCommand(Behaelter.C_VENTIL_START | 1);  // An
       }
       else {
          System.out.println("Ventil1 stop");
         behaelter.sendCommand(Behaelter.C_VENTIL_STOP | 1);  // Aus
       }
     }
     else if (e.getSource()==BnStartVentil2) {
          System.out.println("Ventil 2");
       if (BnStartVentil2.isSelected()) {
         behaelter.sendCommand(Behaelter.C_VENTIL_START | 2);  // An
       }
       else {
         behaelter.sendCommand(Behaelter.C_VENTIL_STOP | 2);  // Aus
       }
     }
     else if (e.getSource()==BnStartVentil3) {
          System.out.println("Ventil 3");
       if (BnStartVentil3.isSelected()) {
         behaelter.sendCommand(Behaelter.C_VENTIL_START | 3);  // An
       }
       else {
         behaelter.sendCommand(Behaelter.C_VENTIL_STOP | 3);  // Aus
       }
     }

  }  // actionPerformed


  private void sliderBehaelter_Click() {
    int value = sliderBehaelter.getValue();
    behaelter.setDurchfluss(value);
    jLabelBehaelter.setText("Behälter: Q="+Integer.toString(2*behaelter.getDurchfluss())+" m³/s" );
  }

  private void sliderVentil1_Click() {
    int value = sliderVentil1.getValue();
    ventil1.setDurchfluss(value);
  }
  private void sliderVentil2_Click() {
    int value = sliderVentil2.getValue();
    ventil2.setDurchfluss(value);
  }
  private void sliderVentil3_Click() {
    int value = sliderVentil3.getValue();
    ventil3.setDurchfluss(value);
  }

  private void setVentileEnabled(boolean value) {
    BnStartVentil1.setEnabled(value);
    BnStartVentil2.setEnabled(value);
    BnStartVentil3.setEnabled(value);
    sliderVentil1.setEnabled(value);
    sliderVentil2.setEnabled(value);
    sliderVentil3.setEnabled(value);
  }

   // wird von der Klasse Behaelter aufgerufen, CallBack-Methode
  public void setStatus(int status) {
     // Code redundant
    if ( (status & Behaelter.C_FULL) == Behaelter.C_FULL ) {
       setVentileEnabled(true);
       BnStart.setSelected(false);
       BnStart.setText("Start");
    }

    if ( (status & Behaelter.C_VENTILE_RUN) == Behaelter.C_VENTILE_RUN) {
       setVentileEnabled(true);
       //BnStartVentil1.setSelected(false);
       //BnStartVentil2.setSelected(false);
       //BnStartVentil3.setSelected(false);
    }
    else {
       setVentileEnabled(false);
    }
  }  // setStatus


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

}  // steuerung_behaelter


// Beschreibt die Funktionalitaet fuer das JFrame
interface IBehaelterParent {
  public void setStatus(int status);
}


// Beschreibt die Funktionalitaet fuer den Behaelter
// wird von den Ventilen aufgerufen
interface IBehaelter {
  public int  getVolumen(int volumen);  // Wunsch und Realitaet
  public void setDurchfluss(int durchfluss);
  public int  getDurchfluss();
}


class Behaelter implements ActionListener, IBehaelter {
    // Bit fuer die Anzeige
  public static final int C_LEER = 1;
  public static final int C_LT_10 = 2;
  public static final int C_LT_25 = 4;
  public static final int C_LT_50 = 8;
  public static final int C_LT_75 = 16;
  public static final int C_LT_100 = 32;
  public static final int C_FULL = 64;
  public static final int C_RUN = 128;
  public static final int C_VENTILE_RUN = 256;

   // Befehle
  public static final int C_BEF_START   = 0x10;
  public static final int C_BEF_STOP    = 0x11;
  public static final int C_BEF_CLEAR   = 0x1F;
  public static final int C_BEF_NOTHALT = 0xFF;

  public static final int C_VENTIL_START = 0x20;
  public static final int C_VENTIL_STOP  = 0x30;


  private Timer myTimer=null;
  private int time=250;

   // Liste der Views und Ventile, so flexibel
  private Vector<IGUIBehaelter> listeGUI;
  private Vector<IGUIVentil> listeVentile;

   // interne Variablen
  private int maxvolumen=500;
  private int volumen=0;
  private int status=0;
  private int durchfluss=1;
  private IBehaelterParent parent=null;
  private boolean bRun=false;

   // Konstruktor
  public Behaelter(IBehaelterParent parent) {
    this.parent = parent;
    myTimer = new Timer(time, this); // 200 ms
    volumen=0;
    listeGUI = new Vector<IGUIBehaelter>();
    listeVentile = new Vector<IGUIVentil>();
  }

   // Check, welches Kommando angekommen ist
  public void sendCommand(int command) {
    System.out.println("Command: "+command);
     if (command == C_BEF_START) {
        setMaxVolumen(maxvolumen); // Alle View bekommen den aktuellen Wert
        myTimer.start();  
        bRun=true;
        ChangeStatus();
     }
     else if (command == C_BEF_STOP) {
        myTimer.stop();
        bRun=false;
        ChangeStatus();
     }
     else if (command == C_BEF_NOTHALT) {
        myTimer.stop();
        bRun=false;
        ChangeStatus();
        for (IGUIVentil ventil : listeVentile) {
         ventil.sendCommand(IGUIVentil.C_BEF_NOTHALT);
        }
        CBasis.Message("NOT HALT","Bitte alle Studenten in einem Biergarten evakuieren");
     }
     if ( command == C_BEF_CLEAR) {
       volumen=0;
       ChangeStatus();
     }

        // Ventile, selektiere erst den Hauptbefehl, dann die Nummer
     if ( (command & 0xF0) == C_VENTIL_START ) {
       int nr = (command & 0xF)-1;  // nun anschalten
        System.out.println("Ventilnr an: "+nr);
       IGUIVentil ventil = listeVentile.get(nr);
       ventil.sendCommand(IGUIVentil.C_BEF_START);
     }
     else if ( (command & 0xF0) == C_VENTIL_STOP ) {
       int nr = (command & 0xF)-1;  // nun ausschalten
        System.out.println("Ventilnr aus: "+nr);
       IGUIVentil ventil = listeVentile.get(nr);
       ventil.sendCommand(IGUIVentil.C_BEF_STOP);
     }
  }

  public void addView(IGUIBehaelter behaelter) {
    listeGUI.add(behaelter);
  }

  public void addVentil(IGUIVentil ventil) {
    listeVentile.add(ventil);
    ventil.addBehaelter(this);
  }

   // muss alles nacheinander ablaufen
  public synchronized int getVolumen(int volumen) {  // Wunsch und Realitaet
    if (this.volumen>=volumen) {
      this.volumen-=volumen;
      ChangeStatus();
      return volumen;
    }
    else {
      this.volumen=0;
      for (IGUIVentil ventil: listeVentile) {
        ventil.sendCommand(IGUIVentil.C_BEF_STOP);
      }
      ChangeStatus();
      return this.volumen;
    }    
  }  // getVolumen

  // Mausclick Abarbeitung
   public void actionPerformed(ActionEvent e) {
      int status;
      addVolumen(durchfluss);
      status = getStatus();
      if (  (status & C_FULL) == C_FULL ) { 
        myTimer.stop();
        ChangeStatus();
        // CBasis.Message("Füllstand","Behälter ist voll");
      }
    }  // actionperformed


  public void setDurchfluss(int durchfluss) {
    if (durchfluss>0)
      this.durchfluss=durchfluss;
  }

  public int  getDurchfluss() {
    return durchfluss;
  }


  public void addVolumen(int inc)   {
    volumen+=inc;
    //guibehalter.setVolumen(volumen);
    ChangeStatus();
  }

  public void setVolumen(int volumen)   {
    this.volumen=volumen;
    ChangeStatus();
  }
  public void setMaxVolumen(int maxvolumen)   {
    this.maxvolumen=maxvolumen;
    for (IGUIBehaelter beh: listeGUI) {
      beh.setMaxVolumen(maxvolumen);
    }
    ChangeStatus();
  }

  public int getStatus() {
    return status;
  }


    // erstzellen des Statusbits, Nachrichten verschicken
  private void ChangeStatus() {
    int statusOld = status;
    status=0;
    double hproz = volumen*100.0/maxvolumen;
    // System.out.println("Vol: "+volumen);
    if (volumen==0) 
      status= status | C_LEER;
    else 
      if (hproz<10.0) 
       status= status | C_LT_10;
      else if (hproz<25.0) 
             status= status | C_LT_25;
           else if (hproz<50.0) 
                 status= status | C_LT_50;
                else if ( hproz<75)
                       status= status | C_LT_75;
                     else 
                       if ( hproz>=100.0)   // Rundungsfehler 
                         status= status | C_FULL;
                       else 
                         status= status | C_LT_100;  // 75 <= x <100%

    if (bRun) {
      status= status | C_RUN;
    }
    
    if ( volumen>=30 ) {
      status = status | C_VENTILE_RUN;
    }
    else {
      if ( ((statusOld & C_VENTILE_RUN) == C_VENTILE_RUN) && (volumen>=10)) 
        status = status | C_VENTILE_RUN;  // runtewr geht es langsamer
    }

    parent.setStatus(status);
    for (IGUIBehaelter beh: listeGUI) {
      beh.setVolumen(volumen);
      beh.setStatus(status);
    }

  } // ChangeStatus


}  // Class Behaelter 



// Beschreibt die Funktionalitaet fuer den Viewer-Behaelter
interface IGUIBehaelter {
  public void setStatus(int status);
  public void setVolumen(int volumen);
  public void setMaxVolumen(int maxvolumen);
}



class GUIBehaelterLabel extends JLabel implements IGUIBehaelter {
  private int volumen=0;
  private int maxvolumen=0;


  public GUIBehaelterLabel(String sText) {
    super(sText);
  }


  public void setStatus(int status) {
    String sValue;
    if ( (status & Behaelter.C_RUN) == Behaelter.C_RUN)
       sValue="Status: laufend ";
    else
       sValue="Status: Stop ";

    if ( (status & Behaelter.C_LEER) == Behaelter.C_LEER) 
      sValue+=" Behälter ist leer";
    else 
      if ( (status & Behaelter.C_LT_10) == Behaelter.C_LT_10) 
        sValue+=" Behälter ist < 10% gefüllt";
      else 
         if ( (status & Behaelter.C_LT_25) == Behaelter.C_LT_25) 
           sValue+=" Behälter ist < 25% gefüllt";
         else 
            if ( (status & Behaelter.C_LT_50) == Behaelter.C_LT_50) 
              sValue+=" Behälter ist < 50% gefüllt";
            else 
               if ( (status & Behaelter.C_LT_75) == Behaelter.C_LT_75) 
                 sValue+=" Behälter ist < 75% gefüllt";
               else 
                  if ( (status & Behaelter.C_LT_100) == Behaelter.C_LT_100) 
                    sValue+=" Behälter ist < 100% gefüllt";
                  else 
                     if ( (status & Behaelter.C_FULL) == Behaelter.C_FULL) 
                       sValue+=" Behälter ist voll";
                     else {
                       sValue+=" *********  Fehlerhafter Wert im Füllstatus-Bits  ****** ";
                       CBasis.Message( "setStatus","Modul: GUIBehaelterLabel\nFehlerhafter Wert im Füllstatus-Bits");    
                     }
     /*
     if ( (status & Behaelter.C_VENTILE_RUN) == Behaelter.C_VENTILE_RUN) {
        sValue+="  Ventile verfügbar";
     }  
     */
     setText(sValue);
   }  // setStatus
   

  public void setVolumen(int volumen) {
    volumen=volumen;
    updateUI();
  }

  public void setMaxVolumen(int maxvolumen) {
    this.maxvolumen = maxvolumen;
  }

}  // class GUIBehaelterLabel




class GUIBehaelterVolumen extends JLabel implements IGUIBehaelter {
  private int volumen=0;
  private int maxvolumen=0;


  public GUIBehaelterVolumen(String sText) {
    super(sText);
  }


  public void setStatus(int status) {
     
   }  // setStatus
   

  public void setVolumen(int volumen) {
    volumen=volumen;
    setText("Volumen: "+volumen+" m³/s");
  }

  public void setMaxVolumen(int maxvolumen) {
    this.maxvolumen = maxvolumen;
  }

}  // class GUIBehaelterVolumen




class GUIBehaelterTextField extends JTextField implements IGUIBehaelter {
  private int volumen=0;
  private int maxvolumen=0;


  public GUIBehaelterTextField(String sText) {
    super(sText);
  }


  public void setMaxVolumen(int maxvolumen) {
    this.maxvolumen = maxvolumen;
  }

  private int getBit(int value, int bit) {
    if ( (value & bit) == bit)
      return 1;
    else
      return 0;
  }

   // Nun die Bits auseinandernehmen
  public void setStatus(int status) {
    int b7=0, b6=0, b5=0, b4=0, b3=0, b2=0, b1=0, b0=0;
    b0=getBit(status,1);
    b1=getBit(status,2);
    b2=getBit(status,4);
    b3=getBit(status,8);
    b4=getBit(status,16);
    b5=getBit(status,32);
    b6=getBit(status,64);
    b7=getBit(status,128);

    setText(
      b7+"   "+b6+"   "+b5+"   "+b4+"   "+b3+"   "+b2+"   "+b1+"   "+b0 );
  }

  public void setVolumen(int volumen) {
    volumen=volumen;
    updateUI();
  }


}  // class GUIBehaelterTextField



// Klasse zum Anzeige eines Behälters
class GUIBehaelterPanel extends JPanel implements IGUIBehaelter {

  private int volumen=0;
  private int maxvolumen=0;


  public void setStatus(int status) {
  }

  public void setMaxVolumen(int maxvolumen) {
    System.out.println("Maxvol Behaelter: "+maxvolumen);
    this.maxvolumen = maxvolumen;
    updateUI();
  }

  public void setVolumen(int volumen)   {
    this.volumen=volumen;
    updateUI();
  }

   // Diese Routine wird automatisch vom Betriebssystem aufgerufen
   // oder von "updateUI()"
  public void paint (Graphics g) {
     g.setColor(Color.white);
     g.fillRect(0,0,getWidth(), getHeight());
     if (maxvolumen>0) {
       int hoehe = volumen*getHeight()/maxvolumen;
       g.setColor(Color.blue);
       g.fillRect(0,getHeight()-hoehe,getWidth(), getHeight());
     }
  }

}  // class GUIBehaelterPanel


// Beschreibt die Funktionalitaet fuer ein Ventil
interface IGUIVentil {
   // Befehle
  public static final int C_BEF_START   = 0x10;
  public static final int C_BEF_STOP    = 0x11;
  public static final int C_BEF_CLEAR   = 0x1F;
  public static final int C_BEF_NOTHALT = 0xFF;

   // fuer das Status-Byte
  public static final int C_RUN = 128;

  public void   setDurchfluss(int durchfluss);
  public void   setVolumen(int volumen);
  public int    getDurchfluss();  // fuer behaelter
  public void   sendCommand(int command);
  public void   addBehaelter(IBehaelter behaelter);
}



// Klasse zum Anzeige eines Behälters
class GUIVentil extends JPanel implements ActionListener, IGUIVentil {

  private Timer myTimer=null;  // Timer
  private int time=500;

  private int volumen=0;
  private int durchfluss=1;  // kubikmeter/s
  private String sName="";
  private int status=0;

  private IBehaelter behaelter;


  public GUIVentil(String sName) {
    this.sName = sName;
    myTimer = new Timer(time, this); // 200 ms
  }

  public void addBehaelter(IBehaelter behaelter) {
    this.behaelter=behaelter;
  }


   // Auswerten der Befehle
  public void sendCommand(int command) {
    System.out.println("Ventil: Command: "+command);
    status = 0;
     if (command == IGUIVentil.C_BEF_START) {
      System.out.println("Ventil: Timer start");
        myTimer.start();  
        status = status | IGUIVentil.C_RUN;
        updateUI();
     }
     else if (command == IGUIVentil.C_BEF_STOP) {
      System.out.println("Ventil: Timer stop");
        myTimer.stop();
        updateUI();
     }
     else if (command == IGUIVentil.C_BEF_NOTHALT) {
        myTimer.stop();
        updateUI();
        CBasis.Message("NOT Halt","Not-Halt im Ventil "+sName);
     }
     if ( command == IGUIVentil.C_BEF_CLEAR) {
       volumen=0;
       updateUI();
     }
  } // sendCommand


   // hier wird der Timer-Event abgearbeitet
   public void actionPerformed(ActionEvent e) {
        // hole Volumen, aber nur soviel wie vorhanden ist
      int vol = behaelter.getVolumen(durchfluss);
      addVolumen(vol);
   }  // actionperformed


  public void setDurchfluss(int durchfluss) {
    this.durchfluss=durchfluss;
    updateUI();
  }

  public int getDurchfluss() {
    return durchfluss;
  }

  public void addVolumen(int volumen)   {
    System.out.println("Volumen Ventil: "+volumen);
    this.volumen+=volumen;
    updateUI();
  }

  public void setVolumen(int volumen)   {
    this.volumen=volumen;
    updateUI();
  }

   // zeichnet den Status des Ventils
  public void paint (Graphics g)
  {
     int h=(getHeight()>>2)-5;
     g.setColor(Color.lightGray);
     g.fillRect(0,0,getWidth(), getHeight());
     g.setColor(Color.red);
     if (false) {
     g.drawString(sName,10,h);
     g.drawString("  Q: "+Integer.toString(durchfluss)+" m³/s", 10,h+h);
     g.drawString("  Vol: "+Integer.toString(volumen)+" m³/s", 10,h+h+h);
     g.drawString("  Status: "+Integer.toString(status), 10,h+h+h+h);
     }
     else {
       g.setFont( new Font("Arial", Font.BOLD,18) );
       g.setColor(Color.blue);
       g.drawString(sName,10,h);
       g.setColor(Color.red);
       g.drawString("  Q: "+Integer.toString(durchfluss)+" m³/s", 10,h+h);
       g.drawString("  Vol: "+Integer.toString(volumen)+" m³/s", 10,h+h+h);
       g.drawString("  Status: "+Integer.toString(status), 10,h+h+h+h);
     }

  }

}  // class GUIVentil


// Hilfsklasse fuer die Anzeige einer Nachricht
class CBasis {

  public static void Message( String sTitle, String sMessage) {
    JOptionPane.showConfirmDialog(null,sMessage,sTitle,
      JOptionPane.DEFAULT_OPTION,
      JOptionPane.INFORMATION_MESSAGE);  // Symbol
    /*  Optionen der Schalter:
         DEFAULT_OPTION    Ok
         YES_NO_OPTION
         YES_NO_CANCEL_OPTION
         OK_CANCEL_OPTION
     */
     /*  Symbole:
      ERROR_MESSAGE
      INFORMATION_MESSAGE
      WARNING_MESSAGE
      QUESTION_MESSAGE
      PLAIN_MESSAGE
     */

  } // Message

}