// File: ConstEdgePanel.java
// Classes: ConstEdgePanel
// Author: Kedar Patankar

package EDU.neu.ccs.demeter.tools.apstudio.graphedit;

import java.awt.Panel;
import java.awt.TextField;
import java.awt.Choice;
import java.awt.Color;

import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import EDU.neu.ccs.demeter.tools.apstudio.ui.PropsGridLayout;

/* Purpose : Property sheet for construction edges and repetition edges. This displays as well allows to modify 
the properties 
*/

public class ConstEdgePanel extends Panel implements ActionListener, FocusListener, ItemListener
{
	private Editor _editor;
	private PropertyWindow _pw;

	private String _edgeName,_before,_after,_cardinality,_from,_to,_panicName;

	private TextField _edgeNameText,_beforeText,_afterText,_fromText,_toText;
	private Choice _cardinalityChoice;
	private Choice _partModifierChoice; // not implemented

	private UConstEdge _edge;

	public ConstEdgePanel(Editor editor,PropertyWindow pw) // constructor
	{
		_editor = editor;
		_pw = pw;
		setLayout(new PropsGridLayout(5,5));
		TextField edgeNameLabel,beforeLabel,afterLabel,cardinalityLabel,modifierLabel,fromLabel,toLabel;

		edgeNameLabel = new TextField("Edge Name");
		beforeLabel = new TextField("Syntax:Before");
		afterLabel= new TextField("Syntax:After");
		cardinalityLabel = new TextField("Cardinality");
		modifierLabel = new TextField("Edge Modifier");
		fromLabel = new TextField("From");
		toLabel = new TextField("To");

		edgeNameLabel.setEditable(false);
		beforeLabel.setEditable(false);
		afterLabel.setEditable(false);
		cardinalityLabel.setEditable(false);
		modifierLabel.setEditable(false);
		fromLabel.setEditable(false);
		toLabel.setEditable(false);

		_edgeNameText = new TextField();
		_beforeText = new TextField();
		_afterText = new TextField();
		_edgeNameText.addActionListener(this);
		_beforeText.addActionListener(this);
		_afterText.addActionListener(this);
		_edgeNameText.addFocusListener(this);
		_beforeText.addFocusListener(this);
		_afterText.addFocusListener(this);

		_cardinalityChoice = new Choice();
		_cardinalityChoice.addItem("1");
		_cardinalityChoice.addItem("0..1");
		_cardinalityChoice.addItem("0..*");
		_cardinalityChoice.addItem("1..*");
		_cardinalityChoice.addItemListener(this);

		_partModifierChoice = new Choice();
		_partModifierChoice.addItem("None");
		_partModifierChoice.addItem("Final");
		_partModifierChoice.addItem("Static");
		_partModifierChoice.addItem("private");
		_partModifierChoice.addItem("Read Only");
		_partModifierChoice.setEnabled(false);

		_fromText = new TextField();
		_toText = new TextField();

		_fromText.setEditable(false);
		_toText.setEditable(false);

		add(edgeNameLabel);
		add(_edgeNameText);
		add(beforeLabel);
		add(_beforeText);
		add(afterLabel);
		add(_afterText);
		add(cardinalityLabel);
		add(_cardinalityChoice);
		add(modifierLabel);
		add(_partModifierChoice);
		add(fromLabel);
		add(_fromText);
		add(toLabel);
		add(_toText);
		setBackground(Color.lightGray);
	}

// Display the values for the first time. This method shows construction edge
	public void setValues(UConstEdge e,String name,String cardinality,String before,String after,String from, String to)
	{
		_edgeName = name;
		_panicName = name; // This name is used as default when the cardinality is changed.
		// Repetition edges can't have names but user can switch between repetition and construction edge very
		// easily.
		_edge = e;

		if(name == null)
		{
			ArcPerspective a = _edge.get_persp();

			String edgeName = a.get_DestinationName();
			Perspective p = a.get_sourcePerspective();
			UConstOrAltVertex u = (UConstOrAltVertex)p.owner();

			edgeName = edgeName.toLowerCase();

			if(u.checkThisOut(edgeName))
			{
				int count =0;
				for(boolean found = true;found;)
				{
					count++;
					String trialName = edgeName + count;
					found = u.checkThisOut(trialName);
				}
				edgeName = edgeName +"_"+ count;
			}
			_panicName = edgeName;
			_edgeNameText.setText("Not Applicable");
			_edgeNameText.setEditable(false);
			_edgeNameText.setEnabled(false);
		}
		else
		{
			_edgeNameText.setText(name);
			_edgeNameText.setEditable(true);
			_edgeNameText.setEnabled(true);
		}

		if(before == null)
		{
			_beforeText.setText("");
			_before = null;
		}
		else
		{
			_beforeText.setText(before);
			_before = before;
		}

		if(after == null)
		{
			_afterText.setText("");
			_after =null;
		}
		else
		{
			_afterText.setText(after);
			_after = after;
		}

		_fromText.setText(from);
		_toText.setText(to);

		int index=0;
		
		if ("1".equals(cardinality)) index = 0;
		else if ("0..1".equals(cardinality)) index = 1;
		else if ("0..*".equals(cardinality)) index = 2;
		else if ("1..*".equals(cardinality)) index = 3;

		_cardinalityChoice.select(index);
		_partModifierChoice.select(0);
	}

// Event handling. Need to consider only ActionEvent and FocusEvent
// All changes are made only when user presses enter key and the new value is appropriate.
// If the focus is lost before hitting enter key old value is restored.
	public void actionPerformed(ActionEvent event)
	{
		Object source = event.getSource();

		if(source == _edgeNameText)
		{
			String newName = _edgeNameText.getText().trim();
// Validating the new name
			if(newName.length()<=0)
			{
				_pw.showMessage("Name is compulsory");
				return;
			}

			String oldName;
			if(_edgeName == null)
				oldName ="";
			else
				oldName = _edgeName;

			if(oldName.equals(newName))
			{
				_pw.setDefaultMessage();
				return;
			}

			PartName pn;
			try{
			pn = PartName.parse(newName); // see if it is parsable
			}catch(RuntimeException pe)
			{
				_pw.showMessage("Not a valid part name. Name contains illegal characters");
				_edgeNameText.requestFocus();
				_edgeNameText.select(0,_edgeName.length());
				return;
			}

			if(!newName.equals(pn.get_name().toString())) // see if parser accepted whole string as one thing
			{
				_pw.showMessage("Error: Parser interpreted differently");
				_edgeNameText.requestFocus();
				_edgeNameText.select(0,_edgeName.length());
				return;
			}

			String from = _fromText.getText();
			UID id = _editor.curDocument().net().nameToUID(from);
			UConstOrAltVertex u = (UConstOrAltVertex) _editor.curDocument().net().getNode(id);
			boolean found = u.checkThisOut(newName);
			if(found) // check if the edge name is already used for the source vertex
			{
				_pw.showMessage("Edge name already used");
				_edgeNameText.requestFocus();
				_edgeNameText.select(0,_edgeName.length());
				return;
			}
			setEdgeName(newName);

			_panicName=newName;
			_editor.curDocument().damaged(_edge.get_persp());
		}
		else
		if(source == _beforeText) // handle before syntax
		{
			String before = _beforeText.getText().trim();

			if(before.length()>0)
			{
				_edge.set_beforeSyntax(before);
				_before = before;
			}
			else
			{
				_edge.set_beforeSyntax(null);
				_before=null;
			}
		}
		else
		{  // handle after syntax
			String after = _afterText.getText().trim();

			if(after.length()>0)
			{
				_edge.set_afterSyntax(after);
				_after = after;
			}
			else
			{
				_edge.set_afterSyntax(null);
				_after = null;
			}
		}
		_editor.curDocument().cdNeedsSaving(true);
		_pw.setDefaultMessage();
	}
	public void focusGained(FocusEvent event){}
	public void focusLost(FocusEvent event)
	{
		Object source = event.getSource();
		if(source == _edgeNameText)
			restoreName();
		else
		if(source == _beforeText)
			restoreBefore();
		else
			restoreAfter();
	}


