package surface.classeditor;

import hu.swankey.ammo.common.script.yunits.YClass;
import hu.swankey.ammo.common.script.yunits.YUnit;
import hu.swankey.ammo.common.yggdrasil.basics.Reference;
import hu.swankey.ammo.common.yggdrasil.basics.YObject;
import hu.swankey.ammo.common.yggdrasil.basics.ComplexYObject.ComplexYClass;
import hu.swankey.ammo.common.yggdrasil.definition.Definition;
import hu.swankey.ammo.common.yggdrasil.definition.YAttributeDefinition;
import hu.swankey.ammo.common.yggdrasil.definition.YClassDefinition;
import hu.swankey.ammo.common.yggdrasil.definition.YMethodDefinition;
import hu.swankey.ammo.common.yggdrasil.definition.YPackageDefinition;
import hu.swankey.ammo.common.yggdrasil.ext.Universe;
import hu.swankey.ammo.common.yggdrasil.ext.World;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.border.Border;
import javax.swing.tree.TreePath;

import surface.CommandBar;
import surface.SelectorTree;
import adapters.FieldListModel;
import adapters.MethodListModel;
import adapters.SuperiorTreeModel;
import background.Controller;
import client_engine.IClientControllerListener;

public class ClassEditor extends JPanel implements IClientControllerListener /*, TreeModelListener*/ {
	
	private static final long serialVersionUID = 1L;

	private static final String MSG_NOT_A_CLASS = "Please select a class!";
	
	private ImageIcon icon = new ImageIcon( new ImageIcon(getClass().getResource("/icons/brick.png")).getImage().getScaledInstance(30, 30, java.awt.Image.SCALE_SMOOTH));
	
	//private static final String MSG_SELECTION_IS_THE_COMPLEX_CLASS = "Cannot edit the '" + Complex.yclass().getName() + "' class, sorry!";
	
	
//	private static final String TITLE_PRIMARY_SELECTION = "Primary selection:";
//	private static final String TITLE_SECONDARY_SELECTION = "Secondary selection:";
	
	private static final String LABEL_SUPERIORS = "Superiors:";
	private static final String LABEL_FIELDS = "Fields:";
	private static final String LABEL_METHODS = "Methods:";
	
	private static final String TITLE_CLASSES1 = "Edited class";
	private static final String TITLE_CLASSES2 = "Selected class";
	
//	private static final String BUTTON_NEW_CLASS = "Create class";
//	private static final String BUTTON_ADD_SUPERIOR = "Add superior";
	
//	private static final int NAME_WIDTH = 20;
//	private static final int FIELD_HEIGHT = 24;
	
	private final Controller controller;
//	private ClassDefinition classdef;
	
	//private JComponent centralArea;
//	private YggdrasilTreeModel model;
	
	private final int DIVIDER_SIZE = 3;
	private final int GAP_SIZE = 5;
//	private final int RIGID_SIZE = 10;
	private final int CLASS_SELECTOR_WIDTH = 240;
	
	
	
	private final Font fontTitle = getFont().deriveFont(Font.BOLD);
	private final Font fontClassName = getFont().deriveFont(Font.BOLD, 18);
	
	private final Border borderSection = BorderFactory.createEmptyBorder(10, 15, 0, 0);
	private final Border borderPageTitle = BorderFactory.createEmptyBorder(20, 10, 10, 10);
	private final Border innerBorder = BorderFactory.createEmptyBorder(0, 20, 0, 0);
	//private final Border innerBorder2 = BorderFactory.createEmptyBorder(0, 12, 0, 0);
	
	private final JScrollPane centralArea;
	
	private final JLabel label_notaclass = new JLabel(MSG_NOT_A_CLASS, JLabel.CENTER);
	private final JPanel classEditorPanel;
	
	private final JLabel label_className;
	private final JLabel label_fields;
	private final JLabel label_methods;
	
	private final SuperiorTree tree_superiors;
	private final FieldList list_fields;
	private final MethodList list_methods;
	
