package adapters;

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 YClass filterClass;

    private ClassTreeModel(YClass filterClass) {
        this.filterClass = filterClass;
    }

    public static ClassTreeModel getClassTreeModelFor(Yggdrasil yggdrasil) {
        return getClassTreeModelFor(yggdrasil, YClass.singleton());
    }

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

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

    @Override
    public void addTreeModelListener(TreeModelListener listener) {
        listeners.add(listener);
    }
    
    private List<YUnit> getChildren(Object def){
        YPackage ypackage = (YPackage) ((Definition) def).getWrapped();
        ArrayList<YUnit> list = new ArrayList<YUnit>();
        for (YUnit yunit: ypackage.getAll()) {
            if (yunit instanceof YPackage || filterClass.isSuperiorOf((YClass)yunit)) {
                list.add(yunit);
            } 
        }
        
        return list;
    }

    @Override
    public Object getChild(Object def, int index) {
        return getChildren(def).get(index).getWrapperElement();
    }

    @Override
    public int getChildCount(Object def) {
        return getChildren(def).size();
    }

    @Override
    public int getIndexOfChild(Object def, Object child) {
        if (!(def instanceof Definition))
            return -1;
        if (!(child instanceof Definition))
            return -1;

        YUnit childunit = (YUnit) ((Definition) child).getWrapped();
        return getChildren(def).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

    }

}
