package ckelling.baukasten;

import java.applet.*;
import java.awt.*;
import java.lang.*;
import java.util.*;
/* import java.io.*; */
import java.net.*;

// Versionsgeschichte
// 0.8.0  25.11.96
// 0.8.2  29.06.97

/**
 *	Adressierungsarten.java
 *
 *	Demonstration der Adressierungsarten á la MC 68000
 *
 *	@author		Carsten Kelling
 *	@version	0.8.2, 29.06.97
 */
public class Adressierungsarten extends Rechner
{
	///// Konstanten Anfang /////

    public final static String VERSIONSTRING = "Adressierungsarten 0.8.2";

	// moegliche Werte fuer c_state stehen nun
	// in Klasse "Rechner"

    public final static int	CONTROLHEIGHT	= 30;
    public final static int	ADDERWIDTH		= 20;

	///// Konstanten Ende /////


	private EditableMemory	ram;

	private Adder		adder;

	private SimpleBus		abus;
	private SimpleBus		dbus;
	private SimpleBus		iregToAdder;
	private SimpleBus[]		regToAdder;
	private SimpleBus		indexRegToAdder;

	private Adressierungsarten_Control	adressierungsarten_Control;
	private DescriptionLibrary			descriptionLibrary;
	private RTFTextArea				helpText;

	private Register16Split	ireg;
	private Register16		targetReg;
	private Register16[]	reg;
	private Register16		indexReg;

	private int				randomIreg;
	private int				randomReg;
	private int				randomIndexReg;
	private boolean 		randomFlag;
	public	boolean 		useRandomNumbers;

	private int				adderStartX;
	private int				adderStartY;
	private int				adderHeight;


	public String getAppletInfo()
	{
		return "Demonstration der Adressierungsarten a la MC 68000";
	}

	public String getVersionString()
	{
		return VERSIONSTRING;
	}

