//Titel:            MDI-Fenster
//Version:          1.0
//Copyright:
//Autor:
//Firma:
//Beschreibung:


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

import java.util.ArrayList;

// InternalFrame
import javax.swing.event.*;



public class TdoT extends JFrame {
  // Container für die Clientfenster
  private JDesktopPane _desktopPane = new JDesktopPane();

    // Menü Variablen
  private JMenuBar menuBar1;
  private JMenu MainFile;
  private JMenuItem MnStart;
  private JMenuItem MnClose;

  private JMenu MainWindows;
  private JMenuItem MnPrevWindows;
  private JMenuItem MnNextWindows;
  private JMenuItem MnTile;
  private JMenuItem MnCascade;

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

  public void setGUI() {
    this.getContentPane().setLayout( new BorderLayout() );
    this.setContentPane(_desktopPane);
    this.setSize(new Dimension(600, 400));
    this.setVisible(true);
    setMenus();
  }  // setGUI


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

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

    MnStart.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnStart_click();
      }
    });
    MainFile.add(MnStart);
    MainFile.addSeparator();

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

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


    menuBar1.add(MainFile);

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

    MnCascade.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnCascade_click();
      }
    });
    MnTile.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnTile_click();
      }
    });
    MainWindows.add(MnPrevWindows);
    MainWindows.add(MnNextWindows);
    MainWindows.addSeparator();
    MainWindows.add(MnCascade);
    MainWindows.add(MnTile);
    menuBar1.add(MainWindows);

    this.setJMenuBar(menuBar1);
  } // setMenus



  void MnStart_click() {
     StartDialog  dlg = new StartDialog (_desktopPane);
     dlg.setVisible(true);
  }

  void MnClose_click() {
    System.exit(0);
  }


   // -----------------
  void MnCascade_click() {
      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_click() {



  void MnTile_click() {
    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;
              }
          }
      }
  } // MnTile




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

}  // TdoT



class myThread extends JInternalFrame implements Runnable {
//  private CMaster _master;
  JTextArea TEdit = new JTextArea("");
  int [] _zahlen;

  public myThread(String caption, int [] zahlen) {
    _zahlen = zahlen;
    this.setTitle(caption);
    setGUI();
    setVisible(true);
    setSize(200, 200);
  } // myThread


  public void setGUI() {
    this.setClosable(true);
    this.setIconifiable(true);
    this.setMaximizable(true);
    this.setResizable(true);
    this.getContentPane().setLayout(new BorderLayout() );
//    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    this.getContentPane().setLayout( new GridBagLayout() );

    JLabel jLabel1 = new JLabel("Ergebnisse");
    jLabel1.setFont( new Font("Arial", Font.BOLD,14)  );
    TEdit.setFont( new Font("Arial", Font.BOLD,14)  );

    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, 0));

     // JScrollPane
    this.getContentPane().add(new JScrollPane(TEdit),
        new GridBagConstraints(0, 1, 1, 1, 100.0, 100.0
            ,GridBagConstraints.EAST,
            GridBagConstraints.BOTH,
            new Insets(0,20,0,20), 0, 0));

  } // setGUI

  public void run() {
    String sErg="";
    boolean bPrim;
    int j;
    if (_zahlen!=null) {
      for (int z : _zahlen) {
        bPrim=true;
        for (j=2; j<z; j++) {
          if ( (z%j)==0) {
            bPrim=false;
            break;
          }
        } // for
        if (bPrim) sErg+=z+"\n";
      } // for (int z : zahlen) {
    }
    else {
       CMaster master = CMaster.getInstance();
       int [] zahlen;
       while (true) {
         zahlen = master.getPaket();
         if (zahlen==null) break;
         for (int z : zahlen) {
           bPrim=true;
           for (j=2; j<z; j++) {
             if ( (z%j)==0) {
               bPrim=false;
               break;
             }
           } // for
           if (bPrim) sErg+=z+"\n";
         } // for (int z : zahlen) {
       }  // while
    }
    TEdit.setText(sErg);
  }  // run

}  // myThread



