import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DecimalFormat;


public class Simulation extends JApplet implements ActionListener{

	java.util.Timer timer0;
	java.util.Timer timer1;
	java.util.Timer timer2;
	java.util.Timer timer3;
	java.util.Timer timer4;
	java.util.Timer timer5;
	java.util.Timer timer6;

	Image cpu;

	JLabel marl,mdrl,status,title,ramTimel,sPointerl,controllinel;
	JLabel space1,space2,space3,space4,space5;
	JTextField mar,mdr,ramTime,sPointer,controlline;
	JTextArea memory0,memory1;
	JScrollPane scroll0,scroll1;
	JButton action;
	String[] actions = { "Read" , "Write" , "Pop" , "Push" };
	JComboBox actList = new JComboBox(actions);
	String[] styles = { "Byte" , "Word" , "LongWord" };
	JComboBox styleList = new JComboBox(styles);

	String[] mem = new String[8192];
	DecimalFormat fourDigit = new DecimalFormat( "00" );

	int mod;
	int state = 7;
	int popsign = 0;
						class Label0Task extends TimerTask {
							public void run() {
								status.setText("      Operation  has done succesfully     ");
								state = 0;
								controlline.setText("DTACK");
								repaint();
							}
						}

						class Label1Task extends TimerTask {
							public void run() {
		  					    status.setText("Set Control Line to 0(write) ...   ");
								state = 1;
								controlline.setText("0");
								repaint();
							}
						}
						class Label2Task extends TimerTask {
							public void run() {
								status.setText("Placing MDR data on Datalines ... ");
								state = 2;
								System.out.println("222222222");
								initMemory();
								repaint();
							}
						}



						class Label3Task extends TimerTask {
							public void run() {
								status.setText("Set Control Line to 1(Read)");
								state = 3;
								controlline.setText("1");
								repaint();
							}
						}


						class Label4Task extends TimerTask {
							public void run() {
								status.setText("Placing MAR on Address BUS...");
								state = 4;
								repaint();
							}
						}

						class Label5Task extends TimerTask {
							public void run() {
								status.setText("asserting MFC signal ... ");
								controlline.setText("MFC");
								state = 5;
								repaint();

							}
						}

						class Label6Task extends TimerTask {
							public void run() {
								status.setText("Loads data lines into MDR register ...");
								mdr.setText("");
								for (int i=0;i< mod;i++){
									mdr.setText(mem[Integer.parseInt(toDecimal(mar.getText()))+(mod-1)-i]+mdr.getText());
								}
								if (mdr.getText().length() < 8 )
													for (int i= mdr.getText().length(); i<8;i++){
														mdr.setText("0"+mdr.getText());
													}
								state = 6;
								repaint();

							}
						}

						class Label7Task extends TimerTask {
							public void run() {
								status.setText("      Status    ");
								state = 7;
								controlline.setText("");
								repaint();
							}
						}



	public void init(){

		cpu = getImage(getDocumentBase(),"cpu.jpg");
		title = new JLabel("         MOTOROLA 68K 3BUS ARCHITECTURE         ");
		title.setFont(new Font("ali",Font.ITALIC,12));

		marl = new JLabel("MAR");
		mdrl = new JLabel("MDR");
		status = new JLabel("               Status                 ");
		ramTimel = new JLabel("Memory Access Time");
		sPointerl = new JLabel("Stack Pointer");
		space1 = new JLabel("             ");
		space2 = new JLabel("             ");
		space3 = new JLabel("             ");
		space4 = new JLabel("                  ");
		space5 = new JLabel("             ");
		controllinel = new JLabel("               Control Line :   ");


		mar = new JTextField(4);
		mdr = new JTextField(8);
		sPointer = new JTextField(4);
		ramTime = new JTextField(4);
		controlline = new JTextField(5);

		memory0 = new JTextArea(8,19);
		memory1 = new JTextArea(8,9);
		scroll0 = new JScrollPane(memory0);

		action = new JButton("Action");
		action.addActionListener(this);
		actList.setSelectedIndex(0);
		actList.addActionListener(this);
		styleList.setSelectedIndex(0);
		styleList.addActionListener(this);

		setSize(250,600);
		Container c = getContentPane();
		c.setLayout(new FlowLayout());

		c.add(title);
		c.add(scroll0);
		c.add(marl);
		c.add(mar);
		c.add(mdrl);
		c.add(mdr);
		c.add(ramTimel);
		c.add(ramTime);

		c.add(sPointerl);
		c.add(sPointer);
		c.add(space1);
		c.add(styleList);
		c.add(actList);
		c.add(space2);
		c.add(action);
		c.add(space4);
		c.add(controllinel);
		c.add(controlline);
		c.add(status);

		sPointer.setEditable(false);
		sPointer.setText("1FFF");

		ramTime.setText("1000");
		controlline.setEditable(false);

		for (int i=0;i<8192;i++) mem[i] ="00";
		initMemory();

	}


