package lab01;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

public class Calculator extends JPanel {
	private static final long serialVersionUID = 1L;
	private static Font fontLarge;
	Display display;
	CPU cpu;
	JPanel buttons;
	String op;

	public Calculator() {
		op = "LOD";
		cpu = new CPU();
		Font font = getFont();
		fontLarge = font.deriveFont((float) (2.5 * font.getSize2D()));
		setLayout(new BorderLayout());
		display = new Display();
		display.setFont(fontLarge);

		add(display, BorderLayout.PAGE_START);
		buttons = new JPanel(new GridLayout(5, 4));

		addButton("CE", (e) -> display.clearEntry());
		addButton("C", (e) -> execute("LOD", 0));
		addButton("<X", (e) -> display.undo());
		addButton("/", (e) -> executeNext("DIV"));

		addButton("7", (e) -> display.addNumber(7));
		addButton("8", (e) -> display.addNumber(8));
		addButton("9", (e) -> display.addNumber(9));
		addButton("x", (e) -> executeNext("MUL"));

		addButton("4", (e) -> display.addNumber(4));
		addButton("5", (e) -> display.addNumber(5));
		addButton("6", (e) -> display.addNumber(6));
		addButton("-", (e) -> executeNext("SUB"));

		addButton("1", (e) -> display.addNumber(1));
		addButton("2", (e) -> display.addNumber(2));
		addButton("3", (e) -> display.addNumber(3));
		addButton("+", (e) -> executeNext("ADD"));

		addButton("+/-", (e) -> display.setValue(-1 * display.getValue()));
		addButton("0", (e) -> display.addNumber(0));
		addButton(" ", (e) -> {}); // do nothing button?
		addButton("=", (e) -> executeNext("LOD"));

		add(buttons, BorderLayout.PAGE_END);
	}

	private void addButton(String name, ActionListener action) {
		JButton but = new JButton(name);
		but.setFont(fontLarge);
		but.addActionListener(action);
		buttons.add(but);
	}

	private void executeNext(String nextOp) {
		int arg = display.getValue();
		cpu.execute(op, arg);
		op = nextOp;
		display.setValue(cpu.getAccumulator());
		display.newNumber();
	}

	private void execute(String op, int arg) {
		cpu.execute(op, arg);
		display.setValue(cpu.getAccumulator());
	}

	private static void createAndShowGUI() {
		// Create and set up the window.
		JFrame frame = new JFrame("Java Calculator");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setContentPane(new Calculator());

		// Display the window.
		frame.pack();
		frame.setVisible(true);
	}

	public static void main(String[] args) {
		// Schedule a job for the event-dispatching thread:
		// creating and showing this application's GUI.
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() { createAndShowGUI(); }
		});

	}

	private class Display extends JLabel {
		private static final long serialVersionUID = 1L;
		int value;
		boolean newNumber;

		public Display() {
			super();
			setOpaque(true);
			setHorizontalAlignment(JLabel.RIGHT);
			setBackground(new Color(131, 213, 248));
			setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
			clearEntry();
		}

		public void clearEntry() {
			setValue(0);
			newNumber = true;
		}

		public void addNumber(int num) {
			if (newNumber) clearEntry();
			newNumber = false;
			setValue(value * 10 + num);
		}

		public void newNumber() { newNumber = true; }

		public void undo() { setValue(value / 10); }

		/**
		 * @return the value
		 */
		public int getValue() { return value; }

		/**
		 * @param value the value to set
		 */
		public void setValue(int value) {
			this.value = value;
			setText(String.format("%18d", value));
		}

	}
}