package ckelling.baukasten;

import java.awt.*;
import java.lang.*;
import java.util.*;


// Versionsgeschichte
// 0.8.0  Bild der ALU ist skalier- und rotierbar
// 0.8.1  16.02.97
// 0.8.2  18.05.97
// 0.8.3  28.07.97
// 0.8.4  01.08.97

/**
 *	Führt diverse arithmetische und logische Berechnungen
 *  mit einem oder zwei Operanden
 *  durch und zeichnet das Symbol einer ALU
 *	inklusive Operanden, Operator, Resultat und flags.
 *  Das Bild der ALU ist in Schritten von 90 Grad skalier- und rotierbar,
 *  Operanden, Operator, Resultat und flags sind aber nur bei
 *  "V"-ähnlicher ALU sichtbar.
 *
 *	@author		Carsten Kelling
 *	@version	0.8.4, 01.08.97
 */
public class ALU extends RechnerKomponente
{
	//// Konstanten Anfang ////

    public final static int	DEFAULT_WIDTH_HOR = 3*48;  // Standardmaße bei "v" oder "^"
    public final static int	DEFAULT_HEIGHT_HOR = 2*40;
	protected Point		BASE;

    public final static int LEFT	= 1;
    public final static int RIGHT	= 2;
    public final static int BOTTOM = 3;

	//// Konstanten Ende ////


	protected int	ZWEI_HOCH_BITWIDTH = (int) Math.pow(2, (double) Register16.BITWIDTH);
	protected String	grabMode;

	protected String	label;
	protected int 	calculatingMode;

	protected Point   grounds;
	protected int		width;
	protected int		height;
	protected Point	input1;
	protected Point	input2;
	protected Point	output;
	protected Point	upperLeft;
	protected int		labelX;
	protected int		labelHeight;

	protected String	operator;
	protected int 	op1, displayOp1;
	protected int 	op2, displayOp2;
	protected int 	result, displayResult;

	protected boolean zeroFlag, displayZeroFlag;
	protected boolean lessFlag, displayLessFlag;

	protected boolean hasBeenActivated;

	protected Point[] umriss;
	protected String orientation;

	protected boolean blinker;

	protected Rechner parent;
	
	protected Font	  aluFont;


	/**
	 *  Erzeugt eine ALU mit Standardhöhe und -breite.
	 *
	 *  @param str Titel der ALU
	 *  @param grabMode Bestimmt, auf welchen Punkt der Komponente sich (x, y) bezieht.
	 *  @see #getPossibleQualifiers
	 */
	public ALU (String str, int x, int y, String grabMode, Rechner par)
	{
		this(str, x, y, DEFAULT_WIDTH_HOR, DEFAULT_HEIGHT_HOR, grabMode, "v", par);
	}

	/**
	 *  @param str Titel der ALU
	 *  @param grabMode Bestimmt, auf welchen Punkt der Komponente sich (x, y) bezieht.
	 *  @param orientation Ausrichtung der ALU: "v", "^", ">" oder "<"
	 *  @see #getPossibleQualifiers
	 *  @see #setOrientation
	 */
	public ALU (String str, int x, int y, int width, int height, String grabMode, String orientation, Rechner par)
	{
		parent = par;
		label = str;
		this.orientation = orientation;

		calculatingMode = Rechner.ADD_MEM;
		operator = new String("+");
		activated = false;
		hasBeenActivated = false;

		op1 = displayOp1 = 0;
		op2 = displayOp2 = 0;
		result = displayResult = 0;

		zeroFlag = false;
		lessFlag = false;

		blinker = false;
		
		if (parent.SMALLFONTSIZE <= 10)
			aluFont = parent.SMALLDIALOGFONT;
		else
			aluFont = parent.DIALOGFONT;
			

		reshape(x, y, width, height, grabMode);
	} /* end ALU */


	public void reshape(int x, int y, int width, int height)
	{
		reshape(x, y, width, height, grabMode);
	}