	public void init()
	{
		System.out.println(VERSIONSTRING);
		System.out.println("Initialisierung - Anfang");

		Point coord;
		//System.out.println("FontMetrics (Standard): " + getGraphics().getFontMetrics().toString());
		/**
		System.out.println("Event.MOUSE_MOVE: " + Integer.toString(Event.MOUSE_MOVE));
		System.out.println("Event.MOUSE_UP"     + Integer.toString(Event.MOUSE_UP));
		System.out.println("Event.MOUSE_DOWN"   + Integer.toString(Event.MOUSE_DOWN));
		System.out.println("Event.MOUSE_DRAG"   + Integer.toString(Event.MOUSE_DRAG));
		System.out.println("Event.MOUSE_ENTER"  + Integer.toString(Event.MOUSE_ENTER));
		System.out.println("Event.MOUSE_EXIT"   + Integer.toString(Event.MOUSE_EXIT));
		System.out.println("Event.ACTION_EVENT" + Integer.toString(Event.ACTION_EVENT));
		System.out.println("Event.GOT_FOCUS"    + Integer.toString(Event.GOT_FOCUS));
		System.out.println("Event.KEY_ACTION"   + Integer.toString(Event.KEY_ACTION));
		System.out.println("Event.KEY_ACTION_RELEASE"   + Integer.toString(Event.KEY_ACTION_RELEASE));
		System.out.println("Event.KEY_PRESS"    + Integer.toString(Event.KEY_PRESS));
		System.out.println("Event.KEY_RELEASE"  + Integer.toString(Event.KEY_RELEASE));
		*/

		initialize(new Dimension(590, 500), new Dimension(540, 380)); // defined in class Rechner

		PROGRAM = "3address";  // Parameter in HTML-Datei ignorieren
		useRandomNumbers = false;

		//ram = new SimpleMemory("Programm- und Datenspeicher", 10, 10, MEMORYSIZE, BITWIDTH, (Rechner) this);
		// Format: (<Bezeichner>, x, y, Speichergroesse, Bitbreite, Verweis auf Adressierungsarten)

		if (SMALLFONTSIZE <= 10)
			ram = new EditableMemory("Programm- und Datenspeicher", 10, 30, 8, 4,    MEMORYSIZE, BITWIDTH, (Rechner) this);
			// Format:              (Titel,                         x,  y,  Zellen x, Speichergroesse,      Verweis auf dieses Objekt)
			//                                                                 Zellen y,         Speicherbreite,
		else
			ram = new EditableMemory("Programm- und Datenspeicher", 10, 30, 8, 8,    MEMORYSIZE, BITWIDTH, (Rechner) this);

		ram.initRam(PROGRAM);
		ram.setOpcodesSupported(false);


	//// Busse ////
		coord = ram.getCoordinates("right");
		abus = new SimpleBus("Adreßbus", coord.x, coord.y, 150, 0, (Rechner) this);
		/**
		   Format: (<Bezeichner>, x1, y1, width, height, Referenz auf dieses Objekt um Farb-Konstanten benutzen zu können)
		   Hauptstrang des Busses verläuft von
		   (x1, y1) nach (x1 + width, y1 + height).
		*/
		abus.setLabelPosition("end", "top");
		/**
			Fuer horizontale Busse: (start/end, top/bottom); Standard: (start, top)
			Fuer vertikale Busse:	(left/right, start/end); Standard: (right, start)
		*/


		coord = ram.getCoordinates("bottom");

		dbus = new SimpleBus("Datenbus", coord.x, coord.y, 0, 187+LINEWIDTH, (Rechner) this);
		dbus.setLabelPosition("left", "start");

		//resetBus = new SimpleBus("Reset", coord.x + 50 - LINEWIDTH, coord.y, 0, 60, (Rechner) this);
		//resetBus.setLabelPosition("right", "start");

		dbus.addEdge("targetreg",  0, 90,  -20, 0);
		dbus.addEdge("ireg",       0, 37,   20, 0);
		dbus.addEdge("reg[1]",     0, 87,   20, 0);
		dbus.addEdge("reg[2]",     0, 137,  20, 0);
		dbus.addEdge("indexreg",   0, 187,  20, 0);
		/**
			Format: (<Bezeichner>, x3, y3, x4, y4)
			Eine Abzweigung vom Bus beginnt bei (x1+x3, y1+y3)
			und verläuft x4 Pixel nach rechts sowie y4 nach unten.
		*/


	//// Register ////
		coord = dbus.getCoordinates("targetReg", "end");
		targetReg = new Register16("Zielregister", coord.x, coord.y, "right", (Rechner) this);
		add(targetReg); targetReg.show();

		coord = dbus.getCoordinates("ireg", "end");
		ireg = new Register16Split("Befehlsregister", coord.x, coord.y, "left", (Rechner) this);
		add(ireg); ireg.show();
		ireg.setOpcodesSupported(false);

		reg = new Register16[3];
		reg[0] = null;
		coord = dbus.getCoordinates("reg[1]", "end");
		reg[1] = new Register16("Register 1", coord.x, coord.y, "left", (Rechner) this);
		add(reg[1]); reg[1].show();

		coord = dbus.getCoordinates("reg[2]", "end");
		reg[2] = new Register16("Register 2", coord.x, coord.y, "left", (Rechner) this);
		add(reg[2]); reg[2].show();

		coord = dbus.getCoordinates("indexreg", "end");
		indexReg = new Register16("Indexregister", coord.x, coord.y, "left", (Rechner) this);
		add(indexReg); indexReg.show();


	//// Busse 2 ////
		coord = abus.getCoordinates("start");
		int abusStartX = coord.x;
		int abusStartY = coord.y;

		coord = ireg.getCoordinates("right");
		coord.translate(-abusStartX, -abusStartY - LINEWIDTH*3/2);
		abus.addEdge("ireg", 30, 0, 0, coord.y, coord.x - 30, 0);

		coord = reg[1].getCoordinates("right");
		coord.translate(-abusStartX, -abusStartY - LINEWIDTH*3/2);
		abus.addEdge("reg[1]", 45, 0, 0, coord.y, coord.x - 45, 0);

		coord = reg[2].getCoordinates("right");
		coord.translate(-abusStartX, -abusStartY - LINEWIDTH*3/2);
		abus.addEdge("reg[2]", 60, 0, 0, coord.y, coord.x - 60, 0);

		coord = indexReg.getCoordinates("right");
		coord.translate(-abusStartX, -abusStartY - LINEWIDTH*3/2);
		abus.addEdge("indexreg", 75, 0, 0, coord.y, coord.x - 75, 0);

		coord = abus.getCoordinates("indexReg", "start");
		adderStartX = coord.x + 20;

		coord = ireg.getCoordinates("right");
		adderStartY = coord.y;
		iregToAdder = new SimpleBus("", coord.x, coord.y + LINEWIDTH/2, adderStartX - coord.x, 0, (Rechner) this);

		regToAdder = new SimpleBus[3];
		regToAdder[0] = new SimpleBus("", 0, 0, 0, 0, (Rechner) this);

		coord = reg[1].getCoordinates("right");
		regToAdder[1] = new SimpleBus("", coord.x, coord.y + LINEWIDTH/2, adderStartX - coord.x, 0, (Rechner) this);

		coord = reg[2].getCoordinates("right");
		regToAdder[2] = new SimpleBus("", coord.x, coord.y + LINEWIDTH/2, adderStartX - coord.x, 0, (Rechner) this);

		coord = indexReg.getCoordinates("right");
		adderHeight = coord.y - adderStartY + 2*Adder.CORNER_GAP;
		adder = new Adder("Addierer", adderStartX, adderStartY, ADDERWIDTH, adderHeight, "upperInput", (Rechner) this);
		indexRegToAdder = new SimpleBus("", coord.x, coord.y + LINEWIDTH/2, adderStartX - coord.x, 0, (Rechner) this);

		coord = abus.getCoordinates("end");
		int abusSizeX = coord.x - abusStartX - LINEWIDTH;
		coord = new Point(adderStartX + ADDERWIDTH, adderStartY + adderHeight/2);
		coord.translate(-abusStartX, -abusStartY);
		abus.addEdge("adderoutput", abusSizeX, 0, 0, coord.y, coord.x - abusSizeX, 0);


	//// Label ////
		//coord = abus.getCoordinates("address", "end");
		//address = new EditableLabel(coord.x, coord.y + 5, "left", (Rechner) this);
		//add(address); address.show();
		//address.setEditable(true);


		//alu = new ALU("ALU", coord.x, coord.y, "right", (Rechner) this);


	//// Connections ////
		// Den Bussen wird mitgeteilt, welche Komponenten an welchen Kanten angeschlossen sind;
		// bei einem bus.activate() kann der Bus dann den passenden Wert annehmen
		// und im InfoTip zeigen.

		abus.setConnection("start", ram, OUT);
		abus.setConnection("ireg", ireg, IN);
		abus.setConnection("reg[1]", reg[1], IN);
		abus.setConnection("reg[2]", reg[2], IN);
		abus.setConnection("indexreg", indexReg, IN);
		abus.setConnection("adderoutput", adder, IN);

		dbus.setConnection("start", ram, INOUT);
		dbus.setConnection("ireg", ireg, INOUT);
		dbus.setConnection("targetreg", targetReg, INOUT);
		dbus.setConnection("reg[1]", reg[1], INOUT);
		dbus.setConnection("reg[2]", reg[2], INOUT);
		dbus.setConnection("indexreg", indexReg, INOUT);

		iregToAdder.setConnection("start", ireg, IN);
		iregToAdder.setConnection("end", adder, OUT);

		regToAdder[1].setConnection("start", reg[1], IN);
		regToAdder[1].setConnection("end", adder, OUT);

		regToAdder[2].setConnection("start", reg[2], IN);
		regToAdder[2].setConnection("end", adder, OUT);

		indexRegToAdder.setConnection("start", indexReg, IN);
		indexRegToAdder.setConnection("end", adder, OUT);


		adressierungsarten_Control = new Adressierungsarten_Control(this);
		adressierungsarten_Control.setTitle("Ablauf steuern");
		//adressierungsarten_Control.pack();
		double faktor = SMALLFONTSIZE / (double) NORMALFONTSIZE;
		adressierungsarten_Control.resize((int) (280*faktor), (int) (480*faktor));

		coord = dbus.getCoordinates("end");
		helpText = new RTFTextArea(SMALLFONT, 4, 70);

		helpText.setText("Hier werden Hilfetexte erscheinen.");
		helpText.move(0, coord.y + 20);
		helpText.resize(WIDTH, HEIGHT - coord.y - 20);
		descriptionLibrary = new DescriptionLibrary();

		setLayout (new BorderLayout() );
		add("South", helpText);

		Rectangle bounds = bounds();
		//adressierungsarten_Control.move (bounds.x + bounds.width, bounds.y);

		System.out.println("Initialisierung - Ende");

		show();
		adressierungsarten_Control.show();
		helpText.show();

		c_state = n_state = ABSOLUT;

		randomIreg = 0;
		randomReg = 0;
		reg[1].setValue(0x10);
		reg[2].setValue(0x20);
		indexReg.setValue(0x30); randomIndexReg = 0x30;
		updateAll();
		deactivateAll();

		randomFlag = true;
		//erzeugt Zufallszahlen; genutzt werden diese aber evtl. erst durch
		//useRandomNumbers = true

		versionStringX = WIDTH - stringWidth(DIALOGFONT, VERSIONSTRING) - 5;

		paint(onScreenGC);
} /* end init */


