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

/*
 * OntologyUI.java
 *
 * Created on May 1, 2010, 9:52:14 PM
 */

package ontology.ui;

import dowser.model.Attribute;
import dowser.model.DomainEntity;
import dowser.model.DomainModel;
import dowser.model.Operation;
import dowser.model.Relation;
import dowser.model.StaticModelValidator;
import dowser.ui.DomainRenderer;
import dowser.ui.DomainTreeEditor;
import dowser.ui.DomainTreeModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.tree.TreePath;

/**
 *
 * @author chepa
 */
public class OntologyUI extends javax.swing.JFrame implements StaticModelValidator.IModelChangeListener {

	private boolean updateDomainEntity(DomainModel model, DomainEntity entity, String newName){
		if (m_DomainModel != model) {
			return false;
		}
		m_DomainModel.renameEntity(entity, newName);
		m_DomainTreeModel.notifyListeners();
		return true;
	}

	public boolean updateOperationName(DomainModel model, Operation operation, String newName) {
		return updateDomainEntity(model, operation, newName);
	}

	public boolean updateAttributeName(DomainModel model, Attribute attrib, String newName) {
		return updateDomainEntity(model, attrib, newName);
	}

	public boolean updateClassName(DomainModel model, dowser.model.Class cClass, String newName) {
		return updateDomainEntity(model, cClass, newName);
	}

	protected DomainTreeModel m_DomainTreeModel = new DomainTreeModel();
	protected DomainModel m_DomainModel = new DomainModel();
	protected DomainRenderer m_DomainRenderer = new DomainRenderer();

	private class ClassPopupMenu extends JPopupMenu {

		private dowser.model.Class m_Class;

		public void setClass(dowser.model.Class cClass) {
			m_Class = cClass;
		}

		public ClassPopupMenu() {
			super();
			{
				final JMenuItem itmAddAttribute = new JMenuItem("Add Attribute");
				itmAddAttribute.addActionListener(new ActionListener() {

					public void actionPerformed(ActionEvent e) {
						int cnt = m_Class.getAttributeCount() + 1;
						String attribName = "_Attribute_" + cnt;
						m_Class.addAttribute(attribName);
						m_DomainTreeModel.notifyListeners();
					}
				});
				add(itmAddAttribute);
			}
			{
				final JMenuItem itmAddOperation = new JMenuItem("Add Operation");
				itmAddOperation.addActionListener(new ActionListener() {

					public void actionPerformed(ActionEvent e) {
						int cnt = m_Class.getOperationCount() + 1;
						String oprnName = "_Operation_" + cnt;
						m_Class.addOperation(oprnName);
						m_DomainTreeModel.notifyListeners();
					}
				});
				add(itmAddOperation);
			}
		}
	}

	private class RelationPopupMenu extends JPopupMenu {

		private Relation m_Relation;

		public void setRelation(Relation relation) {
			m_Relation = relation;
		}

		public RelationPopupMenu() {
			super();
			{
				final JMenuItem itmAddAttribute = new JMenuItem("Add Participant");
				itmAddAttribute.addActionListener(new ActionListener() {

					public void actionPerformed(ActionEvent e) {
						if (m_DomainModel.getClassCount() > 0) {
							int cnt = m_Relation.getParticipantCount();
							String role = "_Role_" + cnt;
							String mul = "1..1";
							if (m_Relation.getName().startsWith("#aggregation")) {
								if (m_Relation.getParticipantCount() >= 2) {
									JOptionPane.showMessageDialog(null, "You can't add more than two classes in an aggregation !", "Error", JOptionPane.ERROR_MESSAGE);
									return;
								}
								role = m_Relation.getParticipantCount() == 0 ? "composite" : "sub-component";
								mul = m_Relation.getParticipantCount() == 0 ? "0..1" : "0..*";
							}
							m_Relation.addParticipant(m_DomainModel.getClass(0), role, mul);
							m_DomainTreeModel.notifyListeners();
						} else {
							JOptionPane.showMessageDialog(null, "No class available as participant !", "Error", JOptionPane.ERROR_MESSAGE);
						}
					}
				});
				add(itmAddAttribute);
			}
		}
	}