	/**
	 *  @param newGrabMode Bestimmt, auf welchen Punkt der Komponente sich (x, y) bezieht
	 *  @see #getPossibleQualifiers
	 */
	public void reshape(int x, int y, int width, int height, String newGrabMode)
	{
		grounds = new Point(x, y);
		this.width = width;
		this.height = height;

		if (orientation.equalsIgnoreCase("v") || orientation.equals("^"))
			BASE = new Point(width / 3, height / 2);
		else  // ">" oder "<"
			BASE = new Point(width / 2, height / 3);

		setCoordinates(x, y, newGrabMode);
	}

	/**
	 *  Verschiebt die Komponente an den Punkt (x, y);
	 *  (x, y) muß dabei nicht notwendigerweise von der linken, oberen
	 *  Ecke der Komponente eingenommen werden, sondern kann z.B. auch von der Mitte
	 *  ihres rechten Randes oder dem Ausgang (bei einer ALU) eingenommen werden.
	 *
	 *  @param grabMode Bestimmt, auf welchen Punkt der Komponente sich (x, y) bezieht.
	 *  @see #getPossibleQualifiers
	 *  @see #getCoordinates
	 */
	public void setCoordinates(int x, int y, String grabMode)
	{
		this.grabMode = grabMode;

		umriss = new Point[8];
		if (orientation.equals("<"))
		{
			if ( grabMode.equalsIgnoreCase("upper") || grabMode.equalsIgnoreCase("upperInput") )
			{
				input1 = new Point(x, y);
				input2 = new Point(x, y + 2*BASE.y);
				output = new Point(x - 2*BASE.x, y + BASE.y);
				upperLeft = new Point(x - 2*BASE.x, y - BASE.y/2);
			}
			else if ( grabMode.equalsIgnoreCase("lower") || grabMode.equalsIgnoreCase("lowerInput") )
			{
				input1 = new Point(x, y - 2*BASE.y);
				input2 = new Point(x, y);
				output = new Point(x - 2*BASE.x, y - BASE.y);
				upperLeft = new Point(x - 2*BASE.x, y - (5*BASE.y)/2);
			}
			else if (grabMode.equalsIgnoreCase("output"))
			{
				input1 = new Point(x + 2*BASE.x, y - BASE.y);
				input2 = new Point(x + 2*BASE.x, y + BASE.y);
				output = new Point(x, y);
				upperLeft = new Point(x, y - (3*BASE.y)/2);
			}
			else  // "leftTop"
			{
				input1 = new Point(x + 2*BASE.x, y + BASE.y/2);
				input2 = new Point(x + 2*BASE.x, y + (5*BASE.y)/2);
				output = new Point(x, y + (3*BASE.y)/2);
				upperLeft = new Point(x, y);
			}
			umriss[0] = new Point(2*BASE.x, 0);  // Zeichnen rechts oben beginnen
			umriss[1] = new Point(-2*BASE.x, BASE.y);
			umriss[2] = new Point(0        , BASE.y);
			umriss[3] = new Point(2*BASE.x , BASE.y);
			umriss[4] = new Point(0        , -BASE.y);
			umriss[5] = new Point(-BASE.x  , -BASE.y/2);
			umriss[6] = new Point(BASE.x   , -BASE.y/2);
			umriss[7] = new Point(0        , -BASE.y);
		}
		else if (orientation.equals(">"))
		{
			if ( grabMode.equalsIgnoreCase("upper") || grabMode.equalsIgnoreCase("upperInput") )
			{
				input1 = new Point(x, y);
				input2 = new Point(x, y + 2*BASE.y);
				output = new Point(x + 2*BASE.x, y + BASE.y);
				upperLeft = new Point(x, y - BASE.y/2);
			}
			else if ( grabMode.equalsIgnoreCase("lower") || grabMode.equalsIgnoreCase("lowerInput") )
			{
				input1 = new Point(x, y - 2*BASE.y);
				input2 = new Point(x, y);
				output = new Point(x + 2*BASE.x, y - BASE.y);
				upperLeft = new Point(x, y - (5*BASE.y)/2);
			}
			else if (grabMode.equalsIgnoreCase("output"))
			{
				input1 = new Point(x - 2*BASE.x, y - BASE.y);
				input2 = new Point(x - 2*BASE.x, y + BASE.y);
				output = new Point(x, y);
				upperLeft = new Point(x - 2*BASE.x, y - (3*BASE.y)/2);
			}
			else  // "leftTop"
			{
				input1 = new Point(x, y + BASE.y/2);
				input2 = new Point(x, y + (5*BASE.y)/2);
				output = new Point(x + 2*BASE.x, y + (3*BASE.y)/2);
				upperLeft = new Point(x, y);
			}
			umriss[0] = new Point(0        , 0);  // Zeichnen links oben beginnen
			umriss[1] = new Point(2*BASE.x , BASE.y);
			umriss[2] = new Point(0        , BASE.y);
			umriss[3] = new Point(-2*BASE.x, BASE.y);
			umriss[4] = new Point(0        , -BASE.y);
			umriss[5] = new Point(BASE.x   , -BASE.y/2);
			umriss[6] = new Point(-BASE.x  , -BASE.y/2);
			umriss[7] = new Point(0        , -BASE.y);
		}
		else if (orientation.equals("^"))
		{
			if ( grabMode.equalsIgnoreCase("left") || grabMode.equalsIgnoreCase("leftInput") )
			{
				input1 = new Point(x, y);
				input2 = new Point(x + 2*BASE.x, y);
				output = new Point(x + BASE.x, y - 2*BASE.y - 2);
				// "-2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				upperLeft = new Point(x - BASE.x/2, y - 2*BASE.y - 2);
			}
			else if ( grabMode.equalsIgnoreCase("right") || grabMode.equalsIgnoreCase("rightInput") )
			{
				input1 = new Point(x - 2*BASE.x, y);
				input2 = new Point(x, y);
				output = new Point(x - BASE.x, y - 2*BASE.y - 2);
				// "-2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				upperLeft = new Point(x - (5*BASE.x)/2, y - 2*BASE.y - 2);
			}
			else if (grabMode.equalsIgnoreCase("output"))
			{
				input1 = new Point(x - BASE.x, y + 2*BASE.y + 2);
				// "+2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				input2 = new Point(x + BASE.x, y + 2*BASE.y + 2);
				output = new Point(x, y);
				upperLeft = new Point(x - (3*BASE.x)/2, y);
			}
			else  // "leftTop"
			{
				input1 = new Point(x + BASE.x/2, y + 2*BASE.y);
				input2 = new Point(x + (5*BASE.x)/2, y + 2*BASE.y);
				output = new Point(x + (3*BASE.x)/2, y);
				upperLeft = new Point(x, y);
			}
			umriss[0] = new Point(0       , 2*BASE.y);  // Zeichnen links unten beginnen
			umriss[1] = new Point(BASE.x  , 0);
			umriss[2] = new Point(BASE.x/2, -BASE.y);
			umriss[3] = new Point(BASE.x/2, BASE.y);
			umriss[4] = new Point(BASE.x  , 0);
			umriss[5] = new Point(-BASE.x , -BASE.y*2);
			umriss[6] = new Point(-BASE.x , 0);
			umriss[7] = new Point(-BASE.x , BASE.y*2);
		}
		else  // "v"
		{
			orientation = new String("v");
			if ( grabMode.equalsIgnoreCase("left") || grabMode.equalsIgnoreCase("leftInput") )
			{
				input1 = new Point(x, y);
				input2 = new Point(x + 2*BASE.x, y);
				output = new Point(x + BASE.x, y + 2*BASE.y + 2);
				// "+2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				upperLeft = new Point(x - BASE.x/2, y);
			}
			else if ( grabMode.equalsIgnoreCase("right") || grabMode.equalsIgnoreCase("rightInput") )
			{
				input1 = new Point(x - 2*BASE.x, y);
				input2 = new Point(x, y);
				output = new Point(x - BASE.x, y + 2*BASE.y + 2);
				// "+2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				upperLeft = new Point(x - (5*BASE.x)/2, y);
			}
			else if (grabMode.equalsIgnoreCase("output"))
			{
				input1 = new Point(x - BASE.x, y - 2*BASE.y - 2);
				// "-2", weil die Linien der Umrandung vertikal doppelt gezeichnet werden
				input2 = new Point(x + BASE.x, y - 2*BASE.y - 2);
				output = new Point(x, y);
				upperLeft = new Point(x - (3*BASE.x)/2, y - 2*BASE.y - 2);
			}
			else  // "leftTop"
			{
				input1 = new Point(x + BASE.x/2, y);
				input2 = new Point(x + (5*BASE.x)/2, y);
				output = new Point(x + (3*BASE.x)/2, y + 2*BASE.y);
				upperLeft = new Point(x, y);
			}
			umriss[0] = new Point(0       , 0);  // Zeichnen links oben beginnen
			umriss[1] = new Point(BASE.x  , 0);
			umriss[2] = new Point(BASE.x/2, BASE.y);
			umriss[3] = new Point(BASE.x/2, -BASE.y);
			umriss[4] = new Point(BASE.x  , 0);
			umriss[5] = new Point(-BASE.x , BASE.y*2);
			umriss[6] = new Point(-BASE.x , 0);
			umriss[7] = new Point(-BASE.x , -BASE.y*2);
		}

		labelX = upperLeft.x + BASE.x + (BASE.x - parent.stringWidth(aluFont, label))/2;
		labelHeight = parent.getHeight(aluFont);

	} /* end setCoordinates */