class StartDialog extends JFrame {

  private final int MAX = 200000;  // 200000

  JLabel jLabel1 = new JLabel("Anzahl der Threads");
  JSpinner spAnzThread =  new JSpinner( new SpinnerNumberModel(5,1, 30, 1)   );

  JRadioButton rb1 = new JRadioButton("Ein Thread", true);
  JRadioButton rb2 = new JRadioButton("n Threads, gleiche Gewichtung", false);
  JRadioButton rb3 = new JRadioButton("n Threads, Master / Slave", false);

  JLabel jLabel2 = new JLabel("Ergebnis");
  JTextField TErgebnisse =  new JTextField("");

  JButton BnStart = new JButton("Start");
  JButton BnEsc = new JButton("Abbruch");

  JDesktopPane _desktopPane;

  public StartDialog (JDesktopPane desktopPane) {
    _desktopPane = desktopPane;
    setSize(300, 250);
    setLocation(800,10);
    setTitle("Auswahl der Optionen");
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    setGUI();
  }

  private void setGUI() {
    this.getContentPane().setLayout( new GridBagLayout() );

    BnStart.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        BnStart_Clicked();
      }
    });

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


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

    this.getContentPane().add(spAnzThread,
        new GridBagConstraints(1, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,20,0,20), 0, 0));


    this.getContentPane().add(rb1,
        new GridBagConstraints(0, 1, 2, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,20,0,20), 0, 0));

    this.getContentPane().add(rb2,
        new GridBagConstraints(0, 2, 2, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,20,0,20), 0, 0));

    this.getContentPane().add(rb3,
        new GridBagConstraints(0, 3, 2, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,20,0,20), 0, 0));

    ButtonGroup group1 = new ButtonGroup();
    group1.add( rb1 );
    group1.add( rb2 );
    group1.add( rb3 );


    this.getContentPane().add(jLabel2,
        new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(20,10,0,20), 0, 0));

    this.getContentPane().add(TErgebnisse,
        new GridBagConstraints(1, 4, 1, 1, 100.0, 0.0
            ,GridBagConstraints.NORTH,
            GridBagConstraints.HORIZONTAL,
            new Insets(20,20,0,20), 0, 0));

   // --------------------------
            // Schalter
     JPanel panelBn = new JPanel();
     panelBn.setLayout( new FlowLayout() );
     //panelBn.setBackground(Color.green);

    this.getContentPane().add(panelBn,
        new GridBagConstraints(0, 5, 2, 1, 100.0, 0.0
            ,GridBagConstraints.CENTER,
            GridBagConstraints.HORIZONTAL,
            new Insets(10,10,10,10), 0, 0));


    panelBn.add(BnStart);
    panelBn.add(BnEsc);

  jLabel1.setFont( new Font("Arial", Font.BOLD,14)  );
  spAnzThread.setFont( new Font("Arial", Font.BOLD,14)  );
  jLabel2.setFont( new Font("Arial", Font.BOLD,14)  );
  TErgebnisse.setFont( new Font("Arial", Font.BOLD,14)  );
  BnStart.setFont( new Font("Arial", Font.BOLD,14)  );
  BnEsc.setFont( new Font("Arial", Font.BOLD,14)  );
  } // setGUI

  void SingleThread() {
    Integer N = (Integer) spAnzThread.getValue();
    Thread cpu;
    int i;
    long t1, t2;
    int [] zahlen;
    int n = N.intValue();
    zahlen = new int[MAX-1];
    for (i=2; i<=MAX; i++) 
       zahlen[i-2]=i;
    myThread frame = new myThread("SingleThread", zahlen);
    frame.setLocation(0, 0);
    _desktopPane.add(frame);
    cpu = new Thread(frame);
	    t1 =  System.currentTimeMillis();
    cpu.start();
    	try {
 		cpu.join();
    }
    catch (InterruptedException e) {
    }
    t2 =  System.currentTimeMillis();
    TErgebnisse.setText((t2-t1)+" ms" );
    // frame.setVisible(false);
  }  // SingleThread

  private void AequidistanteThread() {
    Integer N = (Integer) spAnzThread.getValue();
    Thread [] cpus;
    int i,j, d1, d2, diff;
    long t1, t2;
    int [] zahlen;
    int n = N.intValue();
    cpus = new Thread[n];
    diff = MAX / n;
    d1=2;  // untere Grenz
    d2=diff; // obere Grenze
    for (i=0; i<n; i++) {
      if (d2>MAX) d2=MAX;
      zahlen = new int[d2-d1+1];
      for (j=d1; j<=d2; j++) 
         zahlen[j-d1]=j;
      myThread frame = new myThread("Äquidistante Thread", zahlen);
      int x=220*(i%4)+10;
      int y = 220*(i/4)+10;
      frame.setLocation(x, y);
      _desktopPane.add(frame);
      cpus[i] = new Thread(frame);
      d1+=diff;
      d2+=diff;
    }

    t1 =  System.currentTimeMillis();
    for (i=0; i<n; i++) {
      cpus[i].start();
    }
    	try {
      for (i=0; i<n; i++) {
        cpus[i].join();
      }
    }
    catch (InterruptedException e) {
    }
    t2 =  System.currentTimeMillis();
    TErgebnisse.setText((t2-t1)+" ms" );
    // frame.setVisible(false);
  }

  private void MasterSlaveThread() {
    Integer N = (Integer) spAnzThread.getValue();
    Thread [] cpus;
    long t1, t2;
    int i;
    int n = N.intValue();
    cpus = new Thread[n];

    CMaster master = CMaster.getInstance();
    master.setPakete(MAX);

    for (i=0; i<n; i++) {
      myThread frame = new myThread("Master/Slave Threads", null);
      int x=220*(i%4)+10;
      int y = 220*(i/4)+10;
      frame.setLocation(x, y);
      _desktopPane.add(frame);
      cpus[i] = new Thread(frame);
    }

    t1 =  System.currentTimeMillis();
    for (i=0; i<n; i++) {
      cpus[i].start();
    }
    	try {
      for (i=0; i<n; i++) {
        cpus[i].join();
      }
    }
    catch (InterruptedException e) {
    }
    t2 =  System.currentTimeMillis();
    TErgebnisse.setText((t2-t1)+" ms" );
    // frame.setVisible(false);
  } // MasterSlave


  void BnStart_Clicked() {
    TErgebnisse.setText("");
    TErgebnisse.updateUI();
    if (rb1.isSelected() )   SingleThread();
    if (rb2.isSelected() )   AequidistanteThread();
    if (rb3.isSelected() )   MasterSlaveThread();
  }

  void BnEsc_Clicked() {
    setVisible(false);
  }


}


class CMaster {
  private final int STEP = 100;
  private static CMaster _instance = new CMaster();
  private ArrayList _liste;
  private int _index;

  private CMaster() {
     _liste= new ArrayList();
  }

  public static CMaster getInstance() {
   return _instance;
  }

  public synchronized  int [] getPaket() {
    _index++;
    if (_index>=_liste.size())
     return null;
    else
     return (int []) _liste.get(_index);
  }

  public void setPakete(int anz) {
    int j, d1, d2;
    int [] zahlen;
    d1=0;
    d2=STEP;
    _liste.clear();
    while (d1<=anz) {
      if (d2>anz) d2=anz;
      zahlen = new int[d2-d1+1];
      for (j=d1; j<=d2; j++) 
         zahlen[j-d1]=j;
      _liste.add(zahlen);
      d1+=STEP;
      d2+=STEP;
    }  // while    
    _index=-1;
    // System.out.println("Count: "+_liste.size() );
  }

}