	private final SelectorTree tree_classes;
	private final SelectorTree tree_classes2;
	
	
	public static ClassEditor createClassEditor(Controller controller){
		ClassEditor editor = new ClassEditor(controller);
		controller.addListener(editor);
		return editor;
	}
	
	private ClassEditor(final Controller controller){
		this.controller = controller;
				
		
		setLayout (new BorderLayout(GAP_SIZE, GAP_SIZE) );
		
		
		// Classes:
		tree_classes = SelectorTree.createClassSelector(TITLE_CLASSES1, controller, true, YClass.singleton());

		
		// Classes2:
		tree_classes2 = SelectorTree.createClassSelector(TITLE_CLASSES2, controller, false, YClass.singleton());
		
		
		
		// SplitPane:
		
		JSplitPane jsplit_selectors = new JSplitPane( JSplitPane.VERTICAL_SPLIT, tree_classes, tree_classes2 );
		jsplit_selectors.setDividerSize(DIVIDER_SIZE);
		jsplit_selectors.setDividerLocation(0.5);
		jsplit_selectors.setResizeWeight(0.5);
		jsplit_selectors.setPreferredSize( new Dimension(CLASS_SELECTOR_WIDTH, Short.MAX_VALUE) );
				
		
		JPanel jpanel_right = new JPanel();
		jpanel_right.setLayout( new BoxLayout(jpanel_right, BoxLayout.Y_AXIS) );
		jpanel_right.add( jsplit_selectors );
		
		
		
		CommandBar commandBar = CommandBar.createCommandBar(controller, false);
		
		jpanel_right.add( commandBar.addHiddenCommand(
		        "New Class", Reference.ROOT_SYMBOL + ".classes.def.ComplexClassDef.new(name:%S(name));", "def.YPackageDefinition", null));
		
		jpanel_right.add( commandBar.addHiddenCommand(
                "New Method", "addMethod( method: root.classes.def.MethodDef.new(name:%S(name)));", "def.YClassDefinition", null) );
        jpanel_right.add( commandBar.addHiddenCommand(
                "Remove Method", "removeMethod( method: %2);", "def.YClassDefinition", "def.YMethodDefinition") );
		
		jpanel_right.add( commandBar.addHiddenCommand(
				"Add as Superior", "addSuperior(yclass:%2);", "def.YClassDefinition", "def.YClassDefinition"));
		jpanel_right.add( commandBar.addHiddenCommand(
				"Remove Superior", "removeSuperior(yclass:%2);", "def.YClassDefinition", "def.YClassDefinition") );
		
		jpanel_right.add( commandBar.addHiddenCommand(
				"New Field", "addField(yclass:%2, name:%S(name));", "def.ComplexYClassDefinition", "def.YClassDefinition") );
        jpanel_right.add( commandBar.addHiddenCommand(
                "Remove Field", "removeField(field:%2);", "def.ComplexYClassDefinition", "def.YAttributeDefinition") );
		
		jpanel_right.add( commandBar.addHiddenCommand(
				"Edit Source", "%2.setSource(source:%C(source));", null, "def.Definition") );
		
//		jpanel_right.add( controller.getCommandBar().addHiddenCommand(
//				"Add Element", "addField(yclass:%2, name:%S(name))", "def.ComplexClassDef") );		
		
		
		add( jpanel_right, BorderLayout.LINE_END );
		
		
		add(centralArea = new JScrollPane());
		
		/* --- EDITOR PANEL --- */
		classEditorPanel = new JPanel();
		classEditorPanel.setLayout( new BoxLayout(classEditorPanel, BoxLayout.Y_AXIS) );		
		
		// Title:
		JPanel titlePanel = new JPanel();		
		titlePanel.setLayout( new BoxLayout(titlePanel, BoxLayout.X_AXIS) );
		titlePanel.setAlignmentX(0);
		titlePanel.setBorder(borderPageTitle);
		label_className = new JLabel();
		label_className.setFont( fontClassName );
		label_className.setBorder( borderSection );
		//ImageIcon img = new ImageIcon( new ImageIcon(controller.getClass().getResource("/icons/brick.png")).getImage().getScaledInstance(30, 30, java.awt.Image.SCALE_SMOOTH) );		
		titlePanel.add( new JLabel( icon ));
		titlePanel.add(label_className);
		
		// Superiors:
		JLabel label_superiors = new JLabel(LABEL_SUPERIORS);
		label_superiors.setFont(fontTitle);
		label_superiors.setBorder(borderSection);
		tree_superiors = SuperiorTree.createSuperiorTree(YObject.yclass(), controller);
		tree_superiors.setAlignmentX(0);
		tree_superiors.setBorder(innerBorder);
		tree_superiors.setBackground(null);
		
		// Fields:
		label_fields = new JLabel(LABEL_FIELDS);
		label_fields.setFont(fontTitle);
		label_fields.setBorder(borderSection);
		list_fields = FieldList.create(controller);
		list_fields.setAlignmentX(0);
		list_fields.setBorder(innerBorder);
		list_fields.setBackground(null);
		
		//Methods:
		label_methods = new JLabel(LABEL_METHODS);
		label_methods.setFont(fontTitle);
		label_methods.setBorder(borderSection);
		list_methods = MethodList.create(controller);
		list_methods.setAlignmentX(0);
		list_methods.setBorder(innerBorder);
		list_methods.setBackground(null);
		
		//classEditorPanel.setBackground( new Color(0xe5dba2) );
		classEditorPanel.add(titlePanel);
		classEditorPanel.add(label_superiors);
		classEditorPanel.add(tree_superiors);
		classEditorPanel.add(label_fields);
		classEditorPanel.add(list_fields);
		classEditorPanel.add(label_methods);
		classEditorPanel.add(list_methods);	
		
		primaryElementChanged(controller.getPrimaryElement());
	}
	
	
//	private void refresh(){
//		if (controller.p)
//	}
	
	
//	public void regenerate(){
//		Element selected = controller.getPrimaryElement();
//		
//		if (model != null)
//			model.removeTreeModelListener(this);
//		model = controller.getYggdrasil().getTreeModel(selected);
//		model.addTreeModelListener(this);
//		
//		if (selected instanceof ClassDefinition)
//			classdef = (ClassDefinition)selected;
//		else
//			classdef = null;
//		
////		if (centralArea != null)
////			remove(centralArea);
////	
////		add( centralArea, BorderLayout.CENTER );
//		repaint();
//	}
	
	
//	private JPanel createEditorPanel(){
//
//
//		//JLabel label_className = new JLabel();
//		
//
//
//			
//	
//		//editorPanel.add( label_className );
//		//editorPanel.add( Box.createRigidArea(new Dimension(	0, RIGID_SIZE)) );
//		editorPanel.add( superiorsEditor );
//	
//		return editorPanel;
//	}
	
//	public JComponent createNameEditor(){
//		JPanel nameEditor = new JPanel();
//		
//		// Layout & border:
//		nameEditor.setLayout( new BoxLayout(nameEditor, BoxLayout.Y_AXIS) );
//		nameEditor.setBorder( sectionBorder );
//		
//		// Name field:
//		//JTextField nameField = new JTextField( classdef.getName(), NAME_WIDTH );
//		//nameField.setMaximumSize( new Dimension(200, FIELD_HEIGHT) );
//				
//		// Add components:
//		nameEditor.add( new JLabel( LABEL_CLASS_NAME ) );
//		//nameEditor.add( Box.createRigidArea(new Dimension(RIGID_SIZE, RIGID_SIZE)) );
//		//nameEditor.add( nameField );
//		return nameEditor;
//	}
	