	/**
	 * Dreht das Bild der ALU.
	 *
	 * @param orientation Ausrichtung der ALU: "v", "^", ">" oder "<"
	 */
	public void setOrientation(String o)
	{
		if ( (o != null) &&
		     (o.equalsIgnoreCase("v") || o.equals("^") || o.equals("<") || o.equals(">")) )
		{
			this.orientation = o.toLowerCase();
			reshape(grounds.x, grounds.y, width, height);
		}
	}

	public Rectangle bounds()
	{
		return new Rectangle(upperLeft.x, upperLeft.y, width, height);
	}


	public void paint (Graphics g)
	{
		g.setColor(parent.BACKGROUND);
		
		if (orientation.equals("v") || orientation.equals("^"))
			g.fillRect(upperLeft.x, upperLeft.y, 3*BASE.x, 2*BASE.y);
		else
			g.fillRect(upperLeft.x, upperLeft.y, 2*BASE.x, 3*BASE.y);

		// Zeichnen des Umrisses
		if (activated)
			g.setColor(parent.ALU_COLOR_ACTIVATED);
		else
			g.setColor(parent.ALU_COLOR);
		int ax = upperLeft.x + umriss[0].x;
		int ay = upperLeft.y + umriss[0].y;
		int bx;
		int by;
		for (int i = 1; i < 8; i++)
		{
			bx = ax + umriss[i].x;
			by = ay + umriss[i].y;
			g.drawLine(ax, ay,   bx, by  );
			g.drawLine(ax, ay+1, bx, by+1);
			g.drawLine(ax+1, ay, bx+1, by);
			ax = bx;
			ay = by;
		}

		if (orientation.equals("v"))
		// nur solche ALUs zeigen Operator etc. an.
		{
			g.setFont(aluFont);
			
			String displayFlags;  // Ausgabe der Flags (noch in Schwarz)
			if (displayZeroFlag == true)
			{
				if (displayLessFlag == true)
					displayFlags = new String("?");
				else
					displayFlags = new String("=0");
			}
			else
			{
				if (displayLessFlag == true)
					displayFlags = new String("<0");
				else
					displayFlags = new String(">0");
			}

			g.drawString(displayFlags, upperLeft.x + 2*BASE.x + 14, output.y - 4);

			if ( (parent.blackAndWhite == true) && (blinker == true) )
				g.setColor(parent.BACKGROUND);
			else if (activated == true)
				g.setColor(parent.ALU_COLOR_ACTIVATED);

			String operand1Expanded = parent.expandToString(displayOp1, ZWEI_HOCH_BITWIDTH);
			String operand2Expanded = parent.expandToString(displayOp2, ZWEI_HOCH_BITWIDTH);

			int labelWidth = parent.stringWidth(aluFont, operand1Expanded);
			g.drawString(operand1Expanded, upperLeft.x + (BASE.x-labelWidth)/2 + 4	  		, input1.y + labelHeight);
			labelWidth = parent.stringWidth(aluFont, operand2Expanded);
			g.drawString(operand2Expanded, upperLeft.x + 2*BASE.x + (BASE.x-labelWidth)/2 - 4, input1.y + labelHeight);

			g.drawString(operator, input1.x + BASE.x - 3, input1.y + labelHeight);

			StringBuffer erg = new StringBuffer("= ");
			erg.append(parent.expandToString(displayResult, ZWEI_HOCH_BITWIDTH));
			g.drawString(erg.toString(), upperLeft.x + BASE.x, output.y - 4);

			// Ausgabe des Titels ("ALU" etc.) in Schwarz
			g.setColor(Color.black);
			g.setFont(parent.DIALOGFONT);
			g.drawString(label, labelX, input1.y - 4);
		}
		else  // ">", "<" oder "^"
		{
			// Ausgabe des Titels ("ALU" etc.) in Schwarz
			g.setColor(Color.black);
			g.drawString(label, labelX, upperLeft.y);
		}


	} /* end paint */


