//Titel:            Testbeispuiel für MDI-Fenster
//Version:          1.0
//Copyright:        HS-Harz, FB AI
//Autor:            Dipl.-Inf. Dipl.-Ing. Michael Wlhelm
//Firma:
//Beschreibung:

// Beispiel eines MDI-Fenster mit Threads

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




public class ClientThread2 extends JFrame {

  // Container für die Clientfenster
  private JDesktopPane _desktopPane = new JDesktopPane();

    // Variablen für die Menüs
  private JMenuBar menuBar1;   // MenüContainer
  private JMenu MainFile;      // Hauptmenü
  private JMenuItem MnNew;     // Menüeintrag
  private JMenuItem MnClose;   // Menüeintrag


  private JMenu MainWindows;        // HauptMenü
  private JMenuItem MnPrevWindows;  // Menüeintrag
  private JMenuItem MnNextWindows;  // Menüeintrag
  private JMenuItem MnTile;         // Menüeintrag
  private JMenuItem MnCascade;      // Menüeintrag



   // Konstruktor
  public ClientThread2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    setGUI();
  }

  public void setGUI() {
      // BorderLayout setzen
    this.getContentPane().setLayout( new BorderLayout() );

      // Variable DesktopPane einfügen
      // in ihr werden alle Clientfenster eingefügt
    this.getContentPane().add(_desktopPane, BorderLayout.CENTER);
    this.setSize( 600, 400);

    setMenus();
  }


    // setzt die Menüs
  private void setMenus() {
    menuBar1 = new JMenuBar();

      // DATEI
    MainFile = new JMenu("Datei");
    MnNew = new JMenuItem("Neu");
    MnClose = new JMenuItem("Schließen");

      // Event definieren
    MnNew.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnNew_actionPerformed(e);
      }
    });
      // Short Key definieren  STRG+N
    MnNew.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
    MainFile.add(MnNew);

    MainFile.addSeparator();

    // --------------------------
      // Event definieren
    MnClose.addActionListener(new ActionListener()  {

      public void actionPerformed(ActionEvent e) {
        MnClose_actionPerformed(e);
      }
    });
    MainFile.add(MnClose);

      // Hauptmenü FILE in den MenüBar einfügen
    menuBar1.add(MainFile);




    // ----------------
    // Menü Windows
    MainWindows = new JMenu("Fenster");
    MnPrevWindows = new JMenuItem("Vorheriges Fenster");
    MnNextWindows = new JMenuItem("Nächstes Fenster");
    MnCascade = new JMenuItem("Kaskade");
    MnTile = new JMenuItem("Aufteilen");

      // Event definieren
    MnCascade.addActionListener(new ActionListener()  {

      public void actionPerformed(ActionEvent e) {
        MnCascade_actionPerformed(e);
      }
    });

      // Event definieren
    MnTile.addActionListener(new ActionListener()  {

      public void actionPerformed(ActionEvent e) {
        MnTile_actionPerformed(e);
      }
    });
      // MenüEinträge definieren
    MainWindows.add(MnPrevWindows);
    MainWindows.add(MnNextWindows);
    MainWindows.addSeparator();
    MainWindows.add(MnCascade);
    MainWindows.add(MnTile);
    menuBar1.add(MainWindows);

    this.setJMenuBar(menuBar1);
  } // setMenus


     // Event definieren, CODE
  void MnNew_actionPerformed(ActionEvent e) {
    MyInternalFrame frame = new MyInternalFrame(null);
    // frame.setBounds(0, 0, 450, 300);
    frame.setVisible(true);
    _desktopPane.add(frame, new Integer(1));
      // Neu
    _desktopPane.moveToFront(frame);
  }




   // wird aufgerufen beim Schließen des Hauptfensters
  void MnClose_actionPerformed(ActionEvent e) {
    System.exit(0);
  }



   // -----------------
   // Cascade der Fenster
  void MnCascade_actionPerformed(ActionEvent e) {
      int i, j, p, Abstand, w, h, n;
      JInternalFrame f;     // the actual Clientwindow
      JInternalFrame[] ff;  // Array of all internal Clientwindow
      ff = _desktopPane.getAllFrames();
      n = ff.length;  // Count of
      // calc the distace of the frames, depends on the count of the frames
      if (n > 0) {
          if (n<=3)
            Abstand = 80;
          else {
            if (n>6)
              Abstand = 25;
            else
              Abstand = 40;
          }
          // calc the width and height of each frame
          w = _desktopPane.getWidth() - (n-1)*Abstand;
          h = _desktopPane.getHeight() - (n-1)*Abstand;
          // the top frame has the index 0 !
          // index i is for the position
          // index j ist for the frames, the last is the top-frame !
          for (i = 0, j=n-1; i <n; i++,j--) {
              f = (JInternalFrame)ff[j];  // typecasting
              p = i*Abstand;
              f.setLocation(p, p);        // position
              f.setSize(w,h);             // width height
          }
      }
  }   // MnCascade_actionPerformed(ActionEvent e) {



   // Aufteilen der Fenster
  void MnTile_actionPerformed(ActionEvent e) {
    System.out.println("Menüeintrag Tile");
      JInternalFrame[] ff;    // Array for all internal frames
      JInternalFrame f; //
      int hoehe, anz, breite, left, top;
      int indexCol, anzCol, anzRow, anzRowUnten, n, i, h, b1, b2;
      boolean bZweiBreiten;

      ff = _desktopPane.getAllFrames();
        // Count > 0 ?
      if (ff.length > 0) {
          // Quadratische Aufteilung

            /*
             5:
                 -
                - -
                - -

             11:
                 - -
                - - -
                - - -
                - - -

            */

          n = ff.length;
          if (n < 1) {
              return;
          }
          if (n == 1) {
              f = (JInternalFrame)ff[0];
              try {
                  f.setMaximum(true);
              }
              catch (Exception e1) {
                  e1.printStackTrace();
              }
              return;
          }
          
          anzCol = (int)Math.round(Math.sqrt(n)); // Wurzel aus Anzahl
          // bestimme Anzahl der unteren (vollen) Zeilen
          anzRowUnten = n / anzCol;  // trunc
            // Abfrage nach Rest
          if (n > (anzRowUnten * anzCol)) {
              anzRow = anzRowUnten + 1;
              bZweiBreiten = true;
          }
          else {
              anzRow = anzRowUnten;
              bZweiBreiten = false;
          }
          //  AnzRow zeigt die Anzahl aller Zeilen
          
          // nun werden zwei Breiten und eine Höhe ausgerechnet
          // 1. Breite  gilt für die vollen Reihen
          // 2. Breite  gilt für oberste  Reihe, falls sie nicht voll ist
          hoehe = _desktopPane.getHeight();
          h = _desktopPane.getHeight() / anzRow;
          b1 = _desktopPane.getWidth() / anzCol; // volle Breite
          if (bZweiBreiten)
             b2 = _desktopPane.getWidth() / (n - anzCol * anzRowUnten); // untere Breite
          else
             b2 = b1;
              
          // Rückwärts
          anz = 0;
          left = 0;
          top = hoehe - h;
          indexCol = 0;
          for (i = ff.length - 1; i >= 0; i--) {
              f = (JInternalFrame)ff[i];
              //f.setSize(100,100);
              try {
                  f.setMaximum(false);
              }
              catch (Exception e2) {
                  e2.printStackTrace();
              }
              anz++;
              indexCol++;
              if (indexCol > anzCol) {
                  // neue Reihe anfangen
                  left = 0;
                  top -= h;
                  indexCol = 1;
              }
              // Position im Fenster setzen
              f.setLocation(left, top);
              // Breite Höhe setzen
              // Check, ob man in der obersten Zeile sich befindet ?
              if (anz > (anzRowUnten * anzCol)) {
                  f.setSize(b2, h); // width height
                  left += b2;
              }
              else {
                  f.setSize(b1, h); // width height
                  left += b1;
              }
          }
      }
  }  // Tile



    // zum korrekten Beenden benötigt
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if(e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

   // Hauptprogramm
  static public void main(String[] args) {
    ClientThread2 desktop = new ClientThread2();
    desktop.setVisible(true);
  }
  
}





