import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Math;
import java.util.Arrays;

/**
 * Applet to do basic set relations
 * Creation date: (01/30/2002 8:35:19 AM)
 * Modified date: (04/15/2002 2:55:00 PM)
 * @author: Andrew Freed, arf132@psu.edu
 */

/*
Development of this applet was sponsored by the Penn State Fund for 
Excellence in Learning and Teaching (FELT), project "Java-based 
Teaching of Mathematics in Information Sciences and Technology",
supervised by Frank Ritter and David Mudgett.
*/

public class BasicSetApplet extends Applet {
	private Label 	lblSizeOfA		= new Label("Size of A:");
	private Label 	lblSizeOfB		= new Label("Size of B:");
	private TextField txtSizeOfA		= new TextField("10");
	private TextField txtSizeOfB		= new TextField("7");
	private Button 	btnGo 		= new Button("Go!");
	private Label 	lblHeaderA		= new Label("A:");
	private Label 	lblHeaderB		= new Label("B:");
	private Label 	lblSetA		= new Label("Set A");
	private Label 	lblSetB		= new Label("Set B");
	private Button 	btnAUnionB		= new Button("A \\/ B");
	private Button 	btnAIntersectB	= new Button("A /\\ B");
	private Button 	btnAMinusB		= new Button("A - B");
	private Button 	btnAComplement 	= new Button("Ac");
	private Label 	lblAUnionB		= new Label("A Union B");
	private Label 	lblAIntersectB	= new Label("A Intersect B");
	private Label 	lblAMinusB		= new Label("A Minus B");
	private Label 	lblAComplement 	= new Label("A Complement");