	/**
	 *  Zeichnet die Komponente
	 *  immer, wenn sie aktiviert ist und
	 *  genau einmal, wenn sie deaktiviert wurde.
	 *
	 *  @see #activate
	 *  @see #deactivate
	 */
	public void paintActivated(Graphics g)
	{
		if (activated == true)
			paint(g);
		else if (hasBeenActivated)
		{
			hasBeenActivated = false;
			paint(g);
		}
	} /* end paintActivated */


	/**
	 *  Liefert die Koordinaten eines bestimmten Punktes der Komponente,
	 *  z.B. die der linken oberen Ecke, der Mitte des rechten Randes oder
	 *  des Ausganges (bei einer ALU).
	 *
	 *  @param str Beschreibung des gemeinten Punktes
	 *  @see #getPossibleQualifiers
	 *  @see #setCoordinates
	 */
	public Point getCoordinates(String str)
	{
		Point p = new Point(0,0);

		if ( ( (orientation.equals("v") || orientation.equals("^")) && (str.equalsIgnoreCase("leftInput") || str.equalsIgnoreCase("left")) ) ||
		     ( (orientation.equals("<") || orientation.equals(">")) && (str.equalsIgnoreCase("upperInput") || str.equalsIgnoreCase("upper")) ) )
		{
			p.move(input1.x, input1.y);
		}
		else if ( ( (orientation.equals("v") || orientation.equals("^")) && (str.equalsIgnoreCase("rightInput") || str.equalsIgnoreCase("right")) ) ||
		          ( (orientation.equals("<") || orientation.equals(">")) && (str.equalsIgnoreCase("lowerInput") || str.equalsIgnoreCase("lower")) ) )
		{
			p.move(input2.x, input2.y);
		}
		else if (str.equalsIgnoreCase("output"))
		{
			p.move(output.x, output.y);
		}
		else  // "leftTop"
		{
			p.move(upperLeft.x, upperLeft.y);
		}

		return p;
	} /* end getCoordinates for ALU */

