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


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

// Opendialog
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.filechooser.*;
//import java.util.Hashtable;
//import java.util.Enumeration;

import java.util.ArrayList;

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

import java.util.Observable;
import java.util.Observer;


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

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

   // Konstruktor
  public ATI_MVC() {
    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");
    MnNew = new JMenuItem("Neu");
    MnNew2 = new JMenuItem("New2");
    MnClose = new JMenuItem("Schließen");

    MnNew.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnNew_click();
      }
    });
    MnNew.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
    MainFile.add(MnNew);

    MnNew2.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        MnNew2_click();
      }
    });
    MnNew2.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
    MainFile.add(MnNew2);
    MainFile.addSeparator();

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

      public void actionPerformed(ActionEvent e) {
        MnClose_click();
      }
    });
    MainFile.add(MnClose);
    menuBar1.add(MainFile);
    this.setJMenuBar(menuBar1);
  } // setMenus



  void MnNew_click() {
    CModell modell = new CModell();
    CController contr = new CController();
    myInternalFrame frame = 
     new myInternalFrame(modell, contr);
    int pos = 
    _desktopPane.getAllFrames().length+1;
    frame.setBounds(
     (pos*50 % _desktopPane.getWidth()),
     (pos*50 % _desktopPane.getHeight()), 
         250, 150);
    _desktopPane.add(frame, new Integer(1));
  }

  void MnNew2_click() {
   JInternalFrame[] ff;
   myInternalFrame frameParent;
   ff = _desktopPane.getAllFrames();
   if (ff.length>0) {
     frameParent =(myInternalFrame)ff[0];
     frameParent.setLocation(0,0);
     CModell modell =
              frameParent.getModell();
     CController contr = 
            frameParent.getController();
     myInternalFrame frame = 
      new myInternalFrame(modell,contr);
     int pos = 
     _desktopPane.getAllFrames().length+1;
     frame.setBounds(
      (pos*50 % _desktopPane.getWidth()),
      (pos*50 % _desktopPane.getHeight()), 
          250, 150);
     _desktopPane.add(frame, new Integer(1));

   }

  }  // MnNew2



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


   // -----------------
  void MnCut_click() {
    System.out.println("Menüeintrag Cut");
  }
  void MnCopy_click() {
    System.out.println("Menüeintrag Copy");
  }
  void MnInsert_click() {
    System.out.println("Menüeintrag Insert");
  }


   // -----------------
  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) {
    ATI_MVC frame = new ATI_MVC();
    frame.setVisible(true);
  }

}  // ATI_MVC


class CModell {
  public String sText="Heute ist Montag";
}

class CController extends Observable{
   boolean _bUpdateModus=false;

  public void setUpdateModus(boolean bUpdateModus) {
    _bUpdateModus = bUpdateModus;
  }
  public boolean getUpdateModus() {
    return _bUpdateModus;
  }

  public void notifyOberservers(int tagnr) {
    if ( ! getUpdateModus() ) {
      setUpdateModus(true);
      super.setChanged();
        // Sende Nachricht an ALLE Viewer
      super.notifyObservers( new Integer(tagnr) );
    }
  }

}  // CController


// IUpdate == Observer
class myInternalFrame 
   extends JInternalFrame 
   implements Observer, ITextArea_Change {

  private CModell _modell;
  private CController _contr;
  private JTextAreaDocListener _editor;

  private static int tagnr = 0;
  private int _tag;

  public myInternalFrame(CModell modell,
            CController contr) {
    _modell = modell;
    _contr = contr;
    _contr.addObserver(this); // Registrierung

    _tag = ++tagnr;
    setTitle("Tag: "+_tag);

    setSize(50,30);
   setGUI();
	setVisible(true);
   _editor.setText(_modell.sText);
  } // myInternalFrame

  public void setGUI() {
    this.setClosable(true);
    this.setIconifiable(true);
    this.setMaximizable(true);
    this.setResizable(true);
    this.getContentPane().setLayout(new BorderLayout() );

    _editor = new JTextAreaDocListener(this);
    this.getContentPane().add(
       new JScrollPane(_editor),
         BorderLayout.CENTER);
    _editor.setFont( 
       new Font("Arial", Font.BOLD,18)  );

    JButton bnUpdate=new JButton("Update");

    this.getContentPane().add(
       bnUpdate, BorderLayout.NORTH);

    bnUpdate.addActionListener(
    new java.awt.event.ActionListener() {
      public void actionPerformed(
                         ActionEvent e) {
        bnUpdate_click();
      }
    });
  } // setGUI
  private void bnUpdate_click() {
    System.out.println("in frame bnUpdate");
  }

  public CModell getModell() {
    _modell.sText = _editor.getText();
    return _modell;
  }
  public CController getController() {
    return _contr;
  }
  
  public void sendChangeMessage() {
    System.out.println("Change");
    if ( ! _contr.getUpdateModus() ) {
      _modell.sText = _editor.getText(); // 5.
      _contr.notifyOberservers(_tag);
      _contr.setUpdateModus(false);
    }
 }

  public void update(Observable contr, Object obj) {
    System.out.println("in update");
     Integer Tag = (Integer) obj;
     int tagnr = Tag.intValue();
    if ( _tag != tagnr ) {
      if (  _contr.getUpdateModus() ) {
        _editor.setText(_modell.sText );
        System.out.println("ich ja: "+_tag);
      }
    } 
    else {
        System.out.println("ich nicht: "+_tag);
    }
  }

}  // myInternalFrame


interface ITextArea_Change {
  public void sendChangeMessage();
}
       


class JTextAreaDocListener extends JTextArea  {
   private ITextArea_Change _parent;
   public  boolean bModify=false;

   public JTextAreaDocListener(ITextArea_Change parent) {
     super();
     init(parent);
   }


   public JTextAreaDocListener(ITextArea_Change parent, String sText) {
     super(sText);
     init(parent);
   }

   private void init(ITextArea_Change parent) {
     _parent = parent;
       // ableiten der Update-Methoden des Listeners
     this.getDocument().addDocumentListener(new DocumentListener(){
         public void changedUpdate(DocumentEvent ev) {
             System.out.println("changedUpdate");
             _parent.sendChangeMessage();
         }
         
         public void insertUpdate(DocumentEvent ev) {
             System.out.println("changed insert");
             _parent.sendChangeMessage();
         }
         
         public void removeUpdate(DocumentEvent ev) {
             System.out.println("changed remove");
             _parent.sendChangeMessage();
         }
     });     
    } // init
}  // JTextAreaDocListener