	public void actionPerformed(ActionEvent e){
		if (e.getActionCommand() == "Action" ) {

			if (mdr.getText().length() < 8 )
					for (int i= mdr.getText().length(); i<8;i++){
						mdr.setText("0"+mdr.getText());
					}
			mdr.setText(mdr.getText().toUpperCase());

			if (mar.getText().length() < 4 )
								for (int i= mar.getText().length(); i<4;i++){
									mar.setText("0"+mar.getText());
					}

			mar.setText(mar.getText().toUpperCase());
			if (actList.getSelectedIndex() == 0 ) read( styleList.getSelectedIndex());
			else if (actList.getSelectedIndex() == 1 ) write(styleList.getSelectedIndex());
			else if (actList.getSelectedIndex() == 2 ) pop( styleList.getSelectedIndex() );
			else push( styleList.getSelectedIndex() );
		}



	}

	public void initMemory(){
		memory0.setText("");

		for (int i=0;i<8192;i++){

			String e = Integer.toHexString(i);
			if (e.length() == 1) e = "000" + e;
			if (e.length() == 2) e = "00" + e;
			if (e.length() == 3) e = "0" + e;
			if (i%2 == 0)
				memory0.append((" "+ e +"             "+ mem[i] +"    |    " ).toUpperCase());
			else
				memory0.append((" "+ e +"             "+ mem[i] +"\n" ).toUpperCase());
		}
		return;
	}


	public void WriteMemory(String address, String data){
		mem[Integer.parseInt(toDecimal(address))]=data;
		initMemory();
		return;
	}

	public void write(int style ){
		if (style == 0)  mod = 1;
		else if (style == 1)  mod = 2;
		else  mod = 4;
		if (( mod == 4 || mod == 2) && Integer.parseInt(toDecimal(mar.getText()))%2 == 1 ) {
			busError();
			return;
		}
		timer1= new java.util.Timer();
		timer1.schedule(new Label1Task(),00);
		timer3= new java.util.Timer();
		timer3.schedule(new Label4Task(),1000);
		timer2= new java.util.Timer();
		timer2.schedule(new Label2Task(),2000);
		timer0= new java.util.Timer();
		timer0.schedule(new Label0Task(),5000);
		timer4= new java.util.Timer();
		timer4.schedule(new Label7Task(),6000);

		for (int i=0 ;i < mod ;i++){
			System.out.println("in loop"+" " +mod+" "+i+" "+mdr.getText().length());

			mem[Integer.parseInt(toDecimal(mar.getText())) +(mod-1)- i] = mdr.getText().substring(8- (2*i + 2) ,8-2*i);

		}

		return;
	}


	public void read(int style){

		controlline.setText("");

		if (style == 0)  mod = 1;
		else if (style == 1)  mod = 2;
		else  mod = 4;

		if (popsign == 0) if (( mod == 4 || mod == 2) && Integer.parseInt(toDecimal(mar.getText()))%2 == 1 ) {
			busError();
			return;
		}

		timer0= new java.util.Timer();
		timer0.schedule(new Label3Task(),00);
		timer1= new java.util.Timer();
		timer1.schedule(new Label4Task(),2000);
		timer2= new java.util.Timer();
		timer2.schedule(new Label5Task(),2000+Integer.parseInt(ramTime.getText()));
		timer3= new java.util.Timer();
		timer3.schedule(new Label6Task(),2000+Integer.parseInt(ramTime.getText())+1000);
		timer4= new java.util.Timer();
		timer4.schedule(new Label0Task(),2000+Integer.parseInt(ramTime.getText())+2000);
		timer5= new java.util.Timer();
		timer5.schedule(new Label7Task(),3000+Integer.parseInt(ramTime.getText())+2000);

		popsign = 0;
		return;

	}