	public JPanel createSuperiorsEditor(){		
		JPanel superiorsEditor = new JPanel();
		
		superiorsEditor.setLayout(  new BoxLayout(superiorsEditor, BoxLayout.Y_AXIS) );		
		superiorsEditor.setBorder( borderSection );
//		superiorsEditor.add( Box.createRigidArea(new Dimension(RIGID_SIZE, RIGID_SIZE)) );
		
		
		//List<YClass> superiors = gatherAllSuperiors( classdef.getWrapped() );
		
		// Superiors:
		JLabel label_title =  new JLabel( LABEL_SUPERIORS );
		//label_title.setFont( titleFont );
		superiorsEditor.add( label_title );
		
		
		
		//SuperiorTree sTree = SuperiorTree.createSuperiorTree(Element.yclass(), controller);

		//superiorTree.setAlignmentX(0);
		//superiorsEditor.add( superiorTree );	
		
//		for( YClass superior: classdef.getWrapped().getSuperiors() ){
//			//Element cdefE = ((SoftLink)linkE).getTarget( controller.getRootPackage() );
//			if (superior instanceof ComplexClass) {
//				JComponent sPanel =  createSuperiorPanel( superior );
//				sPanel.setAlignmentX(0);
//				sPanel.setBorder(innerBorder);
//				superiorsEditor.add( sPanel );
//			}
//		}		
		
		// Fields:
//		superiorsEditor.add( new JLabel( LABEL_FIELDS ) );
//		for(YClass superior: superiors){
//			if (superior instanceof ComplexClass)
//			for(Element vdefE: ((ComplexClass)superior).getElements() ){
//				VariableDefinition vdef = (VariableDefinition) vdefE;
//				JComponent attrPanel =  createAttributePanel(vdef, (ComplexClass)superior);
//				attrPanel.setAlignmentX(0);
//				attrPanel.setBorder(innerBorder);
//				superiorsEditor.add( attrPanel );
//			}
//		}
		
		// Methods:
//		superiorsEditor.add( new JLabel( LABEL_METHODS ) );
//		for(Procedure method: gatherMethodsDefinitions(superiors)){
//			JComponent mPanel =  createMethodPanel(method);
//			mPanel.setAlignmentX(0);
//		    mPanel.setBorder(innerBorder);
//			superiorsEditor.add( mPanel );
//		}		
		
		//superiorsEditor.add( Box.createRigidArea(new Dimension(RIGID_SIZE, RIGID_SIZE)) );
		return superiorsEditor;
	}
	
//	public JComponent createExtensionPanel(SoftLink linkToSuperior){
//		JPanel superiorPanel = new JPanel();
//		BoxLayout layout = new BoxLayout(superiorPanel, BoxLayout.Y_AXIS);
//		Border border = BorderFactory.createEmptyBorder(0, 20, 0, 0);	
//
//		JLabel label = new JLabel(linkToSuperior.getValue());
//				
//		superiorPanel.setLayout( layout );
//		superiorPanel.setBorder( border );
//		superiorPanel.add( label );
//		superiorPanel.add( Box.createRigidArea( new Dimension(0, RIGID_SIZE) ) );
//		
//		Element classdef = linkToSuperior.getTarget( linkToSuperior.getParent().getTypeContainer() );
//		List<ComplexClassDefinition> superiors = gatherAllSuperiors(  (ComplexClassDefinition)classdef );		
//					
//
//		
//		
//		return superiorPanel;
//	}
	
	
//	private List<YClass> gatherAllSuperiors(YClass cclass){
//		ArrayList<YClass> list = new ArrayList<YClass>();
//		list.add(cclass);
//		
//		
//		for (YClass superior: cclass.getSuperiors() )
//		if (superior instanceof ComplexClass && !(list.contains(superior)) )
//			list.addAll( gatherAllSuperiors((ComplexClass)superior) );
//
//		
//		return list;
//	}
	
//	private List<Procedure> gatherMethodsDefinitions( List<YClass> cclasses){
//		List<Procedure> list = new ArrayList<Procedure>();
//		
//		for(YClass cclass: cclasses)
//		for(ArrayList<Procedure> methodList: cclass.getMethods().values() )
//		for(Procedure method: methodList)
//		if (!(list.contains(method)))
//			list.add(method);
//
//		return list;
//	}
	
//	private JTree createSuperiorsTree(YClass yclass){
//		Vector<YClass> rootVector = new Vector<YClass>();
//		rootVector.add(yclass);
//		
//		JTree jtree = new JTree(rootVector);
//		
//		jtree.setCellRenderer( new SuperiorNodeRenderer() );
//		
//		return jtree;
//	}
	
	
	

	
	
//	private JPanel createSuperiorsTree(YClass yclass){
//		
//		HashMap<YClass, ArrayList<JPanel>> panels = new HashMap<YClass, ArrayList<JPanel>>();
//		
//		JPanel elementPanel = createSuperiorPanel(Element.yclass());
//		ArrayList<JPanel> panelList = new ArrayList<JPanel>();
//		panelList.add(elementPanel);		
//		panels.put(Element.yclass(), panelList);
//		
//		createSuperiorsTree(yclass, panels);
//		return elementPanel;
//	}
	
	
//	private ArrayList<JPanel> createSuperiorsTree(YClass yclass, HashMap<YClass, ArrayList<JPanel>> panels){
//		
//		// Az osztályhoz tartozó panelek kikeresése:
//		ArrayList<JPanel> panelList = panels.get(yclass);
//		
//		// Ha nincsenek, létrehozzuk őket:
//		if (panelList == null) {
//			
//			panelList = new ArrayList<JPanel>();		
//					
//			// Minden őshöz csinálunk egyet (hisz bármely ős eltávolításával a leszármazottak is mind eltávolítódnak)
//			for (YClass superior: yclass.getSuperiors()) {
//				List<JPanel> superiorPanels = createSuperiorsTree(superior, panels);
//								
//				// Minden ős minden panéljéhez hozzáadjuk az osztályhoz tartozó panelt:
//				for(JPanel superiorPanel: superiorPanels) {
//					
//					JPanel panel = createExtendedSuperiorPanel(yclass);
//					
//					panelList.add( panel );
//					panels.put(yclass, panelList);					
//					
//					superiorPanel.add(panel);
//				}
//			}
//		}
//		
//		return panelList;
//	}
	
//	private JPanel createExtendedSuperiorPanel(YClass yclass){
//		JPanel extendedPanel = new JPanel();
//		extendedPanel.setLayout( new BoxLayout(extendedPanel, BoxLayout.Y_AXIS) );		
//		extendedPanel.add( createSuperiorPanel(yclass) );
//		extendedPanel.setBorder( innerBorder2 );
//		
//		return extendedPanel;
//	}
	

	
//	private JPanÍ
	
	
//	private JComponent createAttributePanel(VariableDefinition vdef, ComplexClass owner){
//		JPanel attrPanel = new JPanel();
//		BoxLayout layout = new BoxLayout(attrPanel, BoxLayout.X_AXIS);
//		//Border border = BorderFactory.createEmptyBorder(0, 20, 0, 0);
//		
//		
//		
//		
//		attrPanel.setLayout(layout);
//		//attrPanel.setBorder(border);
//		//attrPanel.add( labDelete );
//		attrPanel.add( new JLabel(vdef.getName() + ":" ) );
//		attrPanel.add( Box.createRigidArea( new Dimension(RIGID_SIZE, 0) ) );
//		attrPanel.add( new JLabel(vdef.getClassLink().getValue()) );
//		attrPanel.add( Box.createRigidArea( new Dimension(RIGID_SIZE, 0) ) );
//		attrPanel.add( new JLabel("(" + owner.getName() + ")") );
//		
//		
//	
//		return attrPanel;
//	}
	
//	private JComponent createMethodPanel(Procedure method){
//		JPanel mPanel = new JPanel();
//		
//		mPanel.setLayout( new BoxLayout(mPanel, BoxLayout.X_AXIS) );
//		mPanel.add( new JLabel( method.getReturnType().getName() ) );
//		mPanel.add( Box.createRigidArea( new Dimension(RIGID_SIZE, 0) ) );
//		mPanel.add( new JLabel(method.toString()) );
////		mPanel.add( new JLabel("(" + method.getP .getContainerClass().getName() + ")") );
//		
//		return mPanel;
//	}


