/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dowser.ui;

import dowser.Util;
import dowser.model.Attribute;
import dowser.model.DomainEntity;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.EventObject;
import java.util.HashSet;
import java.util.Set;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.CellEditorListener;
import javax.swing.tree.TreeCellEditor;
import dowser.model.DomainModel;
import dowser.model.Operation;
import dowser.model.Relation;
import dowser.model.Relation.Participant;
import dowser.model.TextRestrictor;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JOptionPane;

/**
 *
 * @author Chetan Pawgi
 */
public class DomainTreeEditor implements TreeCellEditor {

	private abstract class CellEditorComponent extends Component {

		protected JTree m_Tree;
		protected DomainEntity m_Entity;

		public CellEditorComponent(JTree tree, DomainEntity entity, DomainModel model) {
			m_Tree = tree;
			m_Entity = entity;
		}

		public DomainEntity getValue() {
			return m_Entity;
		}

		public abstract Component getComponent();

		public void submitValue() {
			m_Tree.setEditable(false);
		}
	}

	private class TextCellEditorComponent extends CellEditorComponent {

		@Override
		public Component getComponent() {
			return m_text;
		}
		private JTextField m_text;

		public TextCellEditorComponent(JTree tree, DomainEntity entity, DomainModel model) {
			super(tree, entity, model);
			m_text = new JTextField(Util.convertDomainRepresentation(entity));
			m_text.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					stopCellEditing();
				}
			});
			m_text.addKeyListener(new TextRestrictor());
			if (entity instanceof Relation && entity.getName().startsWith("#aggregation")) {
				m_text.setEnabled(false);
			}
		}

		@Override
		public void submitValue() {
			DomainTreeModel m_TreeModel = (DomainTreeModel) m_Tree.getModel();
			DomainModel m_DomainModel = m_TreeModel.getDomainModel();
			m_DomainModel.renameEntity(m_Entity, m_text.getText());
			m_TreeModel.notifyListeners();
			super.submitValue();
		}
	}

	private class ParticipantEditorComponent extends CellEditorComponent {

		@Override
		public Component getComponent() {
			return pnlParticipant;
		}
		private JComboBox cmbPClass;
		private JTextField txtPRole;
		private JComboBox cmbPMulMin;
		private JComboBox cmbPMulMax;
		private JPanel pnlParticipant;

		public ParticipantEditorComponent(JTree tree, Participant participant, DomainModel domainModel) {
			super(tree, participant, domainModel);
			if (participant == null) {
				throw new IllegalArgumentException("participant can't be null");
			}
			if (domainModel == null) {
				throw new IllegalArgumentException("domain model can't be null");
			}
			pnlParticipant = new JPanel();
			pnlParticipant.setLayout(new BoxLayout(pnlParticipant, BoxLayout.Y_AXIS));
			pnlParticipant.setBorder(BorderFactory.createEtchedBorder());
			JPanel pnlPClass = new JPanel();
			pnlPClass.setLayout(new BoxLayout(pnlPClass, BoxLayout.X_AXIS));
			pnlPClass.add(new JLabel("Participanting class : "));
			cmbPClass = new JComboBox(domainModel.getClasses().toArray());
			cmbPClass.setRenderer(new DefaultListCellRenderer() {

				@Override
				public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
					if (value instanceof dowser.model.Class) {
						value = ((dowser.model.Class) value).getName();
					}
					return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
				}
			});
			cmbPClass.setSelectedItem(participant.getParticipatingClass());
			pnlPClass.add(cmbPClass);
			pnlParticipant.add(pnlPClass);

			JPanel pnlPRole = new JPanel();
			pnlPRole.setLayout(new BoxLayout(pnlPRole, BoxLayout.X_AXIS));
			pnlPRole.add(new JLabel("Role : "));
			txtPRole = new JTextField(participant.getRole());
			txtPRole.addKeyListener(new TextRestrictor());

			pnlPRole.add(txtPRole);
			pnlParticipant.add(pnlPRole);

			JPanel pnlPMul = new JPanel();
			pnlPMul.setLayout(new BoxLayout(pnlPMul, BoxLayout.X_AXIS));
			pnlPMul.add(new JLabel("Multiplicity : "));
			cmbPMulMin = new JComboBox(new String[]{"0", "1"});
			pnlPMul.add(cmbPMulMin);
			cmbPMulMax = new JComboBox(new String[]{"1", "*"});
			pnlPMul.add(cmbPMulMax);

			String strMul = participant.getMultiplicity();
			String strMin, strMax;
			if (strMul.contains("..")) {
				String[] arr = strMul.split("[.][.]");
				strMin = arr[0];
				strMax = arr[1];
			} else {
				strMin = strMax = strMul;
			}
			int lim = cmbPMulMin.getItemCount(), i = 0;
			Set<Object> objList = new HashSet<Object>();
			for (i = 0; i < lim; i++) {
				Object o = cmbPMulMin.getItemAt(i);
				objList.add(cmbPMulMin.getItemAt(i));
				if (o.toString().equals(strMin)) {
					cmbPMulMin.setSelectedIndex(i);
					break;
				}
			}
			if (i == lim) {
				objList.add(strMin);
				cmbPMulMin.setModel(new DefaultComboBoxModel(objList.toArray()));
				cmbPMulMin.setSelectedItem(strMin);
			}
			lim = cmbPMulMax.getItemCount();
			objList.clear();
			for (i = 0; i < lim; i++) {
				Object o = cmbPMulMax.getItemAt(i);
				objList.add(cmbPMulMax.getItemAt(i));
				if (o.toString().equals(strMax)) {
					cmbPMulMax.setSelectedIndex(i);
					break;
				}
			}
			if (i == lim) {
				objList.add(strMax);
				cmbPMulMax.setModel(new DefaultComboBoxModel(objList.toArray()));
				cmbPMulMax.setSelectedItem(strMax);
			}

			pnlParticipant.add(pnlPMul);

			JButton btnDone = new JButton("Done");
			pnlParticipant.add(btnDone);
			btnDone.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					stopCellEditing();
				}
			});

			if (participant.getRelation().getName().startsWith("#aggregation")) {
				txtPRole.setEnabled(false);
				cmbPMulMin.setEnabled(false);
				cmbPMulMax.setEnabled(false);
			}
		}

		@Override
		public void submitValue() {
			dowser.model.Class cPClass = (dowser.model.Class) cmbPClass.getSelectedItem();
			Participant participant = (Participant) m_Entity;
			if (!participant.getParticipatingClass().equals(cPClass)) {
				participant.getParticipatingClass().removeRelation(participant.getRelation());
			}
			try {
				participant.setParticipatingClass(cPClass);
				participant.setRole(txtPRole.getText());
				participant.setMultiplicity(cmbPMulMin.getSelectedItem().toString() + ".." + cmbPMulMax.getSelectedItem().toString());
				cPClass.addRelation(participant.getRelation());
				super.submitValue();
			} catch (IllegalArgumentException ex) {
				JOptionPane.showMessageDialog(null, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
				cancelCellEditing();
			}
		}
	}
	private CellEditorComponent m_component;

	public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
		DomainModel domainModel = ((DomainTreeModel) tree.getModel()).getDomainModel();
		if (value instanceof Participant) {
			m_component = new ParticipantEditorComponent(tree, (Participant) value, domainModel);
		} else if (value instanceof dowser.model.Class || value instanceof Attribute || value instanceof Operation || value instanceof Relation) {
			m_component = new TextCellEditorComponent(tree, (DomainEntity) value, domainModel);
		} else {
			return tree.getCellRenderer().getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, false);
		}
		return m_component.getComponent();
	}

	public void addCellEditorListener(CellEditorListener l) {
		//throw new UnsupportedOperationException("Not supported yet.");
	}

	public void cancelCellEditing() {
		//throw new UnsupportedOperationException("Not supported yet.");
	}

	public Object getCellEditorValue() {
		return m_component.getValue();
	}

	public boolean isCellEditable(EventObject event) {
		if (event == null) {
			return true;
		}
		Object source = event.getSource();
		if (!(source instanceof JTree)) {
			return false;
		}
		JTree tree = (JTree) source;
		if (tree.getSelectionPath() == null) {
			return false;
		}
		Object obj = tree.getSelectionPath().getLastPathComponent();
		if (obj == null) {
			return false;
		}
		if (obj instanceof DomainEntity) {
			if (obj instanceof Relation && ((DomainEntity) obj).getName().startsWith("#aggregation")) {
				return false;
			}
			return true;
		}
		return false;
	}

	public void removeCellEditorListener(CellEditorListener l) {
	}

	public boolean shouldSelectCell(EventObject anEvent) {
		return true;
	}

	public boolean stopCellEditing() {
		m_component.submitValue();
		return true;
	}
}
