package ClaimItGUI;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.LayoutManager2;
import java.util.ArrayList;

/**
 * Diese Klasse realisiert einen Layout-Manager, der alle Komponente in Relation zur ursprünglichen Größe der aufnehmenden Komponente 
 * platziert und deren Größe anpaßt, wenn der aufnehmende Container seine Größe ändert. Alle Veränderungen laufen über die setBounds()-Methode
 * der verwalteten Objekte. Sollen Komponenten bei Größenänderungen in besonderer Weise reagieren, ist diese Methode zu überlagern.
 * Beim Hinzufügen von Komponenten wird ein Objekt vom Typ Bounds übergeben, an Hand derer das Objekt am Anfang platziert wird. Alle Komponenten
 * werden in einer "ArrayList" vorgehalten. Wird layoutContainter() aufgerufen, wird diese Liste durchgegangen und für jede Komponente die neue
 * Position und Größe berechnet. 
 * 
 * @author Dirk Becker
 *
 */
public class RelativeScaleAndPlacementLayout implements LayoutManager2
{	
	ArrayList<LayoutManagerComponent> compsToCalc;
	
	double firstWidth, firstHeight;									// Hier speichern wir die Höhe und Breite der Ursprungswerte..

	public RelativeScaleAndPlacementLayout()
	{
		firstWidth = -1;											// Initialisierung für die Fallunterscheidung: bereits gezeichnet oder
		firstHeight = -1;											// gerade erst initialisiert? Siehe layoutContainer().
		
		compsToCalc = new ArrayList<LayoutManagerComponent>();		// Liste der Componenten, die dieser Layout-Manager verwaltet. 
	}
	/**
	 * Diese Methode fügt eine Komponente hinzu, die dieser LayoutManager verwalten soll. Übergeben wird ein Bounds-Objekt, welches
	 * Position und Dimension für die Komponente enthält.
	 * Die Komponente wird der Liste hinzugefügt und die setSize() und setLocation() Methoden dieses Objekts mit den übergebenen Werten 
	 * aufgerufen. 
	 * 
	 * @param toAdd Weitere Komponente, deren Verwaltung dieser Layoutmanager übernehmen soll. 
	 * @param bounds Ein Bounds-Objekt, in der X und Y Koordinaten, sowie Höhe und Breite der Komponente gespeichert sind. 
	 */
	public void addLayoutComponent(Component toAdd, Object bounds) 
	{
		// Da die Superklasse LayoutManager2 lediglich ein Objekt zum Übergeben erlaubt, müssen wir erst nach Bounds caten.
		// Hier wird nicht überprüft, ob dies auch gelingt. 
		Bounds theBounds = (Bounds) bounds;
		// Anschließend Fonts ermitteln und dessen Größe speichern.
		// Die Relative Größe wird anhand der Höhe des Containers ermittelt.
		if (toAdd.getFont() != null)
		{
			Font tmpFont = toAdd.getFont().deriveFont(0, theBounds.getHeight() / 2);
			toAdd.setFont(tmpFont);
		}
		// Anschließend Platzieren. 
		toAdd.setSize(theBounds.getWidth(), theBounds.getHeight());
		toAdd.setLocation(theBounds.getX(), theBounds.getY());
		
		compsToCalc.add(new LayoutManagerComponent(toAdd));
	}
	/**
	 * Gibt die maximale Größe des Objektes zurück, also die Summe aus der Breite und die Summe der Höhe aller Komponenten. 
	 * 
	 * @return Die maximalen Abmessungen der Komponente, die dieser Manager verwaltet.
	 */
	public Dimension maximumLayoutSize(Container parent) 
	{
		int x, y;
		x = 0;
		y = 0;
		for (LayoutManagerComponent comp: compsToCalc)
		{
			y = y + comp.getComponent().getHeight();
			x = x + comp.getComponent().getWidth();
		}
		return new Dimension(x,y);
	}
	/**
	 * Diese Methode wird aufgerufen, wenn das Layout des Containers angepaßt werden muß. Zunächst wird hier überprüft, ob dieses Objekt und 
	 * alle sein zugehörigen Komponenten bereits initialisiert wurden. Ist dies nicht der Fall, wird es hier nachgeholt. Anschließend werden
	 * die Position, die Abmessungen und Schriftgröße neu berechnet und die Komponenten entsprechend ausgerichtet und in der Größe angepaßt.
	 * 
	 * @param parent Komponente, für die das Layout erfolgen soll. 
	 */
	public void layoutContainer(Container parent)
	{
		Bounds tmpBs = new Bounds(0,0,0,0);							// Temporäres Bounds-Objekt.
		float tmpFontSize = 0;
		Font tmpFont;
		
		// Wurde dieses Objekt schon initialisiert?
		if (firstWidth == -1 || firstHeight == -1)
		{
			// Nein, also speichern wir die augenblickliche Größe.
			firstHeight = parent.getHeight();
			firstWidth = parent.getWidth();
		}
		// Anschließend für jede Komponente in der Komponentenliste:
		for (LayoutManagerComponent comp: compsToCalc)
		{
			/* 
			 * Wenn das LayoutManagerComponent-Objekt noch nicht initialisiert wurde, mache das jetzt. 
			 * Nimm dazu die Größe nach der letzten Größenänderung als Maßstab.
			 */
			if (comp.getRelativeX() == 0.0 && comp.getRelativeY() == 0.0)
			{
				/* 
				 * Diese Komponente wurde noch nicht initialisiert. Wir besorgen uns die relative Position innerhalb
				 * der umgebenen Komponente und speichern diese.
				 * Wenn wir hier nur durch "int" teilen, dann wird der Nachkommateil abgeschnitten und wir erhalten stets 0.0.
				 * Casten wir hier jedoch lediglich firstWidth und firstHeight nach "double", wird stets ein zweites Fenster geöffnet,
				 * welches die selbe Größe wie der erste Dialog hat und sich über diesen legt.
				 * Wehe, mich fragt jemand wieso...
				 */
				comp.setRelativeX(comp.getComponent().getLocation().x / firstWidth);
				comp.setRelativeY(comp.getComponent().getLocation().y / firstHeight);
			}
			if (comp.getRelativeHeight() == 0.0 && comp.getRelativeWidth() == 0.0)
			{
				/*
				 * Diese Komponente wurde noch nicht initialisiert. Wir besorgen uns die Relative Höhe und Breite 
				 * der ursprünglichen Komponente und speichern diese.
				 */
				comp.setRelativeHeight(comp.getComponent().getHeight() / firstHeight);
				comp.setRelativeWidth(comp.getComponent().getWidth() / firstWidth);	
			}
			if (comp.getRelativeFontSize() == 0.0)
			{
				/*
				 * Auch die relative Schriftgröße ist noch nicht errmittelt. Wir holen das nach.
				 */
				comp.setRelativeFontSize(comp.getComponent().getFont().getSize2D() / firstHeight);
			}
			
			// Anschließend berechnet die neuen Bounds...
			tmpBs.setX((int)(parent.getWidth() * comp.getRelativeX()));
			tmpBs.setY((int)(parent.getHeight() * comp.getRelativeY()));
			tmpBs.setHeight((int)(parent.getHeight() * comp.getRelativeHeight()));
			tmpBs.setWidth((int)(parent.getWidth() * comp.getRelativeWidth()));
			
			// ...und die neue Schriftgröße...
			tmpFontSize = (float) (parent.getHeight() * comp.getRelativeFontSize());
			tmpFont = comp.getComponent().getFont().deriveFont(tmpFontSize);
			
			// ...dann wende sie auf das betrachtete Objekt an.
			comp.getComponent().setBounds(tmpBs.getX(), tmpBs.getY(), tmpBs.getWidth(), tmpBs.getHeight());
			comp.getComponent().setFont(tmpFont);
		}		
	}
	/**
	 * Ruft die Methode maximumLayoutSize auf. Die minimale Größe ist die bevorzugte Größe ist die maximale Größe.
	 * 
	 * @return Die minimalen Abmessungen der Komponente, die dieser Manager verwaltet.
	 */
	public Dimension minimumLayoutSize(Container parent) 
	{
		return maximumLayoutSize(parent);
	}
	/**
	 * Ruft die Methode maximumLayoutSize auf. Die bevorzugte Größe ist die minimale Größe ist die maximale Größe.
	 * 
	 * @return Die bevorzugten Abmessungen der Komponente, die dieser Manager verwaltet.
	 */
	public Dimension preferredLayoutSize(Container parent) 
	{
		return maximumLayoutSize(parent);
	}
	/**
	 * Über diese Methode können Komponenten aus der Liste der verwalteten Komponenten erntfernt werden. Kommt das Element nicht in der Liste vor,
	 * unternimmt diese Methode nichts weiter.
	 * 
	 * @param comp Komponete, für die dieser Layoutmanager nicht mehr zuständig sein soll. 
	 */
	public void removeLayoutComponent(Component comp) 
	{
		/* 
		 * Da wir eine Komponente übergeben bekommen, müssen wir zunächst herausfinden, welches Element wir eigentlich 
		 * aus der Liste entfernen sollen.
		 */ 
		for (LayoutManagerComponent comps : compsToCalc)
		{
			if (comps.getComponent() == comp)
			{
				compsToCalc.remove(comps);
				return;
			}
		}
	} 
	/**
	 * Diese Methode hat für diesen Layout-Manager keiner Funktion! Objekte, die ohne Bounds übergeben werden, werden ignoriert!
	 * 
	 * @param name Name der übergebenen Komponente.
	 * @param toAdd Componente, die hinzugefügt werden soll. 
	 */
	public void addLayoutComponent(String name, Component toAdd) 
	{
	}
	/**
	 * Diese Methode ist für diesen LayoutManager ohne Funktion! Gibt lediglich 0 zurück.
	 * 
	 * @param parent Übergeordneter Container.
	 */
	public float getLayoutAlignmentX(Container parent) 
	{
		return 0;
	}	
	/**
	 * Diese Methode ist für diesen LayoutManager ohne Funktion! Gibt lediglich 0 zurück.
	 * 
	 * @param parent Übergeordneter Container.
	 */
	public float getLayoutAlignmentY(Container parent) 
	{
		return 0;
	}
	/**
	 * Diese Methode ist für diesen LayoutManager ohne Funktion!
	 * 
	 * @param parent Übergeordneter Container.
	 */
	public void invalidateLayout(Container parent) 
	{
	}
}