	@Override
	public void cursorChanged(Dimension cursor) {
	}

	@Override
	public void primaryElementChanged(YObject newElement) {		
		
		YClass primary = null;

		if (controller.getPrimaryElement() instanceof YClassDefinition)
			primary = ((YClassDefinition)controller.getPrimaryElement()).getWrapped();
		
		
		if (primary != null) {
			
			// Class name:
			label_className.setText( primary.getName() );
			
			// Superior tree:
			tree_superiors.setModel( SuperiorTreeModel.createSuperiorTreeModel(primary, controller.getYggdrasil()) );
			

			list_methods.setModel( MethodListModel.create(primary, controller.getYggdrasil()) );
			
			// Field & method lists:
			if (primary instanceof ComplexYClass) {
				list_fields.setModel( FieldListModel.create((ComplexYClass)primary, controller.getYggdrasil()) );
				label_fields.setVisible(true);
				list_fields.setVisible(true);			
			} else {
				list_fields.setVisible(false);
				label_fields.setVisible(false);
			}
			
			// Switch to the editor:
			centralArea.setViewportView(classEditorPanel);
			
		} else {
			centralArea.setViewportView(label_notaclass);
		}
		
		secondaryElementChanged( controller.getSecondaryElement() );
	}

	@Override
	public void secondaryElementChanged(YObject newElement) {
		
		if (controller.getPrimaryElement() != null) {
			YObject secondary = controller.getSecondaryElement();
			
			
			// Secondary selection:
			if (secondary != null && (secondary instanceof YClassDefinition) || (secondary instanceof YPackageDefinition)) {
				Definition def = (Definition)secondary;
				
				List<YObject> path = new ArrayList<YObject>();
				for(YUnit yunit: ((YUnit)def.getWrapped()).getPath())
					path.add(yunit.getWrapperElement());
				
				//TreePath treePath = new TreePath(path.toArray());
				//tree_classes2.setSelectionPath( treePath );
				//tree_classes2.setSelection( def );
				//tree_classes2.scrollRowToVisible( tree_classes2.getRowForPath(treePath) );
			}	

			// Field selection:
			if (secondary instanceof YAttributeDefinition && ((FieldListModel)list_fields.getModel()).contains((YAttributeDefinition)secondary))
				list_fields.setSelectedValue(controller.getSecondaryElement(), true);
			else
				list_fields.clearSelection();
			
			// Method selection:
			if (secondary instanceof YMethodDefinition && ((MethodListModel)list_methods.getModel()).contains((YMethodDefinition)secondary))
				list_methods.setSelectedValue(controller.getSecondaryElement(), true);
			else
				list_methods.clearSelection();			
			
			// Superior selection:
			YClass superior = null;

			if (secondary instanceof YClassDefinition)
				superior = ((YClassDefinition) secondary).getWrapped();

			if (superior != null && superior.isSuperiorOf(tree_superiors.getYClass()) ) {
				ArrayList<YClass> path = new ArrayList<YClass>();
				YClass step = ((YClassDefinition) secondary).getWrapped();
				while (true) {
					path.add(0, step);

					if (step.getSuperiors().isEmpty())
						break;

					step = step.getSuperiors().get(0);
				}
				
				tree_superiors.setSelectionPath(new TreePath(path.toArray()));
			} else
				tree_superiors.clearSelection();
		}
		
	}

	@Override
	public void selectedWorldChanged(World world) {
	}
	
	@Override
	public void selectedUniverseChanged(Universe universe) {	
	}	


//	@Override
//	public void treeNodesChanged(TreeModelEvent e) {
//		primaryElementChanged( controller.getPrimaryElement() );
//	}
//
//
//	@Override
//	public void treeNodesInserted(TreeModelEvent e) {
//	}
//
//
//	@Override
//	public void treeNodesRemoved(TreeModelEvent e) {
//		primaryElementChanged( controller.getPrimaryElement() );
//	}
//
//
//	@Override
//	public void treeStructureChanged(TreeModelEvent e) {
////		regenerate();
////		validate();
//	}




}