	/**
	 *  Ohne Funktion
	 */
	public void setValue(int foo)
	{
	}

	/**
	 * Liefert das Ergebnis der letzten durchgeführten Berechnung.
	 */
	public int getValue()
	{
		return result;
	}

	/**
	 * Liefert 2^(Bitbreite der Komponente).
	 */
	public long getMaxValue()
	{
		return (long) ZWEI_HOCH_BITWIDTH;
	}
    
    public String[] getAllValues()
    {
        String[] values = {operator, Integer.toString(op1), Integer.toString(op2), Integer.toString(result), (new Boolean(zeroFlag)).toString(), (new Boolean(lessFlag)).toString()};
        return values;
    }
    
    public void setAllValues(String[] oldValues)
    {
        if (oldValues != null && oldValues.length >= 6)
        {
            operator = oldValues[0];
            op1 = Integer.parseInt(oldValues[1]);
            op2 = Integer.parseInt(oldValues[2]);
            result = Integer.parseInt(oldValues[3]);
            zeroFlag = Boolean.valueOf(oldValues[4]).booleanValue();
            lessFlag = Boolean.valueOf(oldValues[5]).booleanValue();
        }
    }

	/**
	 * Führt eine Rechenoperation mit zwei Operanden durch,
	 * aktualisiert die flags und liefert das Ergebnis zurück.
	 *
	 * @param cm  Durchzuführende Operation: Rechner.ADD_MEM, SUB_MEM, DIV_MEM, MUL_MEM, AND_MEM, OR_MEM, XOR_MEM
	 */
	public int calculate(int cm, int operand1, int operand2)
	{
		return calculate(cm, operand1, operand2, true);
	}