	public void stop()
	{
		super.stop();  // Alle Threads anhalten und beseitigen

		adressierungsarten_Control.hide();
	}

	public void start()
	{
		super.start();  // Alle Threads erzeugen und starten

		Rectangle bounds = bounds();
		Rectangle bbounds = adressierungsarten_Control.bounds();
		int x = Math.min(bounds.x + bounds.width, screenSize.width - bbounds.width);
		adressierungsarten_Control.move(x, bounds.y);
		adressierungsarten_Control.show();
	}


	/**
		this method is called when repaint of the panel is requested
	*/

	public synchronized void paint (Graphics onScreenGC)
	{
		Graphics g = offScreenGC;
		if (g == (Graphics) null)
			System.out.println("Oh Gott! paint(Graphics) wurde vor init() aufgerufen!");

		Rectangle size = bounds();

		// Flaeche des Applets loeschen
		g.setColor (BACKGROUND);
		g.fillRect(0, 0, size.width, size.height);

		// Komponenten neu zeichnen
		paintComponents(g);

		g.setColor(Color.black);

		String plus = new String("+");
		//int labelHeight = getHeight(g);
		int labelWidth = stringWidth(DIALOGFONT, plus);

		g.drawString(VERSIONSTRING, versionStringX, 10);

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end paint */

	public synchronized void paintComponents (Graphics g)
	{
		ram.			paint(g);

		adder.		paint(g);

		abus.			paint(g);
		dbus.			paint(g);
		iregToAdder.	paint(g);
		regToAdder[1].	paint(g);
		regToAdder[2].	paint(g);
		indexRegToAdder.paint(g);

		targetReg.		paint(g);
		ireg.			paint(g);
		reg[1].			paint(g);
		reg[2].			paint(g);
		indexReg.		paint(g);

		helpText.		repaint();
	} /* end paintComponents */

	public synchronized void paintActivated (Graphics onScreenGC)
	{
		Graphics g = offScreenGC;

		ram.			paintActivated(g);

		adder.		paintActivated(g);

		abus.			paintActivated(g);
		dbus.			paintActivated(g);
		iregToAdder.	paintActivated(g);
		regToAdder[1].	paintActivated(g);
		regToAdder[2].	paintActivated(g);
		indexRegToAdder.paintActivated(g);

		targetReg.		paintActivated(g);
		ireg.			paintActivated(g);
		reg[1].			paintActivated(g);
		reg[2].			paintActivated(g);
		indexReg.		paintActivated(g);

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end paintActivated */

	public void deactivateAll()
	{
		ram.			deactivate();

		adder.		deactivate();

		abus.			deactivate();
		dbus.			deactivate();
		iregToAdder.	deactivate();
		regToAdder[1].	deactivate();
		regToAdder[2].	deactivate();
		indexRegToAdder.deactivate();

		targetReg.		deactivate();
		ireg.			deactivate();
		reg[1].			deactivate();
		reg[2].			deactivate();
		indexReg.		deactivate();
	} /* end deactivateAll */


	public synchronized void scrollAll()
	{
		abus.			scroll();
		dbus.			scroll();
		iregToAdder.	scroll();
		regToAdder[1].	scroll();
		regToAdder[2].	scroll();
		indexRegToAdder.scroll();

		abus.			paintActivated(offScreenGC);
		dbus.			paintActivated(offScreenGC);
		iregToAdder.	paintActivated(offScreenGC);
		regToAdder[1].	paintActivated(offScreenGC);
		regToAdder[2].	paintActivated(offScreenGC);
		indexRegToAdder.paintActivated(offScreenGC);

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end scrollAll */


	/**
	 *  Alle Komponenten, die zwischen ihrem eigentlichem Wert (value)
	 *  und dem gerade sichtbaren Wert (displayValue) unterscheiden,
	 *  führen ein "displayValue = value" durch.
	 *  Wird stets von deactivateAll() gefolgt.
	 */
	public void updateAll()
	{
		ram.updateAll();

		adder.activate();

		targetReg.activate();
		ireg.     activate();
		reg[1].   activate();
		reg[2].   activate();
		indexReg. activate();

		//alu.activate();
	} /* end updateAll */


	public synchronized void invalidateAllImageCaches()
	{
		ram.			invalidateImageCache();

		abus.			invalidateImageCache();
		dbus.			invalidateImageCache();
		iregToAdder.	invalidateImageCache();
		regToAdder[1].	invalidateImageCache();
		regToAdder[2].	invalidateImageCache();
		indexRegToAdder.invalidateImageCache();

	} /* end invalidateAllImageCaches */


	public void showInfoTip(Point p)
	{
		if (infoTipLabel == null)
			return;

		String itt = "";
		//Color bg = MEDIUM_GREY;
		Color bg = Color.yellow;

		if (abus.intersectsWith(p))
			itt = "Adreßbus: " + abus.getInfoTipText(p);
		else if (dbus.intersectsWith(p))
			itt = "Datenbus: " + dbus.getInfoTipText(p);
		else if (iregToAdder.intersectsWith(p))
			itt = iregToAdder.getInfoTipText(p);
		else if (regToAdder[1].intersectsWith(p))
			itt = regToAdder[1].getInfoTipText(p);
		else if (regToAdder[2].intersectsWith(p))
			itt = regToAdder[2].getInfoTipText(p);
		else if (indexRegToAdder.intersectsWith(p))
			itt = indexRegToAdder.getInfoTipText(p);
		else if (ireg.intersectsWith(p))
			itt = "Befehlsregister : " + ireg.getInfoTipText(p);
		else if (targetReg.intersectsWith(p))
			itt = "Zielregister: " + targetReg.getInfoTipText(p);
		else if (reg[1].intersectsWith(p))
			itt = "Register 1: " + reg[1].getInfoTipText(p);
		else if (reg[2].intersectsWith(p))
			itt = "Register 2: " + reg[2].getInfoTipText(p);
		else if (indexReg.intersectsWith(p))
			itt = "Indexregister: " + indexReg.getInfoTipText(p);
		else if (adder.intersectsWith(p))
			itt = "Addierer: " + adder.getInfoTipText(p);
		else if (ram.intersectsWith(p))
		{
			String ritt = ram.getInfoTipText(p);
			if (! ritt.equals(""))
				itt = "Programm- und Datenspeicher: " + ritt;
		}

		//if (itt.equals(""))
		//	itt = "Zeigen Sie auf eine Komponente";
		//else
		//	bg = Color.yellow;

		int stringWidth = stringWidth(SMALLFONT, itt);
		int gap = 16;
		if (p.x + gap + stringWidth > bounds().width)
			p = new Point(p.x - stringWidth - (3*gap)/2, p.y);
		if (p.y + SMALLFONTHEIGHT > bounds().height)
			p = new Point(p.x, p.y - SMALLFONTHEIGHT);

		symantec.itools.awt.InfoTipManager.draw(p.x + gap, p.y, itt, SMALLFONTMETRICS, bg, Color.black);
		Rectangle b = infoTipPanel.bounds();
		infoTipLabel.setText(itt);
		infoTipLabel.reshape(0, 0, b.width, b.height);
		infoTipLabel.setBackground(bg);

	} /* end showInfoTip */

	public void showAllOpcodes(boolean b)
	{
		showOpcodes = b;
		ram.	showOpcodes(b);

		paint(onScreenGC);
	}


	public synchronized void timerWokeUp(String title)
	{
		if (title.equalsIgnoreCase("blinktimer"))
		{
		    blinker = !blinker;

			ram.		blink(blinker);

			targetReg.	blink(blinker);
			ireg.		blink(blinker);
			reg[1].		blink(blinker);
			reg[2].		blink(blinker);
			indexReg.	blink(blinker);

		    onScreenGC.drawImage(offScreenImage, 0, 0, this);
		}
		// else if (title.equalsIgnoreCase("dotMover")) ...
		else
			super.timerWokeUp(title);

	} /* end timerWokeUp */


	public void stopSimulation()
	{
		demonstrationReady = true;
		c_state = n_state = ABSOLUT;

		targetReg.setValue(0);
		ireg.setValue(0);
		reg[1].setValue(0);
		reg[2].setValue(0);
		indexReg.setValue(0);
		//alu.calculate(ADD_MEM, 0, 0, true);
		ram.initRam(PROGRAM);

		helpText.setText(descriptionLibrary.helpText_Adressierungsarten(c_state, 1) );

		updateAll();
		deactivateAll();
		paint(onScreenGC);
	} /* end stopSimulation */


	public void goUntilBreakpoint()
	// ">> BP"
	{
	}

	public void singleInstruction(boolean doRepaint)
	// ">>"
	{
	}

	public void singleInstructionBack(boolean doRepaint)
	// "<<"
	{
	}

	public synchronized void bufferComputer()
	{
		Vector v = new Vector(6);

		v.addElement(ram.getAllValues());

		v.addElement(new Integer(targetReg.getValue()));
		v.addElement(new Integer(ireg.getValue()));
		v.addElement(new Integer(reg[1].getValue()));
		v.addElement(new Integer(reg[2].getValue()));
		v.addElement(new Integer(indexReg.getValue()));

		simBuffer[simBufferTop] = v;

		simBufferTop = (simBufferTop+1) % SIM_BUFFER_SIZE;
		if (simBufferTop == simBufferBottom)
			simBufferBottom = (simBufferBottom+1) % SIM_BUFFER_SIZE;

	} /* end bufferComputer */

	public synchronized void setComputer()
	{
		if (simBufferTop == simBufferBottom)
			System.out.println("'<' oder '<<': Keine weiteren Arbeitsschritte mehr gespeichert!");
		else
		{
			simBufferTop--;
			if (simBufferTop == -1)
				simBufferTop = SIM_BUFFER_SIZE - 1;
			// System.out.println("setComputer - simBufferTop = " + simBufferTop);

			Vector v = simBuffer[simBufferTop];

			ram.setValue((int[]) v.elementAt(0));

			targetReg.setValue( ((Integer) v.elementAt(1)).intValue() );
			ireg.     setValue( ((Integer) v.elementAt(2)).intValue() );
			reg[1].   setValue( ((Integer) v.elementAt(3)).intValue() );
			reg[2].   setValue( ((Integer) v.elementAt(4)).intValue() );
			indexReg. setValue( ((Integer) v.elementAt(5)).intValue() );
		}
	} /* end setComputer */

	public void singleStep(boolean doRepaint)
	// ">"
	{
		System.out.println("singleStep: " + c_state + "/" + n_state);
		if (demonstrationReady == true)
		{
			if (doRepaint == true)
			{
				deactivateAll();
				helpText.setText(descriptionLibrary.helpText_Adressierungsarten(c_state, 99) );
				paint(onScreenGC);
			}

			c_state = n_state;
			int i;
			String s = new String("");

			ireg.setValue(c_state * 256);

			switch (c_state)
			{
				case ABSOLUT:
					System.out.println("--Absolut");
					bufferComputer();

					if (randomFlag == true)
				  	randomIreg = (int) (Math.random() * 256);
					i = ireg.getValue() / 256;
					ireg.setValue(i * 256 + randomIreg);

					targetReg.setValue(ireg.getValue() & 255);
					break;

				case UNMITTELBAR:
					System.out.println("--Unmittelbar");
					bufferComputer();

					if (randomFlag == true)
				  	randomIreg = (int) (Math.random() * ram.getMemorySize());
					i = ireg.getValue() / 256;
					ireg.setValue(i * 256 + randomIreg);

					ram.setAddress(ireg.getValue() & 255);
					targetReg.setValue(ram.getValue());
					break;

				case REG_DIREKT:
					System.out.println("--Register direkt");
					bufferComputer();

					if (randomFlag == true)
						randomIreg = (int) (Math.random()*2 + 1);
					if (randomIreg > 2)
						randomIreg = 1;
					i = ireg.getValue() / 256;
					ireg.setValue(i * 256 + randomIreg);

					targetReg.setValue( reg[ireg.getValue() & 255].getValue() );
					break;

				case REG_INDIR:
					s = new String(" ");
				case REG_INDIR_PI:
					if (s.equals(""));
						s = new String("Post-Inkrement");
				case REG_INDIR_PD:
					if (s.equals(""));
						s = new String("Prä-Dekrement");
				case REG_INDIR_O:
					if (s.equals(""));
						s = new String("mit Offset");
				case REG_INDIR_OI:
					if (s.equals(""));
						s = new String("mit Offset und Index");

					System.out.println("--Register indirekt " + s);

					bufferComputer();

					if (randomFlag == true)
					{
						if ((c_state == REG_INDIR_O) || (c_state == REG_INDIR_OI))
						{
							randomIreg = (int) (Math.random()*2 + 1) + ((int) (Math.random()*15 + 1))*16;
							randomIndexReg = (int) (Math.random()*30 + 1);
							randomReg = (int) (Math.random()*16 + 1);
						}
						else
							randomIreg = (int)   (Math.random()*2 + 1);
					}

					i = ireg.getValue() / 256;
					ireg.setValue(i * 256 + randomIreg);

					i = ireg.getValue() & 3;

					if (c_state == REG_INDIR_O)
					{
						indexReg.setValue(randomIndexReg);
					}
					else if (c_state == REG_INDIR_OI)
					{
						indexReg.setValue(randomIndexReg);
						reg[i].setValue(randomReg);
					}

					if (c_state == REG_INDIR_PD)
						reg[i].setValue( reg[i].getValue() - 1 );

					int j = reg[i].getValue();
					if (c_state == REG_INDIR_O)
						j = adder.add(j, (ireg.getValue() & 252)/16);
					if (c_state == REG_INDIR_OI)
						j = adder.add(j, indexReg.getValue());

					ram.setAddress(j);
					targetReg.setValue(ram.getValue());
					break;

				case MEM_INDIR:
					System.out.println("--Speicher indirekt");
					bufferComputer();

					if (randomFlag == true)
						randomIreg = (int) (Math.random() * ram.getMemorySize());

					i = ireg.getValue() / 256;
					ireg.setValue(i * 256 + randomIreg);
					ram.setAddress(ireg.getValue() & 255);
					indexReg.setValue(ram.getValue());

					i = indexReg.getValue() & 255;
					if (i < 0)
						i = i + (int) (Math.pow(2, (double) BITWIDTH-1));
					i = i % ram.getMemorySize();
					ram.setAddress(i);
					targetReg.setValue(ram.getValue());
					break;

				default:
					System.out.println("     --- Unbekannte Vorgehensweise! ---");
					c_state = UNKNOWN_COMMAND;
					n_state = ABSOLUT;
					demonstrationReady = true;
					break;
			}
		}
	} /* end singleStep */


	public void demonstrate()
	{
		demonstrate(true);
	}

	public void demonstrate(boolean doRepaint)
	{
		if (demonstrationReady == true)
		{
			demonstrationReady = false;
			demonstrationStep = 1;
			System.out.println("- ready");
		}
		else
		{
			System.out.println("- " + demonstrationStep);

			int i;

			switch (c_state)
			{
				case ABSOLUT:
					switch (demonstrationStep)
					{
						case 1:
							ireg.activate(1);
							break;
						case 2:
							dbus.activate("ireg", "targetreg");
							break;
						case 3:
							targetReg.activate();
							demonstrationReady = true;
					}
					break;
				case UNMITTELBAR:
					switch (demonstrationStep)
					{
						case 1:
							ireg.activate(1);
							break;
						case 2:
							abus.activate("ireg", "start");
							break;
						case 3:
							ram.activate();
							break;
						case 4:
							dbus.activate("start", "targetreg");
							break;
						case 5:
							targetReg.activate();
							demonstrationReady = true;
					}
					break;
				case REG_DIREKT:
					switch (demonstrationStep)
					{
						case 1:
							ireg.activate(1);
							break;
						case 2:
							reg[ ireg.getValue() & 255 ].activate();
							break;
						case 3:
						  if ((ireg.getValue() & 255) == 1)
						  	dbus.activate("reg[1]", "targetreg");
						  else
						  	dbus.activate("reg[2]", "targetreg");
							break;
						case 4:
							targetReg.activate();
							demonstrationReady = true;
					}
					break;
				case REG_INDIR:
				case REG_INDIR_PI:
				case REG_INDIR_PD:
				case REG_INDIR_O:
				case REG_INDIR_OI:
					switch (demonstrationStep)
					{
						case 1:
							ireg.activate(1);
							break;
						case 2:
							reg[ ireg.getValue() & 3 ].activate();
							break;
						case 3:
							i = ireg.getValue() & 3;

							if (c_state == REG_INDIR_O)
							{
								iregToAdder.activate("start", "end");
								regToAdder[i].activate("start", "end");
								adder.activate();
								abus.activate("adderoutput", "start");
							}
							else if (c_state == REG_INDIR_OI)
							{
								iregToAdder.activate("start", "end");
								regToAdder[i].activate("start", "end");
								indexReg.activate();
								indexRegToAdder.activate("start", "end");
								adder.activate();
								abus.activate("adderoutput", "start");
							}
							else if (i == 1)
								abus.activate("reg[1]", "start");
							else
								abus.activate("reg[2]", "start");
							break;
						case 4:
							ram.activate();
							break;
						case 5:
							dbus.activate("start", "targetreg");
							break;
						case 6:
							targetReg.activate();
							if (c_state != REG_INDIR_PI)
								demonstrationReady = true;
							break;
						case 7:
							deactivateAll();
							paint(onScreenGC);
							i = ireg.getValue() & 3;
							reg[i].setValue(reg[i].getValue() + 1);
							reg[i].activate();
							demonstrationReady = true;
					}
					break;
				case MEM_INDIR:
					switch (demonstrationStep)
					{
						case 1:
							ireg.activate(1);
							break;
						case 2:
							abus.activate("ireg", "start");
							break;
						case 3:
							ram.setAddress(ireg.getValue() & 255);
							ram.activate();
							break;
						case 4:
							dbus.activate("start", "indexReg");
							break;
						case 5:
							indexReg.activate();
							break;
						case 6:
							deactivateAll();
							paint(onScreenGC);
							indexReg.activate();
							abus.activate("indexreg", "start");
							break;
						case 7:
							i = indexReg.getValue() & 255;
							if (i < 0)
								i = i + (int) (Math.pow(2, (double) BITWIDTH-1));
							i = i % ram.getMemorySize();
							ram.setAddress(i);
							ram.activate();
							break;
						case 8:
							dbus.activate("start", "targetreg");
							break;
						case 9:
							targetReg.activate();
							demonstrationReady = true;
					}
					break;
				case UNKNOWN_COMMAND:
					demonstrationReady = true;
				default:
					break;
			}
			if (doRepaint == true)
			{
				helpText.setText(descriptionLibrary.helpText_Adressierungsarten(c_state, demonstrationStep) );
				helpText.repaint();
			}

			demonstrationStep++;
		}
	} /* end demonstrate */

	public synchronized void demonstrateBack()
	{
		if (demonstrationStep > 1)
		{
			setComputer();

			// System.out.println("--demonstrateBack()");
			updateAll();
			deactivateAll();
			//for (int i = 0; i < 300; i++)
			//{
			//	onScreenGC.drawLine(5, 5, 100, i);
			//	onScreenGC.drawLine(5, 5+i, 100, 0);
			//}
			paintComponents(offScreenGC);
			//for (int i = 0; i < 300; i++)
			//{
			//	onScreenGC.drawLine(300, 5, 100, i);
			//	onScreenGC.drawLine(300, 5+i, 100, 0);
			//}

			demonstrationReady = true;
			randomFlag = false;
			int old_n_state = n_state;
			n_state = c_state;
			singleStep(false);
			n_state = old_n_state;
			randomFlag = true;

			int ds = demonstrationStep - 1;
			demonstrationStep = 1;
			demonstrationReady = false;

			while (demonstrationStep < ds-1)
			{
				demonstrate(false);
				// do not perform any drawing
			}
			if (ds > 1)
			    demonstrate(true);
			else
    			helpText.setText("\nBitte drücken Sie '>'.");
			paintActivated(onScreenGC);
		}
	} /* end demonstrateBack */

	public int getDemonstrationStep()
	{
		return demonstrationStep;
	}

	public void initCacheComponents(int cSize, int tSize, int assoc) {}
	public void removeCacheRessources() {}

	public void showWindow(String name) {}
	public void hideWindow(String name) {}

	//{{DECLARE_CONTROLS
	//}}
} /* end Adressierungsarten */


