/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.biomoby.central.gui;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.image.BufferedImage;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.JViewport;
import javax.swing.ToolTipManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import org.inb.biomoby.central.MobyCentral;
import org.inb.biomoby.central.model.MobyCentralModel;
import org.inb.biomoby.central.model.ModelListener;
import org.inb.biomoby.central.gui.renderer.EntityTreeCellRenderer;
import org.inb.swing.DecoratedJScrollPane;

/**
 * Compound  abstract layered tree component.
 * The component layouts provided through abstract methods implementation a control over a tree.
 * 
 * @author Dmitry Repchevsky
 */

public abstract class AbstractEntityTreePanel extends JLayeredPane
        implements ChangeListener, ModelListener<MobyCentral>
{
    protected final JTree tree;
    protected final JPanel control;

    private DecoratedJScrollPane scroll;

    public AbstractEntityTreePanel()
    {
        setOpaque(true);

        tree = createTreeComponent();
        tree.setOpaque(false);
        
        tree.setCellRenderer(new EntityTreeCellRenderer());

        ToolTipManager.sharedInstance().registerComponent(tree);

        scroll = new DecoratedJScrollPane(tree);
        scroll.getViewport().addChangeListener(this);

        control = createControlComponent();

        add(scroll, JLayeredPane.DEFAULT_LAYER);
        add(control, JLayeredPane.PALETTE_LAYER);

        MobyCentralModel.instance().addListener(this);
    }

    protected void setBackgroundImage(BufferedImage logo)
    {
        scroll.setBackgroundImage(logo);
    }

    abstract JTree createTreeComponent();
    abstract JPanel createControlComponent();

    /**
     * Method to find a tree node by its location
     *
     * @param point - a location point for a node
     * @return - a node located at the specified point
     */
    public DefaultMutableTreeNode getNodeForLocation(Point point)
    {
        TreePath path = tree.getPathForLocation(point.x, point.y);

        if (path != null)
        {
            return (DefaultMutableTreeNode)path.getLastPathComponent();
        }

        return null;
    }

    @Override
    public void doLayout()
    {
        super.doLayout();

        Dimension size = getSize();
        scroll.setSize(size);
    }

    @Override
    public void stateChanged(ChangeEvent e)
    {
        JViewport viewport = (JViewport)e.getSource();

        Dimension dim = viewport.getExtentSize();
        moveControlPanel(dim.width, dim.height);
    }

    private void moveControlPanel(int width, int height)
    {
        Dimension bPaneSize = control.getPreferredSize();
        control.setBounds(Math.max(3, width - bPaneSize.width - 3), Math.max(3, 3), bPaneSize.width, bPaneSize.height);
    }

    private void setEnabled(Container parent, boolean isEnabled)
    {
        parent.setEnabled(isEnabled);

        for (Component child : parent.getComponents())
        {
            if (child instanceof Container)
            {
                setEnabled((Container)child,isEnabled);
            }
            else
            {
                child.setEnabled(isEnabled);
            }
        }
    }

    @Override
    public void modelCleared()
    {   
        MobyCentral central = MobyCentralModel.instance().getSelectedCentral();
        setEnabled(this, central != null);
    }

    @Override public void modelObjectInserted(MobyCentral central) {}
    @Override public void modelObjectRemoved(MobyCentral central) {}
    @Override public void modelObjectChanged(MobyCentral central1, MobyCentral central2) {}
}