	private int setA[];
	private int setB[];
	private int AVAILABLE_INTS = 20; //Want to choose random numbers below this
	private int sizeOfA=0;
	private int sizeOfB=0;
	
/**
 * Function that will get A intersected with B
 * Assume sorted arrays!
 */
private String getAIntersectB()
    {
      String result = "";

	//If A is empty, we won't do any work (intersection is empty)
	//Otherwise, iterate through both arrays, and add common elements
	//to the intersection string
	for( int idxA = 0; idxA < sizeOfA; idxA++ )
	{
		boolean found = false;
		for( int idxB = 0; idxB < sizeOfB && setA[idxA] >= setB[idxB]; idxB++)
		{
			if( setA[idxA] == setB[idxB] )
				found = true;
		}
		if( found )
			result += ( " " + setA[idxA] + " " );

		found = false;
	}

	lblAIntersectB.setText(result);
      return result;
    }

/**
 * Function that will get A unioned with B
 * Assume sorted sets A, B
 */
private String getAUnionB()
    {
      String result = "";
	int idxA = 0;
	int idxB = 0;

	//If either set is empty, the result is just the other set.
	//If both are empty there the union is empty
	boolean shouldLoop = true;
	if( sizeOfA == 0 || sizeOfB == 0 )
	{
		shouldLoop = false;
		if( sizeOfA == 0 && sizeOfB == 0 )
			result = "";
		else if( sizeOfA == 0 )
			result = aryToString(setB, sizeOfB);
		else // sizeOfB == 0
			result = aryToString(setA, sizeOfA);
	}

	//Iterate through both arrays, and add every value that is in either set
	//Note the use of comparisons to make sure that the union array is also
	//in sorted order
	while( idxA < sizeOfA && idxB < sizeOfB && shouldLoop)
	{
		if( setA[idxA] == setB[idxB] )
		{
			result += (" " + setA[idxA] + " ");
			idxA++;
			idxB++;
		}
		else if( setA[idxA] < setB[idxB] )
		{
			result += (" " + setA[idxA] + " ");
			idxA++;
			//If done with A's then append rest of B's
			if( idxA == sizeOfA )
			{
				while( idxB < sizeOfB )
				{
					result += (" " + setB[idxB] + " ");
					idxB++;
				}
			}
		}
		else // setA[idxA] > setB[idxB]
		{
			result += (" " + setB[idxB] + " ");
			idxB++;
			//If done with B's then append rest of A's
			if( idxB == sizeOfB )
			{
				while( idxA < sizeOfA )
				{
					result += (" " + setA[idxA] + " ");
					idxA++;
				}
			}
		}			
	}
	lblAUnionB.setText(result);
      return result;
    }

/**
 * Function that will get A minus B
 * Assume sorted sets A, B
 */
private String getAMinusB()
    {
      String result = new String();

	//For every element in A, see if it is in B.  If it is not, then it is in A-B
	for( int idxA = 0; idxA < sizeOfA; idxA++ )
	{
		if( notInArray(setB, sizeOfB, setA[idxA]) )
			result += (" " + setA[idxA] + " ");
	}
	lblAMinusB.setText(result);
      return result;
    }

/**
 * Function that will get A complement
 */
private String getAComplement()
    {
      String result = new String();
	if( sizeOfA > 0)
	{
		//Cycle through all the elements of U.  Any element not in A is in Ac
		for( int idx = 1; idx <= AVAILABLE_INTS; idx++ )
		{
			if( notInArray( setA, sizeOfA, idx ) )
				result += (" " + idx + " ");
		}
	}
	else
	{
		// Ac is all of U
		result = " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ";
	}
	lblAComplement.setText(result);
      return result;
    }

/**
 * Function that creates random sets of A, B
 */
private void createABSets()
{
   try
   {
	//Text box must contain data
	if( ( txtSizeOfA.getText() == null) || ( txtSizeOfB.getText() == null) )
	{
		lblSetA.setText("Error: Please a valid set size, less than " + AVAILABLE_INTS);
		lblSetB.setText("Error: Please a valid set size, less than " + AVAILABLE_INTS);
		sizeOfA = 0;
		sizeOfB = 0;
		resetAnswerLabels();
		disableSetTheory();
		return;
	}

	sizeOfA = Integer.parseInt(txtSizeOfA.getText());
	sizeOfB = Integer.parseInt(txtSizeOfB.getText());

	//Size of each set must be less than size of U
	if( sizeOfA > AVAILABLE_INTS || sizeOfB > AVAILABLE_INTS )
	{
		//Fix labels
		lblSetA.setText("Set A");
		lblSetB.setText("Set B");
		if (sizeOfA > AVAILABLE_INTS)
			lblSetA.setText("Please choose a smaller set size");	
		if (sizeOfB > AVAILABLE_INTS)
			lblSetB.setText("Please choose a smaller set size");

		sizeOfA = 0;
		sizeOfB = 0;
		resetAnswerLabels();
		disableSetTheory();
		return;
	}

	//Negative set size not allowed
	if( sizeOfA < 0 || sizeOfB < 0 )
	{
		lblSetA.setText("Set A");
		lblSetB.setText("Set B");
		if( sizeOfA < 0 )
			lblSetA.setText("Please choose a valid set size");	
		if( sizeOfB < 0 )		
			lblSetB.setText("Please choose a valid set size");
		sizeOfA = 0;
		sizeOfB = 0;
		resetAnswerLabels();
		disableSetTheory();
		return;
	}

	//Otherwise valid set size.  Since I can't create an array of size 0,
	//I create a dummy array, but report the size as 0
	if( sizeOfA != 0)
		setA = new int[sizeOfA];
	else
	{
		setA = new int[1];
		setA[0]=0;
	}

	if( sizeOfB != 0)
		setB = new int[sizeOfB];
	else
	{
		setB = new int[1];
		setB[0]=0;
	}

	//Gather random numbers between 1 and AVAILABLE_INTS for each array.
	//Make sure that the elements are unique
	int idxA=0;
	int myRand;
	while( idxA < sizeOfA )
	{
		myRand = (int) ( AVAILABLE_INTS * java.lang.Math.random() + 1);
		if( notInArray( setA, idxA, myRand ) )
			setA[idxA++] = myRand;
	}

	int idxB=0;
	while( idxB < sizeOfB )
	{
		myRand = (int) ( AVAILABLE_INTS * java.lang.Math.random() + 1);
		if( notInArray( setB, idxB, myRand ) )
			setB[idxB++] = myRand;
	}

	//Sort these arrays
	sort(setA);
	sort(setB);

	//Print them for the user
	lblSetA.setText( aryToString(setA, sizeOfA) );
	lblSetB.setText( aryToString(setB, sizeOfB) );

	resetAnswerLabels();
	enableSetTheory();
   }

   //This is to keep the applet from "blowing up" on invalid textbox entry formats
   catch(java.lang.NumberFormatException nfe)
   {
	lblSetA.setText("Error: Please a valid set size, less than " + AVAILABLE_INTS);
	lblSetB.setText("Error: Please a valid set size, less than " + AVAILABLE_INTS);
	txtSizeOfA.setText("");
	txtSizeOfB.setText("");
	sizeOfA = 0;
	sizeOfB = 0;

	resetAnswerLabels();
	disableSetTheory();
   }
}

private void resetAnswerLabels()
{
	lblAUnionB.setText("A Union B");
	lblAIntersectB.setText("A Intersect B");
	lblAMinusB.setText("A Minus B");
	lblAComplement.setText("A Complement");
}

private void disableSetTheory()
{
	btnAUnionB.setEnabled(false);
	btnAIntersectB.setEnabled(false);
	btnAMinusB.setEnabled(false);
	btnAComplement.setEnabled(false);
}

private void enableSetTheory()
{
	btnAUnionB.setEnabled(true);
	btnAIntersectB.setEnabled(true);
	btnAMinusB.setEnabled(true);
	btnAComplement.setEnabled(true);
}

private boolean notInArray( int[] ary, int pos, int value)
{	
	boolean result = true;
	for(int idx=0; idx < pos && result; idx++)
	{
		if( ary[idx] == value )
			result = false;
	}
	return result;
}

private String aryToString( int[] ary, int size )
{
	String result = "";
	if( size != 0 )
	{
		for( int idx=0; idx < size -1; idx++)
			result += (ary[idx] + "  ");
	
		result += ary[ary.length -1];
	}

	return result;
}

//Simple selection sort
private void sort( int ary[] )
{
	int size = ary.length;
	int temp;
	int smallVal;
	int smallPos;
	for( int i=0; i < size; i++ )
	{
		smallVal = ary[i];
		smallPos = i;
		for( int j=i; j < size; j++ )
		{
			if( ary[j] < smallVal )
			{
				smallVal = ary[j];
				smallPos = j;
			}
		}
		temp = ary[i];
		ary[i] = smallVal;
		ary[smallPos] = temp;
	}
}


/**
 * Initializes the applet.
 */
public void init() {
	try {
		super.init();
		setName("BasicSetApplet");
		setLayout(null);
		setSize(500, 350);

		int baseX=10;
		int baseY=40;
		int xStep=55;
		int yStep=30;

		lblSizeOfA.setBounds(baseX, baseY, 50, 30);
		lblSizeOfB.setBounds(baseX + 2*xStep, baseY, 50, 30);
		txtSizeOfA.setBounds(baseX + xStep, baseY, 30, 30);
		txtSizeOfB.setBounds(baseX + 3*xStep, baseY, 30, 30);
		btnGo.setBounds(250, baseY, 40, 30);
		lblHeaderA.setBounds(baseX + xStep, baseY + 3*yStep, 30, 30);
		lblHeaderB.setBounds(baseX + xStep, baseY + 4*yStep, 30, 30);
		lblSetA.setBounds(baseX + 2*xStep, baseY + 3*yStep, 300, 30);
		lblSetB.setBounds(baseX + 2*xStep, baseY + 4*yStep, 300, 30);
		btnAUnionB.setBounds(baseX + xStep, baseY + 5*yStep, 50, 30);
		btnAIntersectB.setBounds(baseX + xStep, baseY + 6*yStep, 50, 30);
		btnAMinusB.setBounds(baseX + xStep, baseY + 7*yStep, 50, 30);
		btnAComplement.setBounds(baseX + xStep, baseY + 8*yStep, 50, 30);
		lblAUnionB.setBounds(baseX + 2*xStep, baseY + 5*yStep, 350, 30);
		lblAIntersectB.setBounds(baseX + 2*xStep, baseY + 6*yStep, 350, 30);
		lblAMinusB.setBounds(baseX + 2*xStep, baseY + 7*yStep, 350, 30);
		lblAComplement.setBounds(baseX + 2*xStep, baseY + 8*yStep, 350, 30);

			btnGo.setActionCommand("btnGo");
			btnGo.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					createABSets();
					btnAUnionB.requestFocus();
				}
			});
			btnAIntersectB.setActionCommand("AIntersectB");
			btnAIntersectB.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					getAIntersectB();
					btnAMinusB.requestFocus();
				}
			});

			btnAUnionB.setActionCommand("AUnionB");
			btnAUnionB.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					getAUnionB();
					btnAIntersectB.requestFocus();
				}
			});

			btnAComplement.setActionCommand("AComplement");
			btnAComplement.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					getAComplement();
					btnGo.requestFocus();
				}
			});

			btnAMinusB.setActionCommand("AMinusB");
			btnAMinusB.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					getAMinusB();
					btnAComplement.requestFocus();
				}
			});

			txtSizeOfA.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					createABSets();
					btnAUnionB.requestFocus();
				}
			});
			txtSizeOfB.addActionListener(new java.awt.event.ActionListener(){
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					createABSets();
					btnAUnionB.requestFocus();
				}
			});
		add(lblSizeOfA);
		add(lblSizeOfB);
		add(txtSizeOfA);
		add(txtSizeOfB);
		add(btnGo);
		add(lblHeaderA);
		add(lblHeaderB);
		add(lblSetA);
		add(lblSetB);
		add(btnAUnionB);
		add(btnAIntersectB);
		add(btnAMinusB);
		add(btnAComplement);
		add(lblAUnionB);
		add(lblAIntersectB);
		add(lblAMinusB);
		add(lblAComplement);

		disableSetTheory();
		btnGo.requestFocus();
	} catch (java.lang.Throwable Exc) {
		handleException(Exc);
	}
}
    