	/**
	 * Führt eine Rechenoperation mit zwei Operanden durch,
	 * aktualisiert auf Wunsch die flags und liefert das Ergebnis zurück.
	 *
	 * @param cm  Durchzuführende Operation: Rechner.ADD_MEM, SUB_MEM, DIV_MEM, MUL_MEM, AND_MEM, OR_MEM, XOR_MEM
	 */
	public int calculate(int cm, int operand1, int operand2, boolean updateFlags)
	{
		calculatingMode = cm;
		op1 = operand1;
		op2 = operand2;

		switch (calculatingMode)
		{
			case Rechner.ADD_MEM:
				result = op1 + op2;
				break;
			case Rechner.SUB_MEM:
				result = op1 - op2;
				break;
			case Rechner.MUL_MEM:
				result = op1 * op2;
				break;
			case Rechner.DIV_MEM:
				result = op1 / op2;
				break;
			case Rechner.SHL:
				result = op1 * (int) Math.pow(2, (double) op2);
				break;
			case Rechner.SHR:
				result = op1 / (int) Math.pow(2, (double) op2);
				break;
			case Rechner.AND_MEM:
				result = op1 & op2;
				break;
			case Rechner.OR_MEM:
				result = op1 | op2;
				break;
			case Rechner.XOR_MEM:
				result = op1 ^ op2;
				break;
			default:
				Rechner.out("ALU.calculate (2 Operanden): unbekannte Rechenart (0x" + Integer.toString(calculatingMode, 16) + ")!");
				break;
		}

		if (updateFlags == true)
		{
			if (result == 0)
				zeroFlag = true;
			else
				zeroFlag = false;

			if (result < 0)
				lessFlag = true;
			else
				lessFlag = false;
		}

		return result;
	} /* end calculate (2 operands) */

	/**
	 * Führt eine Rechenoperation mit einem Operanden durch,
	 * aktualisiert die flags und liefert das Ergebnis zurück.
	 *
	 * @param cm  Durchzuführende Operation: Rechner.INC, DEC, NOT
	 */
	public int calculate(int cm, int operand1)
	{
		return calculate(cm, operand1, true);
	}

