
package Klausur;

import java.util.LinkedList;
import java.util.Queue;

public class MyBaum<T extends Comparable<T>> {
	private Node<T> wurzel;
	private int size;

	public boolean add(T wert) {

		if (wurzel == null) {
			this.wurzel = new Node<T>(wert);
			size++;
			return true;
		}
	
			
		else {
			size++;
			return this.wurzel.add(wert);
		}
			
		
	
		
	}
	
	public boolean contain(T wert) {
		if (wurzel.wert == wert)
			return true;
		
		else
			return wurzel.contain(wert);
	}
	
	
	public int getSize() {
		return size;
	}
	
	public void inorder() {
		
		wurzel.inorder();
		
	}
	
	public void postOrder() {
		
		wurzel.postOrder();;
		
	}
	
	public void levelOrder() {
		wurzel.levelOrder(wurzel);
	}
	
	
	public void remove (T wert) {
		
		if(wurzel.wert == wert)
			wurzel = null;
		
		else
			wurzel.delete(wert);
	}

	class Node<T extends Comparable<T>>  {

		Node<T> links;
		Node<T> rechts;
		T wert;

		public Node(T wert) {
			this.wert = wert;
		}
		
		public boolean contain(T wert) {
			
			if (wert.compareTo(this.wert) < 0) {
				if (links == null)
					return false;
				return links.contain(wert);
				
			}else if (wert.compareTo(this.wert) > 0) {
				
				if (rechts == null)
					return false;
				
				return rechts.contain(wert);			
			}
			else
				return true;
		}
		
		public Node<T> delete(T wert) {
			if (wert.compareTo(this.wert) < 0) {
				if (this.links == null)
					throw new IllegalArgumentException("Wert beim Löschen nicht gefunden.");
				
				links = links.delete(wert);
				
			} else if (wert.compareTo(this.wert) > 0) {
				if (rechts == null)
					throw new IllegalArgumentException("Wert beim Löschen nicht gefunden.");
			
				rechts = rechts.delete(wert);
				
			} else if (wert == this.wert) {
				System.out.println("delete here " + this.wert);
				
				if (links == null && rechts == null)
					return null;
				
				else if (links != null && rechts == null)
					return this.links;
				
				else if (links == null && rechts != null)
					return rechts;
				
				else {
			            Node<T> biggst = links.findBiggest();  // Kleinsten Wert im rechten Teilbaum finden
			            System.out.println("biggst " + biggst.wert);

			            this.wert = biggst.wert;  // Wert ersetzen
			            links = links.delete(biggst.wert);  // Den kleinsten Knoten löschen
			        }
			}
				
			return this;
		} // delete
		
		
		private Node<T> findSmallest() {
		    if (links == null) {
		        return this;  // Der kleinste Knoten ist der linkeste Knoten
		    }
		    return links.findSmallest();
		}

		
		private Node<T> findBiggest() {
			if (rechts == null)
				return this;
			
			return rechts.findBiggest(); 
		}		
		
		
		

		public boolean add(T wert) {

			if (wert.compareTo(this.wert) < 0) {
				if (links != null)
					links.add(wert);
				else {
					links = new Node<>(wert);
					return true;
				}

			} else if ((wert.compareTo(this.wert) > 0)) {
				if (wert.compareTo(this.wert) > 0)
					if (rechts != null)
						rechts.add(wert);
					else {
						rechts = new Node<>(wert);
						return true;
					}		
			}
			return false;

		}
		
		public void inorder() {
			if (links != null)
				links.inorder();
			
			System.out.print(this.wert + " ");
			
			if (rechts != null)
				rechts.inorder();
		}
		
		public void preOrder() {
			System.out.print(this.wert + " ");
			
			if (links != null)
				links.preOrder();
			
			if (rechts != null)
				rechts.preOrder();
		}
		
		public void postOrder() {
			
			if (links != null )
				links.postOrder();
			
			if (rechts != null)
				rechts.postOrder();
			
			System.out.print(this.wert + " ");
		}
		
		
		public void levelOrder(Node<T> wurzel) {

			Queue<Node<T>> queue = new LinkedList<>();
			queue.add(wurzel);

			while (!queue.isEmpty()) {
				Node<T> temp = queue.poll();

				if (temp.links != null)
					queue.add(temp.links);

				if (temp.rechts != null)
					queue.add(temp.rechts);
				
				System.out.print(temp.wert + " ");

			}
			
		}

	}
}