// Clientfenster
class MyInternalFrame extends JInternalFrame implements Runnable {
    static int _openFrameCount = 0;
    static final int _offset = 30;

  private String _sFileName;
  private String _Caption;

  JLabel jLabel1 = new JLabel();
  JTextField TAnzahl = new JTextField();
  JLabel jLSumme1 = new JLabel();
  JLabel jLSumme2 = new JLabel();

  JButton BnOk = new JButton();
  JButton BnESC = new JButton();

  Thread t;

  
  public MyInternalFrame(String sFileName) {
    _sFileName = sFileName;
    if (sFileName==null)
      _Caption = "noname";
    else
      _Caption = sFileName;

    setGUI();
  }

  public void setGUI() {
    JPanel panelBn = new JPanel();

    this.setClosable(true);
    this.setIconifiable(true);
    this.setMaximizable(true);
    this.setResizable(true);
    this.getContentPane().setLayout( new GridBagLayout() );
    this.setTitle(_Caption);

    jLabel1.setText("Anzahl");
    TAnzahl.setText("100");


    BnOk.setText("Ok");
    BnESC.setText("Abbruch");

    this.getContentPane().add(jLabel1, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,20,0,0), 0, 6));

    this.getContentPane().add(TAnzahl,   new GridBagConstraints(1, 0, 3, 1, 1.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,20,0,20), 22, 6));


    panelBn.add(BnOk);
    panelBn.add(BnESC);

  	_openFrameCount++;
    setBounds(_offset * _openFrameCount, _offset *_openFrameCount, 450, 300);

    this.getContentPane().add(panelBn,  new GridBagConstraints(1, 1, 3, 2, 0.0, 0.0
            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(40,0,0,20), 0, 0));


    jLSumme1.setText("Summe");
    this.getContentPane().add(jLSumme1, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,20,0,0), 0, 6));

    jLSumme2.setText("0");
    this.getContentPane().add(jLSumme2, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,20,0,0), 0, 6));

     jLSumme2.setFont( new Font("TimesRoman", Font.ITALIC,32)  );


    BnOk.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnOk_Click();
      }
    });

    BnESC.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnESC_Click();
      }
    });




  }


  private void BnOk_Click() {
    String sAnz;
    int i, n, summe;
    sAnz = TAnzahl.getText();
    if ( basis.IVal(sAnz) ) {
      t = new Thread(this);  // Thread wird erzeugt
      t.start();             // Thread wird gestartet
   }
   else {
     basis.Message("Konvertierung fehlerhaft","Text: "+basis.getErrorCode()+'\n'+sAnz );
   }

  }  // BnOk

  // Thread-Methode
  public void run() {
    String sAnz;
    int i, n, summe;
    sAnz = TAnzahl.getText();
    if ( basis.IVal(sAnz) ) {
      n = basis.getIValResult();   // Ergebnis holen
      // basis.Message("Konvertierung okay","Ergebnis: "+Integer.toString(n) );
      summe = 0;
      try  {
        for (i=1; i<=n; i++) {
          summe+=i;
          jLSumme2.setText( Integer.toString(summe) );
          jLSumme2.paintImmediately(0,0, jLSumme2.getWidth(), jLSumme2.getHeight()  );
          Thread.sleep(100);
          // clock.wait(1000);
        }
      }
      catch (InterruptedException e) {}
    }
  }
  



  public void delay(long time) {
    long t1;
    t1 =  System.currentTimeMillis()+time;
    while ( System.currentTimeMillis() < t1) {
    }
  }  // delay
  

  private void BnESC_Click() {
     dispose();
  }

}  // MyInternalFrame



