/* Copyright (c) 2010, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

package com.cburch.logisim.analyze.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.cburch.logisim.analyze.model.AnalyzerModel;
import com.cburch.logisim.analyze.model.Expression;
import com.cburch.logisim.analyze.model.VariableList;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitMutation;
import com.cburch.logisim.file.LogisimFileActions;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.proj.Projects;
import com.cburch.logisim.std.gates.CircuitBuilder;
import com.cburch.logisim.util.StringUtil;

class BuildCircuitButton extends JButton {
	private static class ProjectItem {
		Project project;
		
		ProjectItem(Project project) {
			this.project = project;
		}
		
		@Override
		public String toString() {
			return project.getLogisimFile().getDisplayName();
		}
	}
	
	private class DialogPanel extends JPanel {
		private JLabel projectLabel = new JLabel();
		private JComboBox project;
		private JLabel nameLabel = new JLabel();
		private JTextField name = new JTextField(10);
		private JCheckBox twoInputs = new JCheckBox();
		private JCheckBox nands = new JCheckBox();
		
		DialogPanel() {
			List<Project> projects = Projects.getOpenProjects();
			Object[] options = new Object[projects.size()];
			Object initialSelection = null;
			for (int i = 0; i < options.length; i++) {
				Project proj = projects.get(i);
				options[i] = new ProjectItem(proj);
				if (proj == model.getCurrentProject()) {
					initialSelection = options[i];
				}
			}
			project = new JComboBox(options);
			if (options.length == 1) {
				project.setSelectedItem(options[0]);
				project.setEnabled(false);
			} else if (initialSelection != null) {
				project.setSelectedItem(initialSelection);
			}
			
			Circuit defaultCircuit = model.getCurrentCircuit();
			if (defaultCircuit != null) {
				name.setText(defaultCircuit.getName());
				name.selectAll();
			}
			
			VariableList outputs = model.getOutputs();
			boolean enableNands = true;
			for (int i = 0; i < outputs.size(); i++) {
				String output = outputs.get(i);
				Expression expr = model.getOutputExpressions().getExpression(output);
				if (expr != null && expr.containsXor()) { enableNands = false; break; }
			}
			nands.setEnabled(enableNands);
			
			GridBagLayout gb = new GridBagLayout();
			GridBagConstraints gc = new GridBagConstraints();
			setLayout(gb);
			gc.anchor = GridBagConstraints.LINE_START;
			gc.fill = GridBagConstraints.NONE;
			
			  gc.gridx = 0;
			  gc.gridy = 0;
			gb.setConstraints(projectLabel, gc); add(projectLabel);
			  gc.gridx = 1;
			gb.setConstraints(project, gc); add(project);
			  gc.gridy++;
			  gc.gridx = 0;
			gb.setConstraints(nameLabel, gc); add(nameLabel);
			  gc.gridx = 1;
			gb.setConstraints(name, gc); add(name);
			  gc.gridy++;
			gb.setConstraints(twoInputs, gc); add(twoInputs);
			  gc.gridy++;
			gb.setConstraints(nands, gc); add(nands);
			
			projectLabel.setText(Strings.get("buildProjectLabel"));
			nameLabel.setText(Strings.get("buildNameLabel"));
			twoInputs.setText(Strings.get("buildTwoInputsLabel"));
			nands.setText(Strings.get("buildNandsLabel"));
		}
	}
	
	private class MyListener implements ActionListener {
		public void actionPerformed(ActionEvent event) {
			Project dest = null;
			String name = null;
			boolean twoInputs = false;
			boolean useNands = false;
			boolean replace = false;
			
			boolean ok = false;
			while (!ok) {
				DialogPanel dlog = new DialogPanel();
				int action = JOptionPane.showConfirmDialog(parent,
						dlog, Strings.get("buildDialogTitle"), JOptionPane.OK_CANCEL_OPTION,
						JOptionPane.QUESTION_MESSAGE);
				if (action != JOptionPane.OK_OPTION) return;
								
				ProjectItem projectItem = (ProjectItem) dlog.project.getSelectedItem();
				if (projectItem == null) {
					JOptionPane.showMessageDialog(parent, Strings.get("buildNeedProjectError"),
							Strings.get("buildDialogErrorTitle"), JOptionPane.ERROR_MESSAGE);
					continue;
				}
				dest = projectItem.project;
				
				name = dlog.name.getText().trim();
				if (name.equals("")) {
					JOptionPane.showMessageDialog(parent, Strings.get("buildNeedCircuitError"),
							Strings.get("buildDialogErrorTitle"), JOptionPane.ERROR_MESSAGE);
					continue;
				}
				
				if (dest.getLogisimFile().getCircuit(name) != null) {
					int choice = JOptionPane.showConfirmDialog(parent,
							StringUtil.format(Strings.get("buildConfirmReplaceMessage"), name),
							Strings.get("buildConfirmReplaceTitle"), JOptionPane.YES_NO_OPTION);
					if (choice != JOptionPane.YES_OPTION) {
						continue;
					}
					replace = true;
				}
				
				twoInputs = dlog.twoInputs.isSelected();
				useNands = dlog.nands.isSelected();
				ok = true;
			}
			
			performAction(dest, name, replace, twoInputs, useNands);
		}
	}
	
	private MyListener myListener = new MyListener();
	private JFrame parent;
	private AnalyzerModel model;

	BuildCircuitButton(JFrame parent, AnalyzerModel model) {
		this.parent = parent;
		this.model = model;
		addActionListener(myListener);
	}
	
	void localeChanged() {
		setText(Strings.get("buildCircuitButton"));
	}
	
	private void performAction(Project dest, String name, boolean replace,
			final boolean twoInputs, final boolean useNands) {
		if (replace) {
			final Circuit circuit = dest.getLogisimFile().getCircuit(name);
			if (circuit == null) {
				JOptionPane.showMessageDialog(parent,
						"Internal error prevents replacing circuit.",
						"Internal Error", JOptionPane.ERROR_MESSAGE);
				return;
			}

			CircuitMutation xn = CircuitBuilder.build(circuit, model, twoInputs,
					useNands);
			dest.doAction(xn.toAction(Strings.getter("replaceCircuitAction")));
		} else {
			// add the circuit
			Circuit circuit = new Circuit(name);
			CircuitMutation xn = CircuitBuilder.build(circuit, model, twoInputs,
					useNands);
			xn.execute();
			dest.doAction(LogisimFileActions.addCircuit(circuit));
			dest.setCurrentCircuit(circuit);
		}
	}
}