	/**
	 * Führt eine Rechenoperation mit einem Operanden durch,
	 * aktualisiert auf Wunsch die flags und liefert das Ergebnis zurück.
	 *
	 * @param cm  Durchzuführende Operation: Rechner.INC, DEC, NOT
	 */
	public int calculate(int cm, int operand1, boolean updateFlags)
	{
		calculatingMode = cm;
		op1 = operand1;

		switch (calculatingMode)
		{
			case Rechner.INC:
				op2 = 1;
				result = op1 + op2;
				break;
			case Rechner.DEC:
				op2 = 1;
				result = op1 - op2;
				break;
			case Rechner.SHL:
				op2 = 1;
				result = op1 * (2^op2);
				break;
			case Rechner.SHR:
				op2 = 1;
				result = op1 / (2^op2);
				break;
			case Rechner.NOT:
				result = op1 ^ ((int) (Math.pow(2, (double) parent.BITWIDTH) - 1));
				break;
			default:
				Rechner.out("ALU.calculate (1 Operand): unbekannte Rechenart (0x" + Integer.toString(calculatingMode, 16) + ")!");
				break;
		}

		if (updateFlags == true)
		{
			if (result == 0)
				zeroFlag = true;
			else
				zeroFlag = false;

			if (result < 0)
				lessFlag = true;
			else
				lessFlag = false;
		}

		return result;
	} /* end calculate (1 operand) */

	/**
	 * Liefert ein "flag", also einen booleschen Wert,
	 * der Auskunft über das Ergebnis (oder den Verlauf)
	 * der letzten Berechnung gibt, bei der die Erzeugung
	 * von flags aktiviert war.
	 * Unterstützte flags:
	 * "zero" - "Ergebnis war 0"
	 * "less" - "Ergebnis war kleiner als 0"
	 *
	 * @see #calculate
	 * @see #getFlags
	 * @param flag Das gewünschte flag: "zero" oder "less"
	 */
	public boolean getFlag(String flag)
	{
		if (flag.equalsIgnoreCase("zero"))
			return zeroFlag;
		else if (flag.equalsIgnoreCase("less"))
			return lessFlag;
		else
			return false;
	} /* end getFlag */

	/**
	 * Liefert alle flags.
	 * flags[0]: getFlag("zero")
	 * flags[1]: getFlag("less")
	 *
	 * @see #getFlag
	 */
	public boolean[] getFlags()
	{
		boolean flags[] = new boolean[2];
		flags[0] = zeroFlag;
		flags[1] = lessFlag;

		return flags;
	} /* end getFlags */

	/**
	 * Setzt alle flags.
	 *
	 * @param flags flags[0]: Zeroflag, flags[1]: Lessflag
	 */
	public void setFlags(boolean[] flags)
	{
		if (flags.length == 2)
		{
			zeroFlag = flags[0];
			lessFlag = flags[1];
		}
	} /* end setFlags */


	/**
	 * Aktiviert die Komponente:
	 * Das Erscheinungsbild ändert sich (um die Aufmerksamkeit des
	 * Betrachters zu erregen; Register werden Rot statt Blau, Busse
	 * lassen Punkte laufen) und
	 * update() wird aufgerufen.
	 * Ruft nicht paint() auf.
	 *
	 * @see #deactivate
	 * @see #update
	 * @see #paintActivated
	 */
	public synchronized void activate()
	{
		if (! activationLocked)
		{
			activated = true;
			hasBeenActivated = true;
			update();
		}
	}

	/**
	 * Deaktiviert die Komponente:
	 * Das Erscheinungsbild ändert sich (die Komponente wird wieder unscheinbar;
	 * Register werden Blau statt Rot, Busse werden wieder unbewegte Linien).
	 * Ruft nicht paint() auf.
	 *
	 * @see #activate
	 * @see #update
	 * @see #paintActivated
	 */
	public synchronized void deactivate()
	{
		if (! activationLocked)
		{
			activated = false;
			blinker = false;
		}
	}

