package adapters;

import hu.swankey.ammo.common.script.yunits.YClass;
import hu.swankey.ammo.common.script.yunits.YPackage;
import hu.swankey.ammo.common.script.yunits.YUnit;
import hu.swankey.ammo.common.yggdrasil.Yggdrasil;
import hu.swankey.ammo.common.yggdrasil.basics.YContainer;
import hu.swankey.ammo.common.yggdrasil.basics.YObject;
import hu.swankey.ammo.common.yggdrasil.definition.Definition;
import hu.swankey.ammo.common.yggdrasil.definition.PackageDefinition;

import java.util.ArrayList;
import java.util.List;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class ClassTreeModel implements TreeModel, TreeModelListener {

	private ClassTreeModel() {

	}

	public static ClassTreeModel getClassTreeModelFor(Yggdrasil yggdrasil) {
	    return getClassTreeModelFor(yggdrasil, YClass.singleton());
	}
	
	public static ClassTreeModel getClassTreeModelFor(Yggdrasil yggdrasil, YClass yclass) {
		ClassTreeModel classTreeModel = new ClassTreeModel();
		yggdrasil.getTreeModel(yggdrasil.getRoot()).addTreeModelListener(
				classTreeModel);
		return classTreeModel;
	}

	List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();

	@Override
	public void addTreeModelListener(TreeModelListener listener) {
		listeners.add(listener);
	}

	@Override
	public Object getChild(Object def, int index) {
		YPackage ypackage = (YPackage) ((Definition) def).getWrapped();
		ArrayList<YUnit> list = new ArrayList<YUnit>(ypackage.getAll());
		return list.get(index).getWrapperElement();
	}

	@Override
	public int getChildCount(Object def) {
		YPackage ypackage = (YPackage) ((Definition) def).getWrapped();
		return ypackage.getAll().size();
	}

	@Override
	public int getIndexOfChild(Object def, Object child) {
		if (!(def instanceof Definition)) return -1;
		if (!(child instanceof Definition)) return -1;
		
		YPackage ypackage = (YPackage) ((Definition) def).getWrapped();
		YUnit childunit = (YUnit) ((Definition) child).getWrapped();
		ArrayList<YUnit> list = new ArrayList<YUnit>(ypackage.getAll());
		return list.indexOf(childunit);
	}

	@Override
	public Object getRoot() {
		return YClass.getRootPackage().getWrapperElement();
	}

	@Override
	public boolean isLeaf(Object def) {
		return !(((Definition) def).getWrapped() instanceof YPackage);
	}

	@Override
	public void removeTreeModelListener(TreeModelListener listener) {
		listeners.remove(listener);
	}

	@Override
	public void valueForPathChanged(TreePath arg0, Object arg1) {
		throw new RuntimeException();
	}

	@Override
	public void treeNodesChanged(TreeModelEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void treeNodesInserted(TreeModelEvent e) {

		YContainer parent = (YContainer) e.getTreePath().getLastPathComponent();

		if (parent instanceof PackageDefinition) {

			YPackage ypackage = ((PackageDefinition) parent).getWrapped();
			List<PackageDefinition> path = createPath(YClass.getRootPackage(), ypackage);

			for (Object o : e.getChildren()) {
				if (o instanceof Definition) {
					Definition newDef = (Definition) o;

					int elementIndex[] = { new ArrayList<String>(ypackage
							.keySet()).indexOf(newDef.getName()) };
					YObject elementArray[] = { (YObject) o };

					TreeModelEvent event = new TreeModelEvent(this, path
							.toArray(), elementIndex, elementArray);

					for (TreeModelListener listener : listeners)
						listener.treeNodesInserted(event);
				}
			}
		}
	}

	private List<PackageDefinition> createPath(YPackage from, YPackage to) {
		List<PackageDefinition> path;

		if (from == to)
			path = new ArrayList<PackageDefinition>();
		else if (to.getParent() == null
				|| (path = createPath(from, (YPackage) to.getParent())) == null)
			return null;

		path.add(to.getWrapperElement());
		return path;
	}

	@Override
	public void treeNodesRemoved(TreeModelEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void treeStructureChanged(TreeModelEvent e) {
		// TODO Auto-generated method stub

	}

}