/**
 * Called whenever the part throws an exception.
 * @param exception java.lang.Throwable
 */
private void handleException(java.lang.Throwable exception) {
	//Currently exceptions are not handled since the applet does not have
	//stdout or stderr available to it.
}

//main allows this applet to be run as a standalone application
/**
 * main entrypoint - starts the part when it is run as an application
 * @param args java.lang.String[]
 */
public static void main(java.lang.String[] args) {
	try {
		Frame frame = new java.awt.Frame();
		BasicSetApplet aBasicSetApplet;
		Class iiCls = Class.forName("BasicSetApplet");
		ClassLoader iiClsLoader = iiCls.getClassLoader();
		aBasicSetApplet = (BasicSetApplet)java.beans.Beans.instantiate(iiClsLoader,"BasicSetApplet");
		frame.add("Center", aBasicSetApplet);
		frame.setSize(aBasicSetApplet.getSize());
		frame.addWindowListener(new java.awt.event.WindowAdapter() {
			public void windowClosing(java.awt.event.WindowEvent e) {
				System.exit(0);
			};
		});
		frame.show();
		java.awt.Insets insets = frame.getInsets();
		frame.setSize(frame.getWidth() + insets.left + insets.right, frame.getHeight() + insets.top + insets.bottom);
		frame.setVisible(true);
	} catch (Throwable exception) {
		System.err.println("Exception occurred in main() of java.applet.Applet");
		exception.printStackTrace(System.out);
	}
}

}