	public void push(int style){

		if (style == 0)  mod = 1;
				else if (style == 1)  mod = 2;
		else  mod = 4;

		if (Integer.parseInt( toDecimal( sPointer.getText() ) ) < -1 ) {
			status.setText("  Stack is full  ");
			return;
		}
		mar.setText("");

		if ( (mod == 4 || mod == 2) &&  Integer.parseInt(toDecimal(sPointer.getText())) %2 == 1 )	mod--;


		if (style == 0) mar.setText( sPointer.getText() + "" );
		else if (style == 1   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 0 ) mar.setText( Integer.toHexString((Integer.parseInt(toDecimal(sPointer.getText())) - 2) ) );
		else if (style == 1   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 1 ) mar.setText( Integer.toHexString((Integer.parseInt(toDecimal(sPointer.getText())) - 1) ) );
		else if (style == 2   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 0 ) mar.setText( Integer.toHexString((Integer.parseInt(toDecimal(sPointer.getText())) - 4) ) );
		else if (style == 2   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 1 ) mar.setText( Integer.toHexString((Integer.parseInt(toDecimal(sPointer.getText())) - 3) ) );


		write(style);

		if (style == 0) sPointer.setText(Integer.toHexString(Integer.parseInt(toDecimal(sPointer.getText())) -  1) );
		else if (style == 1   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 0 )  sPointer.setText(Integer.toHexString(Integer.parseInt(toDecimal(sPointer.getText())) -  3).toUpperCase() );
		else if (style == 1   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 1 )  sPointer.setText(Integer.toHexString(Integer.parseInt(toDecimal(sPointer.getText())) -  2).toUpperCase() );
		else if (style == 2   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 0 )  sPointer.setText(Integer.toHexString(Integer.parseInt(toDecimal(sPointer.getText())) -  5).toUpperCase() );
		else if (style == 2   &&   Integer.parseInt(toDecimal(sPointer.getText())) %2 == 1 )  sPointer.setText(Integer.toHexString(Integer.parseInt(toDecimal(sPointer.getText())) -  4).toUpperCase() );

		return;
	}

	public void pop(int style){

		if ( Integer.parseInt(toDecimal(sPointer.getText())) == 8191 ) {
			status.setText(" Stack is empty ");
			return;
		}



		if (style == 0)  mod = 1;
		else if (style == 1)  mod = 2;
		else  mod = 4;

		if ( Integer.parseInt( toDecimal(sPointer.getText() ) ) == 8189 && mod == 4 ) {
			busError();
			return;
		}

		if ((mod == 2 || mod == 4) && Integer.parseInt(toDecimal(sPointer.getText()))%2 == 0 ) {
			busError();
			return;
		}

		mar.setText( Integer.toHexString( Integer.parseInt( toDecimal( sPointer.getText() ) )+1 ).toUpperCase()   );



		System.out.println(" in pop ");
		popsign = 1;
		read(style);


		if (Integer.toHexString( Integer.parseInt( toDecimal( sPointer.getText() ) ) + mod ).length() ==3   )
			sPointer.setText("0" + Integer.toHexString( Integer.parseInt( toDecimal( sPointer.getText() ) ) + mod ).toUpperCase()  );
		else
			sPointer.setText(Integer.toHexString( Integer.parseInt( toDecimal( sPointer.getText() ) ) + mod ).toUpperCase()  );


		return;
	}

	public void busError(){
		status.setText("Address Error Exception occurred ");
		controlline.setText("");
		return;
	}




	public String toDecimal(String a){
		int i = a.length()-1;
		int s = 0;
		int d = 0;
		char[] b =new char[a.length()];
		b = a.toCharArray();
		while (i >= 0) {
			if (b[i] == 'f') d=15;
			else if (b[i] == 'e') d=14;
			else if (b[i] == 'd') d=13;
			else if (b[i] == 'c') d=12;
			else if (b[i] == 'b') d=11;
			else if (b[i] == 'a') d=10;
			else d=Character.getNumericValue( b[i] );
			s = s + d*((int)Math.pow(16,a.length()-i-1));
			i--;

		}
		return fourDigit.format(s);
	}

	public void paint(Graphics g){
		super.paint(g);
		g.drawImage(cpu, 25 ,360 ,200 ,200 ,this );
		g.setColor(Color.red);
		if (state != 7){
			if (state == 0) g.fillRect(70,460,121,7);
			else if (state == 1) g.fillRect(70,461,118,7);
			else if (state == 2) {
				System.out.println("heloo");
				g.fillRect(70,400,118,7);
			}
			else if (state == 3) g.fillRect(70,461,118,7);
			else if (state == 4) g.fillRect(65,518,123,7);
			else if (state == 5) g.fillRect(70,461,118,7);
			else if (state == 6) g.fillRect(70,400,118,7);
		}

	}

}