	/**
	 *  Folgende Werte bleiben auf dem Bildschirm bis zu einem update() (bzw. activate())
	 *  unverändert:
	 *  - beide Eingänge (Operanden)
	 *  - Ergebnis
	 *  - Operator
	 *  - flags
	 *
	 *  @see #activate
	 *  @see #deactivate
	 */
	public void update()
	{
		displayOp1 = op1;
		displayOp2 = op2;
		displayResult = result;
		displayZeroFlag = zeroFlag;
		displayLessFlag = lessFlag;

		switch (calculatingMode)
		{
			case Rechner.ADD_MEM:
				operator = "+";
				break;
			case Rechner.SUB_MEM:
				operator = "-";
				break;
			case Rechner.MUL_MEM:
				operator = "*";
				break;
			case Rechner.DIV_MEM:
				operator = "/";
				break;
			case Rechner.INC:
				operator = "+";
				break;
			case Rechner.DEC:
				operator = "-";
				break;
			case Rechner.SHL:
				operator = "<<";
				break;
			case Rechner.SHR:
				operator = ">>";
				break;
			case Rechner.AND_MEM:
				operator = "AND";
				break;
			case Rechner.OR_MEM:
				operator = "OR";
				break;
			case Rechner.NOT:
				operator = "NOT";
				break;
			case Rechner.XOR_MEM:
				operator = "XOR";
				break;
			default:
				operator = "";
				break;
		}
	} /* end update */

	/**
	 * Versuch, die verschiedenen Färbungen der Komponenten auf lediglich
	 * Schwarz und Weiß abzubilden: aktivierte Komponenten blinken (in Teilen).
	 * Wird regelmäßig von einem eigenen TimerThread aufgerufen.
	 */
	public synchronized void blink(boolean blinker)
	{
		if (activated == true)
		{
			this.blinker = blinker;
			Graphics g = parent.offScreenGC;

			paint(g);
		}
	}

	/**
	 * Liefert den Titel der Komponente; nur label[0] ist belegt.
	 */
	public String[] getLabel()
	{
		String[] strArray = {label};
		return strArray;
	}

	/**
	 * Legt den Titel der Komponente fest; nur newLabel[0] wird benutzt.
	 */
	public void setLabel(String[] newLabel)
	{
		if (newLabel != null)
		{
			label = newLabel[0];
			labelX = upperLeft.x + BASE.x + (BASE.x - parent.stringWidth(aluFont, label))/2;
			labelHeight = parent.getHeight(aluFont);
		}
	}

	/**
	 * Liefert alle möglichen Werte für den Parameter "grabMode" bei
	 * setCoordinates() und getCoordinates():
	 * Stellen, an denen diese Art von Komponente "angefaßt" werden kann.
	 *
	 * @see #setCoordinates
	 * @see #getCoordinates
	 */
	public String[] getPossibleQualifiers()
	{
		String[] q = new String[4];
		q[2] = "output";
		q[3] = "leftTop";

		if (orientation.equalsIgnoreCase("v") || orientation.equals("^"))
		{
			q[0] = "leftInput"; q[1] = "rightInput";
		}
		else
		{
			q[0] = "upperInput"; q[1] = "lowerInput";
		}

		return q;
	}

	/**
	 * Liefert "true", falls p innerhalb des Umrisses der ALU liegt.
	 */
	public boolean intersectsWith(Point p)
	{
		Polygon border = new Polygon();
		int x1 = upperLeft.x;
		int y1 = upperLeft.y;
		for (int i = 0; i < umriss.length; i++)
		{
			x1 += umriss[i].x;
			y1 += umriss[i].y;
			border.addPoint(x1, y1);
		}

		return border.inside(p.x, p.y);
	}

	/**
	 * Liefert den Hilfetext, der angezeigt wird, wenn der Mauszeiger für
	 * Rechner.INFOTIP_DELAY ms unbewegt über der Komponente steht:
	 * Falls das Rechenergebnis der ALU schon hexadezimal auf dem Schirm zu
	 * sehen ist "12345 dez." und vice versa.
	 */
	public String getInfoTipText(Point p)
	{
		String otherBaseDesc;
		int otherBase;
		if (parent.NUMBERBASE == 16)
		{
			otherBase = 10;
			otherBaseDesc = " dez.";
		}
		else  // "10"
		{
			otherBase = 16;
			otherBaseDesc = " hex.";
		}

		return parent.expandToString(displayResult, ZWEI_HOCH_BITWIDTH, otherBase) + otherBaseDesc;
    }

} /* end ALU */