// Die folgende Klasse dient zur Konvertierung von String in Zahlen
// Sie kapselt die Konvertierung
// Beispiel für int
class basis {

    public static final int C_LEER = 1;
    public static final int C_KEINEZAHL = 2;
    public static final int C_ZUKLEIN = 3;
    public static final int C_ZUGROSS = 4;

      // Konstanten für den Error Code als String
    public static final String SZ_LEER = "Leerer Text";
    public static final String SZ_KEINEZAHL = "Konvertierung schlug fehl";
    public static final String SZ_ZUKLEIN = "Für den Bereich zu klein";
    public static final String SZ_ZUGROSS = "Für den Bereich zu groß";



    // Damit braucht man nicht die Konstanten aus JOptionPane referenzieren
    public static final int YES = 1;
    public static final int NO = 2;
    public static final int ESC = 3;

    private static int intVal;          // speichert das Ergebnis
    private static long longVal;        // speichert das Ergebnis
    private static double dblVal;       // speichert das Ergebnis

    private static int ValError = 0;   // speichert den Konvertierungfehler


    // Zeigt eine Fehlermeldung an
  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


    public static boolean IVal(String szText) {
        // erläuterung von iIVal = Integer.valueOf(szText).intValue();
        boolean result = true;
        String s;
        s = new String(szText); // neues Objekt
        s.trim();
        if (s.length() == 0) {
            ValError = C_LEER;
            intVal = 0;
            result = false;
        }
        else {
            try {
                intVal = Integer.valueOf(szText).intValue();
                ValError = 0;
            }
            catch (NumberFormatException e) {
                // Check ob die "Zahl" für den Integerbereich zu klein oder zu groß
                // System.err.println(e);
                try {
                    dblVal = Double.valueOf(szText).doubleValue();
                    if ( dblVal<Integer.MIN_VALUE) {
                      ValError = C_ZUKLEIN;
                    }
                    if ( dblVal>Integer.MAX_VALUE) {
                      ValError = C_ZUGROSS;
                    }
                }
                catch (NumberFormatException e2) {
                    // Hier könnte noch eine genauere Abfrage integriert werde,
                    // ob die Zahl nicht zu groß für den int-Bereich ist
                    // System.err.println(e);
                    ValError = C_KEINEZAHL;
                    intVal = 0;
                    result = false;
                }
                intVal = 0;
                result = false;
            }
        }
        return result;
    } // IVal

    /**
     * getIValResult
     * @return int iIVal
     * @param none
     * @exception none
     * @version      1.0
     * @author Michael Wilhelm HS Harz, FB AI
     * @use gibt den Wert der Konvertierung aus, oder den Fehlerwert Example
     * @see #getIValError
     * @see #setIValError
     */
    public static int getIValResult() {
       return intVal;
    }


      // gibt einen Klartext für die Konvertierung aus
    public static String getErrorCode() {
      switch (ValError) {
        case C_LEER :      return SZ_LEER;
        case C_KEINEZAHL : return SZ_KEINEZAHL;
        case C_ZUKLEIN :   return SZ_ZUKLEIN;
        case C_ZUGROSS :   return SZ_ZUGROSS;
        default:           return "Fehlerhafter Index in Methode getErrorCode: "+Integer.toString(ValError);
      } // switch
    }

}