	private void restoreName()
	{
		_edgeNameText.setText(_edgeName);
	}

	private void restoreBefore()
	{
		if(_before==null)
			_beforeText.setText("");
		else
			_beforeText.setText(_before);
	}
	private void restoreAfter()
	{
		if(_after==null)
			_afterText.setText("");
		else
			_afterText.setText(_after);
	}

	public void setEdgeName(String name)
	{
		_edgeName = name;

		if(name == null)
		{
			_edgeNameText.setText("Not Applicable");
			_edgeNameText.setEditable(false);
			_edgeNameText.setEnabled(false);
		}
		else
		{
			_edgeNameText.setText(name);
			_edgeNameText.setEditable(true);
			_edgeNameText.setEnabled(true);
		}
		
		((FigConstEdge)_edge.get_persp().get_figure()).set_label(name);
		_edge.set_label(_editor.curDocument(),name);
	}

	public void itemStateChanged(ItemEvent event)
	{
		int index = _cardinalityChoice.getSelectedIndex();
		switch (index)
		{
		case 0 : ((FigConstEdge)_edge.get_persp().get_figure()).set_cardinality("1");
				setEdgeName(_panicName);break;
		case 1 : ((FigConstEdge)_edge.get_persp().get_figure()).set_cardinality("0..1");
				setEdgeName(_panicName);break;
		case 2 : UVertex u = (UVertex) _edge.get_persp().get_sourcePerspective().owner();
			     if(u instanceof UAltVertex)
				 {
					String cardinality = ((FigConstEdge)_edge.get_persp().get_figure()).get_cardinality();
					if(cardinality.equals("1")) _cardinalityChoice.select(0);
					else _cardinalityChoice.select(1);
					_pw.showMessage("Abstract classes can't have repetition edges");
					return;
				 }
				if(u instanceof UConstVertex && _edgeName!=null)
				{
					if ( ((UConstVertex)u).isCrackingRepetition() )
					{
						String cardinality = ((FigConstEdge)_edge.get_persp().get_figure()).get_cardinality();
						if(cardinality.equals("1")) _cardinalityChoice.select(0);
						else _cardinalityChoice.select(1);
						_pw.showMessage("Repetition class can't have parts");
						return;
					}
				}
				((FigConstEdge)_edge.get_persp().get_figure()).set_cardinality("0..*");
				setEdgeName(null);break;
		case 3 : UVertex v = (UVertex) _edge.get_persp().get_sourcePerspective().owner();
			     if(v instanceof UAltVertex)
				 {
					String cardinality = ((FigConstEdge)_edge.get_persp().get_figure()).get_cardinality();
					if(cardinality.equals("1")) _cardinalityChoice.select(0);
					else _cardinalityChoice.select(1);
					_pw.showMessage("Abstract classes can't have repetition edges");
					return;
				 }
				if(v instanceof UConstVertex && _edgeName!=null)
				{
					if ( ((UConstVertex)v).isCrackingRepetition() )
					{
						String cardinality = ((FigConstEdge)_edge.get_persp().get_figure()).get_cardinality();
						if(cardinality.equals("1")) _cardinalityChoice.select(0);
						else _cardinalityChoice.select(1);
						_pw.showMessage("Repetition class can't have parts");
						return;
					}
				}
				((FigConstEdge)_edge.get_persp().get_figure()).set_cardinality("1..*");
				setEdgeName(null);break;
		}

		_editor.curDocument().damaged(_edge.get_persp());
		_editor.curDocument().cdNeedsSaving(true);
	}
} /*  end class ConstEdgePanel */
