package nl.nikhef.safaripark.devmgr;

import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeSelectionModel;

import nl.nikhef.safaripark.SaFariPark;
import nl.nikhef.safaripark.Title;
import nl.nikhef.safaripark.devmgr.DeviceManagerModel.DeviceBayNode;
import nl.nikhef.safaripark.devmgr.DeviceManagerModel.DeviceNode;
import nl.nikhef.sfp.SFPDevice;
import nl.nikhef.sfp.SFPDeviceListener;
import nl.nikhef.sfp.SFPManager;
import nl.nikhef.tools.AWTDispatcher;
import nl.nikhef.tools.ListenerManager;

@SuppressWarnings("serial")
public class DeviceManager extends JPanel implements TreeSelectionListener, SFPDeviceListener, TreeModelListener {

	private DeviceManagerModel _devMgrMod;
	private JTree _tree;
	private ListenerManager<BaySelectionListener> _lm =
			new ListenerManager<BaySelectionListener>(BaySelectionListener.class, new AWTDispatcher<BaySelectionListener>()); 
	
	private SFPDevice _selDev = null;
	private int       _selBay = -1;
	
	private static class TreeRenderer extends DefaultTreeCellRenderer {

		
		private TreeRenderer() 
		{
			setOpenIcon(SaFariPark.loadImageIcon("res/pcb16.png", "Device"));
			setClosedIcon(SaFariPark.loadImageIcon("res/pcb16.png", "Device"));
			setLeafIcon(SaFariPark.loadImageIcon("res/eye16_off.png", "Device"));
		}

		
		
		
	}
	
	public DeviceManager(SFPManager mgr)
	{
		super();
		setLayout(new BorderLayout());
		_devMgrMod = new DeviceManagerModel(mgr);
		_tree = new JTree(_devMgrMod.getTreeModel());
		_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		_tree.getSelectionModel().addTreeSelectionListener(this);
		_tree.setRootVisible(false);
		_tree.setRowHeight(-1);
		
		
		
		
		_tree.setCellRenderer(new TreeRenderer());
		
		
		_devMgrMod.getTreeModel().addTreeModelListener(this);

		JScrollPane sp = new JScrollPane(_tree);
		
		expandAll();
		add(new Title("Device Manager"), BorderLayout.NORTH);
		add(sp, BorderLayout.CENTER);
	}
	

	


	private void expandAll() {
	    int j = _tree.getRowCount();
	    int i = 0;
	    while(i < j) {
	        _tree.expandRow(i);
	        i += 1;
	        j = _tree.getRowCount();
	    }
	}
	
	public void addDeviceSelectedListener(BaySelectionListener dsl) {
		_lm.addListener(dsl);
	}
	
	private boolean _ignoreEvents = false;

	@Override
	public void valueChanged(TreeSelectionEvent tse) 
	{
		if (_ignoreEvents) return;
		
		Object[] objs= tse.getPath().getPath();
		if (objs.length != 3) {
			_ignoreEvents = true;
			_tree.setSelectionPath(tse.getOldLeadSelectionPath());
			_ignoreEvents = false;
			return;
		}
		
		SFPDevice d = DeviceNode.class.cast(objs[1]).getDevice();
		int pos = DeviceBayNode.class.cast(objs[2]).pos;
		
		
		for (BaySelectionListener dsl : _lm.getListeners()) {
			if (!dsl.canSelectBay(d, pos)) {
				_ignoreEvents = true;
				_tree.setSelectionPath(tse.getOldLeadSelectionPath());
				_ignoreEvents = false;
				return;
			}
		}
		
		if (_selDev != d) {
			if (_selDev != null) _selDev.removeDeviceListener(this);
			d.addDeviceListener(this);
		}
		
		_selDev = d;
		_selBay = pos;
		
		
		_lm.getProxy().baySelected(d, pos);
	}

	@Override
	public void sfpModuleStateChanged(SFPDevice dev, int bay) {
		
		if (dev != _selDev || bay != _selBay) return;
		
		_lm.getProxy().baySelected(dev, bay);
		repaint();
	}





	@Override
	public void treeNodesChanged(TreeModelEvent arg0) 
	{
		//expandAll();
	}





	@Override
	public void treeNodesInserted(TreeModelEvent arg0) {
		//expandAll();
	}





	@Override
	public void treeNodesRemoved(TreeModelEvent arg0) {
		//expandAll();
	}





	@Override
	public void treeStructureChanged(TreeModelEvent arg0) {
		//expandAll();
	}

	


}