	/** Creates new form OntologyUI */
    public OntologyUI() {
        initComponents();
		StaticModelValidator.addListener(this);
		m_DomainTreeModel.setModel(getOntologyModel());

		this.addWindowListener(new WindowAdapter() {

			@Override
			public void windowOpened(WindowEvent e) {
				setExtendedState(JFrame.MAXIMIZED_BOTH);
			}
		});

		final JPopupMenu modelPopMenu = new JPopupMenu();
		{
			final JMenuItem itmAddClass = new JMenuItem("Add Class");
			itmAddClass.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					DomainModel model = m_DomainTreeModel.getDomainModel();
					int cnt = model.getClassCount() + 1;
					model.addClass(new dowser.model.Class("_Class_" + cnt));
					m_DomainTreeModel.notifyListeners();
				}
			});

			modelPopMenu.add(itmAddClass);
		}
		{
			final JMenuItem itmAddRelation = new JMenuItem("Add Relation");
			itmAddRelation.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					if (m_DomainModel.getClassCount() != 0) {
						int cnt = m_DomainModel.getRelationCount() + 1;
						Relation r = new Relation("_Relation_" + cnt);
						m_DomainModel.addRelation(r);
						m_DomainTreeModel.notifyListeners();
					} else {
						JOptionPane.showMessageDialog(null, "You can't add a relation without any class", "Error", JOptionPane.ERROR_MESSAGE);
					}
				}
			});

			modelPopMenu.add(itmAddRelation);
		}

		{
			final JMenuItem itmAddAggregation = new JMenuItem("Add Aggregation");
			itmAddAggregation.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					if (m_DomainModel.getClassCount() != 0) {
						Relation r = new Relation("#aggregation");
						m_DomainModel.addRelation(r);
						m_DomainTreeModel.notifyListeners();
					} else {
						JOptionPane.showMessageDialog(null, "You can't add an aggregation without any class", "Error", JOptionPane.ERROR_MESSAGE);
					}
				}
			});

			modelPopMenu.add(itmAddAggregation);
		}


		final ClassPopupMenu classMenu = new ClassPopupMenu();
		final RelationPopupMenu relationMenu = new RelationPopupMenu();

		trStaticModel.setSelectionModel(null);
		trStaticModel.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					TreePath path = trStaticModel.getClosestPathForLocation(e.getX(), e.getY());
					if (path == null) {
						return;
					}
					Object obj = path.getLastPathComponent();
					if (obj == null) {
						return;
					}
					if (!(obj instanceof DomainEntity)) {
						return;
					}
					trStaticModel.setEditable(true);
					trStaticModel.startEditingAtPath(path);
				}
			}

			@Override
			public void mousePressed(MouseEvent e) {
				trStaticModel.setEditable(false);
				processTrigger(e);
			}

			private void processTrigger(MouseEvent e) {
				if (e.isPopupTrigger()) {
					TreePath path = trStaticModel.getClosestPathForLocation(e.getX(), e.getY());
					if (path != null) {
						Object obj = path.getLastPathComponent();
						if (obj == null) {
							return;
						}
						if (obj instanceof DomainModel) {
							modelPopMenu.show(trStaticModel, e.getX(), e.getY());
							return;
						}
						if (obj instanceof dowser.model.Class) {
							classMenu.setClass((dowser.model.Class) obj);
							classMenu.show(trStaticModel, e.getX(), e.getY());
							return;
						}
						if (obj instanceof Relation) {
							relationMenu.setRelation((Relation) obj);
							relationMenu.show(trStaticModel, e.getX(), e.getY());
							return;
						}
					}
				}
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				trStaticModel.setEditable(false);
				processTrigger(e);
			}
		});
    }

		public static OntologyUI getInstance() {
		if (m_Instance == null) {
			m_Instance = new OntologyUI();
		}
		return m_Instance;
	}

	public DomainModel getOntologyModel(){
		if(m_DomainModel == null)
			m_DomainModel = new DomainModel();
		return m_DomainModel;
	}


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        trStaticModel = new javax.swing.JTree(m_DomainTreeModel);
        jMenuBar1 = new javax.swing.JMenuBar();
        mnuFile = new javax.swing.JMenu();
        mnuValidateOnto = new javax.swing.JMenuItem();

        trStaticModel.setCellEditor(new DomainTreeEditor());
        trStaticModel.setCellRenderer(m_DomainRenderer);
        jScrollPane1.setViewportView(trStaticModel);

        mnuFile.setText("File");

        mnuValidateOnto.setText("Validate Ontology");
        mnuValidateOnto.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuValidateOntoActionPerformed(evt);
            }
        });
        mnuFile.add(mnuValidateOnto);

        jMenuBar1.add(mnuFile);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 421, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 421, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 288, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(1, 1, 1)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 287, Short.MAX_VALUE)))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

	private void mnuValidateOntoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuValidateOntoActionPerformed
		StaticModelValidator.ValidateModel(getOntologyModel());
	}//GEN-LAST:event_mnuValidateOntoActionPerformed

	private static OntologyUI m_Instance;
    /**
    * @param args the command line arguments
	 */
	public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {

			public void run() {
				getInstance().setVisible(true);
			}
		});
	}

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JMenu mnuFile;
    private javax.swing.JMenuItem mnuValidateOnto;
    private javax.swing.JTree trStaticModel;
    // End of variables declaration//GEN-END:variables

}
