/*
 * Created on 14.11.2003 18:45:38
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda.plugin.fibheap;

import jedas.*;

/**
 * Extends the FibHeap-class by fast direct access to nodes.
 * 
 * @author Markus Krebs
 */
public class FibHeapExt extends FibHeap implements FibHeapOperations,
											FibHeapSubOperations {

	private static final int maxKey = 100;
	
	public FibNode[] nodes = new FibNode[maxKey];
	
	public FibHeapExt() {
		super();
	}
	
	// === Operations ==========================================
	/*
	public FibNode insert(int k) {
		if(nodes[k]!=null) return null;	// Doppelte Schlüssel vermeiden
		nodes[k] = super.insert(k);
		return nodes[k];
	}*/
	public void insertOp(int k) {
		if(nodes[k]!=null) return;	// Doppelte Schlüssel vermeiden
		//nodes[k] = super.insert(k);
		nodes[k] = insert(k);
	}
	public int deleteminOp() {
		if(isEmpty()) return -1;
		
		int k = super.deletemin();
		nodes[k] = null;
		return k;
	}
	public void decreasekeyOp(int key, int k) {
		if(nodes[key]==null) return;
		
		if(nodes[k]!=null) return;	// Doppelte Schlüssel vermeiden
		decreasekey(nodes[key], k);
		nodes[k] = nodes[key];
		nodes[key] = null;
	}
	public int deleteOp(int key) {
		if(nodes[key]==null) return -1;
		
		delete(nodes[key]);
		nodes[key] = null;
		return key;
	}
	
	// === SubOperations =======================================
	public void setKeyOp(int node, int key) {
		if(nodes[key]!=null) return;	// Doppelte Schlüssel vermeiden
		nodes[node].setKey(key);		
		FibNode temp = nodes[node];
		nodes[node] = null;
		nodes[key] = temp;
		Jedas.updateDisplay();
	}
	public void cutOp(int node) {
		nodes[node].cut(min.getRoot());
		animate();
		//Jedas.getScheduler().start();
	}
	public void markOp(int node) {
		nodes[node].mark();
		animate();
		//Jedas.getScheduler().start();
	}
	public void unmarkOp(int node) {
		nodes[node].unmark();
		animate();
		//Jedas.getScheduler().start();
	}
	public void linkOp(int node1, int node2) {
		// Link nur auf Wurzelknoten
		nodes[node1].getRoot().addChild(nodes[node2].getRoot());
		animate();
		//Jedas.getScheduler().start();
	}
	public void updateMinOp(int node) {
		updateMin(nodes[node]);
		// Scheduler wird bereits in updateMin gestartet
	}
	public void newFHeapMeldOp(int node) {
		if(nodes[node]!=null) return;
		//insertOp(node);	// nicht verwendbar da updateMin
		FibHeap q = new FibHeap(node);
		nodes[node] = q.min;
		//System.out.println("Insert " + q.min.getKey()); // debug
		mainCompObj.transferItem(q.min.compObj);
		DPair pos;
		if (isEmpty()) {
			pos = initialNodePos;
		} else {
			pos = new DPair(min.getRoot().compObj.getPos().get(0) +
							min.getRoot().getTreeWidth()*FibNode.DISTANCE,
							nodePosY-FibNode.DISTANCE);
		}
		q.min.compObj.setPos(pos);
		q.min.fPos = pos;
		q.min.appear();
		if (!isEmpty()) {
			min.getRoot().makeRoomFor(q.min);
		}
		if (!mauda.Exercise.quickAnim)
			animate();
		if (textMode > 2)
			showText("Merging F-heaps",1);

		// FibHeap-Referenz -> FibNode
		q.min.setFibHeap(this);					

		if (!this.isEmpty() && !q.isEmpty()) {
			this.min.getRoot().join(q.min, false);
		} else {
			// Bei leerem Heap muss auf jeden Fall das Minimum
			// gesetzt werden, da nachfolgende Inserts sonst
			// nicht funktionieren würden!!!
			if (this.isEmpty()) updateMin(q.min);			
		}

		this.size += q.getHeapSize();
		this.potential += q.potential;
		count++;	// cost = 1 unit

		// this.transferItem();	Transfer ALL root nodes of other!!!!!!!

		animate();
	}
	public void removeOp(int node) {
		if(nodes[node].isRoot()) {
			remove(nodes[node]);
			nodes[node] = null;
		} else {
			// Delete ausführen, aber keine SubOperationen vermerken
			mauda.operation.SubOperationQueue soq = 
				(mauda.operation.SubOperationQueue)FibHeap.subOperations.clone();
			deleteOp(node);
			FibHeap.subOperations = soq;
		}
	}
	
	/*
	// Angabe: offset wird auf neue Breite addiert
	protected void updateRootListLine(int o) {
		double offset = ((double)o)*FibNode.DISTANCE;
		//System.out.print("*");
		double maxX = 0;
		for(int i=0; i<nodes.length; i++) {
			if(nodes[i]!=null) {
				DPair pos = nodes[i].getAbsPos(mainCompObj);
				if(pos.get(0)>maxX) maxX = pos.get(0);
				//System.out.print(pos.get(0)+" ");
			}
		}
		maxX += FibNode.DISTANCE;
		DPair newSize = new DPair(maxX+offset, 0.0);
		Path sizePath = new Path();
		sizePath.createDistance(rootList.getSize(), newSize, FibNode.MOVETIME);
		Trans sizeTrans = new Trans(rootList, sizePath, Trans.RESIZE);
		Jedas.getScheduler().add(sizeTrans);
		//rootList.setSize(newSize);
		//System.out.println();
	}*/
	
	// =========================================================
	// Alle Knoten des FHs zurückgeben
	public FibNode[] getAllNodes() {
		return nodes;
	}
	
	// Kopieren
	public Object copy() {
		FibHeapExt fibHeapCopy = (FibHeapExt)super.copy();
		//if(helpFibHeap!=null)
		//	fibHeapCopy.helpFibHeap = (FibHeapExt)helpFibHeap.copy(newScheduler);
		for(int i=0; i<maxKey; i++) {
			if(nodes[i]!=null) fibHeapCopy.nodes[i] = (FibNode)fibNodes.get(nodes[i]);
		}
		return fibHeapCopy;
	}
	
	/*
	 * ===================================================================
	 * Ab HIER:
	 * Kopieren des FibHeaps in die schnelle FibHeapDS-Struktur
	 * ===================================================================
	 */
	// Kompletten FibHeap kopieren	
	public Object copyDS() {
		FibHeapDSExt fibHeapCopy = (FibHeapDSExt)super.copyDS();
		for(int i=0; i<maxKey; i++) {
			if(nodes[i]!=null) fibHeapCopy.nodes[i] = (FibNodeDS)fibNodes.get(nodes[i]);
		}
		return fibHeapCopy;
	}
}
