package org.greenstone.gatherer.feedback;

import java.awt.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.table.*;
import javax.swing.text.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
import javax.swing.colorchooser.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.text.MessageFormat;
import javax.swing.plaf.metal.MetalIconFactory.*;
import javax.swing.plaf.metal.MetalIconFactory;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import javax.swing.plaf.metal.MetalInternalFrameTitlePane;

/**
 *  In general, this class will get add special listener 
 *  to a Container and of all the components inside it.
 *  <p>This class will also add special listener to the Container and each of the components inside 
 *  the Container. So, it will allows special listener  to record and listen each of the actions 
 *  the user do to the Container or any of the components inside it. The special listener
 *  is an instance of ActionRecorderDialog.</p>
 *  <p>This class will only recognized all the components that is belongs to the javax.swing package
 *  which are all the implementing classes of RootPaneContainer interface and all the direct known
 *  subclasses of JComponent. All the other components will be stated simply as Container 
 *  and user cannot really get much information out of it.</p>
 *  <p>The added special listener to this component is as what its allowed in API, if the component
 *  have some modified listener added to it then that action will not be known and recorded by
 *  the special listener.</p>
 *  
 *  @author Veronica Liesaputra
 */
public class CompListener
{
    /**
     *  This variable will hold the special listener that will listen and record any of the 
     *  actions user do to the Container and any of the components inside it.
     */
    private ActionRecorderDialog m;
   
    /**
     *  This variable will hold the pair of the component and the model of the component.
     *  With this variable allows ActionRecorderDialog listener to know which component the model that fires an action
     *  belongs to. In this HashMap the model is the key and the component where the model belongs to is
     *  the value. 
     */
    private HashMap hash;
    
    /**
     *  This constructor will set the special listener, the locale and the hashmap to be used in
     *  this Container.
     *  (Precondition: dialog != null)
     *  @param dialog  its the special listener that will listen and record all the action
     *                 user do to any of the component inside the Container.
     *  @param h       its the HashMap that will hold the pair of model with the component it belongs.
     */
    public CompListener 
	(ActionRecorderDialog dialog,HashMap h)
    {
	m = dialog;
	hash = h;
    }
	
    /**
     *  If the JTextComponent is a JTextField then it will add the special action listener to it.
     *  (Precondition: txt != null)
     *  @param txt its the JTextComponent we want to get all the information from.
     */
    public void getTextAreaInfo(JTextComponent txt)
    {
	if (txt instanceof JTextField)
	    {
		((JTextField)txt).removeActionListener(m);
		((JTextField)txt).addActionListener(m);
	    }
    }

    /**
     *  This method will add the special action listener to the JButton.
     *  (Precondition: button != null)
     *  @param button its the JButton we want to get the information from.
     */
    public void getButtonInfo (JButton button)
    {
	button.removeActionListener(m);
	button.addActionListener(m);
    }

     /**
     *  This method will get add the special change listener to the JProgressBar.
     *  (Precondition: bar != null)
     *  @param  bar   its the JProgressBar we want to get information from.
     */
    public void getProgressBarInfo (JProgressBar bar)
    {
	bar.removeChangeListener(m);
	bar.addChangeListener(m);
    }
    
    /**
     *  This method will add the special change listener to the JSlider.
     *  (Precondition: slider != null)
     *  @param  slider its the JSlider we want to get information from.
     */
    public void getSliderInfo (JSlider slider)
    {
	slider.removeChangeListener(m);
	slider.addChangeListener(m);
    }

    /**
     *  This method will add the special change listener to the JSpinner.
     *  (Precondition: spinner != null)
     *  @param spinner its the JSpinner we want to the information from.
     */
    public void getSpinnerInfo (JSpinner spinner)
    {
	spinner.removeChangeListener(m);
	spinner.addChangeListener(m);
    }
    
    /**
     * Dummy method to get JLabel.
     */
    public void getLabelInfo(JLabel lbl)
    {}
    
    /**
     *  This method will add the special action listener to the JComboBox.
     *  (Precondition: box != null)
     *  @param box    its the JComboBox we want to get information from.
     */
    public void getComboBoxInfo(JComboBox box)
    {
	ComboBoxModel cm;
	cm = box.getModel();

	box.removeActionListener(m);
	box.addActionListener(m);
    }

    /**
     *  This method will add the special action listener to the JToggleButton.
     *  (Precondition: button != null)
     *  @param button its a JToggleButton inside the window.
     */
    public void getToggleButtonInfo (JToggleButton button)
    {
	button.removeActionListener(m);
	button.addActionListener(m);
    }

    /**
     *  This method will add the special action listener to the JMenuItem.
     *  (Precondition: menuitem != null)
     *  @param menuitem its the JMenuItem we want to get the information from.
     */
    public void getMenuItemInfo (JMenuItem menuitem)
    {
	menuitem.removeActionListener(m);
	menuitem.addActionListener(m);
    }

    /**
     *  This method will get all the components inside JMenuBar.
     *  (Precondition: menubar != null)
     *  @param menubar its the JMenuBar we want to get the information from.
     */
    public void getMenuBarInfo (JMenuBar menubar)
    {
	int i;
	for (i= 0 ; i < menubar.getMenuCount() ; i++)
	    {
		getInside(menubar.getMenu(i));
	    }
    }

    /**
     *  This method will add the special action and menu listener to the JMenu and
     *  get the components inside JMenu.
     *  (Precondition: menu != null)
     *  @param menu   its the JMenu we want to the the information from.
     */
    public void getMenuInfo (JMenu menu)
    {
	menu.removeActionListener(m);
	menu.removeMenuListener(m);
	menu.addActionListener(m);
	menu.addMenuListener(m);

	int i;
	for (i= 0 ; i < menu.getMenuComponentCount() ; i++)
	    {
		getInside((Container)menu.getMenuComponent(i));
	    }
    }
    
    /**
     *  This method will get all the components inside the JApplet.
     *  (Precondition: applet != null)
     *  @param applet its the JApplet we want to get the information from.
     */
    public void getAppletInfo (JApplet applet)
    {
	Component[] group;
	group = applet.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)applet.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JWindow.
     *  (Precondition: window != null)
     *  @param window its the JWindow we want to get the information from.
     */
    public void getWindowInfo (JWindow window)
    {
	Component[] group;
	group = window.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)window.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JDialog.
     *  (Precondition: dialog != null)
     *  @param dialog its the JDialog we want to get the information from.
     */
    public void getDialogInfo (JDialog dialog)
    {
	Component[] group;
	group = dialog.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)dialog.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JInternalFrame.
     *  (Precondition: frame != null)
     *  @param frame  its the JInternalFrame we want to get the information from.
     */
    public void getInternalFrameInfo (JInternalFrame frame)
    {
	Component[] group;
	group = frame.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)frame.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JFrame.
     *  (Precondition: frame != null)
     *  @param frame  its the JFrame we want to get the information from.
     */
    public void getFrameInfo (JFrame frame)
    {
	Component[] group;
	group = frame.getComponents();
	int i;
	
	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)frame.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JPanel.
     *  (Precondition: pane != null)
     *  @param pane   its the JPanel we want to get the information from.
     */
    public void getPanelInfo (JPanel pane)
    {
	Component[] group;
	group = pane.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)pane.getComponent(i));
		    }
	    }
    }
    
    /**
     *  This method will get all the components inside the JScrollPane.
     *  (Precondition: scroll != null)
     *  @param scroll its the JScrollPane we want to get the information from.
     */
    public void getScrollInfo (JScrollPane scroll)
    {
	Component[] group;
	group = scroll.getComponents();
	int i;
	
	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)group[i]);
		    }
	    }
    }

    /**
     *  This method will add special change listener to the JTabbedPane and get all
     *  the components inside it.
     *  (Precondition: tab != null)
     *  @param tab   its the JTabbedPane we want to get the information from.
     */
    public void getTabbedPaneInfo (JTabbedPane tab)
    {
	int j;
	
	tab.removeChangeListener(m);
	tab.addChangeListener(m);

	for (j = 0 ; j < tab.getTabCount(); j++)
	    {	
		
		Component group = tab.getComponentAt(j);
		getInside((Container)group);
		
	    }
    }
    
    /**
     *  This is the dummy method to ge the option pane info.
     */
    public void getOptionPaneInfo (JOptionPane op)
    {}

    /**
     *  This method will get components inside the JViewPort.
     *  (Precondition: vp != null)
     *  @param vp   its the JViewPort we want to get the information from.
     */
    public void getViewPortInfo (JViewport vp)
    {
	Component[] group;
	group = vp.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)group[i]);
		    }
	    }
    }

    /**
     *  This method will get components inside the Box.
     *  (Precondition: box != null)
     *  @param box  its the Box we want to get the information from.
     */
    public void getBoxInfo (Box box)
    {
	Component[] group;
	group = box.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)group[i]);
		    }
	    }
    }

    /**
     *  This method will get components inside the JSplitPane.
     *  (Precondition: split != null)
     *  @param split  its the JSplitPane we want to get the information from.
     */
    public void getSplitPaneInfo (JSplitPane split)
    {
	Component[] group;
	group = split.getComponents();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)group[i]);
		    }
	    }
    }

    /**
     *  This method will get add special list selection listener to the JList.
     *  (Precondition: list != null)
     *  @param list  its the JList we want to get the information from.
     */
    public void getListInfo (JList list)
    {
	ListModel ls;
	ls = list.getModel();
	
	list.removeListSelectionListener(m);
	list.addListSelectionListener(m);
	
	if (ls != null)
	    {
		if (hash.containsKey(ls) == false)
		    hash.put(ls,list);
		ls.removeListDataListener(m);
		ls.addListDataListener(m);
	    }
    }

    /**
     *  This method will add special change listener to the JColorChooser.
     *  (Precondition: color != null)
     *  @param color  its the JColorChooser we want to get the information from.
     */
    public void getColorInfo (JColorChooser color)
    {
	ColorSelectionModel cm;
	cm = color.getSelectionModel();
	
	if (cm != null)
	    {
		if (hash.containsKey(cm) == false)
		    hash.put(cm,color);
		cm.removeChangeListener(m);
		cm.addChangeListener(m);
	    }

	getInside((Container) color.getPreviewPanel());
    }

    /**
     *  This method will add special action listener to the JFileChooser.
     *  (Precondition: fc != null)
     *  @param fc  its the JFileChooser we want to get the information from.
     */
    public void getFileChooserInfo (JFileChooser fc)
    {
	fc.removeActionListener(m);
	fc.addActionListener(m);
    }		

    /**
     *  This method will add special list selection and column model listener 
     *  to the JTable.
     *  (Precondition: table != null)
     *  @param table  its the JTable we want to get the information from.
     */
    public void getTableInfo (JTable table)
    {
	TableModel tm;
	tm = table.getModel();
	
	TableColumnModel tcm;
	tcm = table.getColumnModel();
	ListSelectionModel lm;
	lm = table.getSelectionModel(); 

	if (lm != null)
	    {
		if (hash.containsKey(lm) == false)
		    hash.put(lm,table);
		lm.removeListSelectionListener(m);
		lm.addListSelectionListener(m);
	    }
	
	if (tcm != null)
	    {
		if (hash.containsKey(tcm) == false)
		    hash.put(tcm,table);
		tcm.removeColumnModelListener(m);
		tcm.addColumnModelListener(m);
	    }
    }

    /**
     *  This is a dummy method to get the JScrollBar.
     */
    public void getScrollBarInfo (JScrollBar scroll)
    {
    }

    /**
     *  This method will add special tree selection listener to the JTree.
     *  (Precondition: tree != null)
     *  @param tree  its the JTree we want to get the information from.
     */
    public void getTreeInfo (JTree tree)
    {
	TreeModel tm;
	tm = tree.getModel();
	
	tree.removeTreeSelectionListener(m);
	tree.addTreeSelectionListener(m);
	
	if (tm != null)
	    {
		if (hash.containsKey(tm) == false)
		    hash.put(tm,tree);
		tm.removeTreeModelListener(m);
		tm.addTreeModelListener(m);
	    }
    }
       
    /**
     *  This method is a dummy method to get Container.
     */
    public void getCompInfo (Container pane)
    {
    }

    /**
     *  This method will get all components inside the JPopupMenu.
     *  (Precondition: popup != null)
     *  @param popup  its the JPopUpMenu we want to get the information from.
     */
    public void getPopUpMenuInfo (JPopupMenu popup)
    {
	Component[] group;
	group = popup.getComponents();
	SingleSelectionModel sm;
	sm = popup.getSelectionModel();
	int i;

	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)popup.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JRootPane.
     *  (Precondition: pane != null)
     *  @param pane  its the JRootPane we want to get the information from.
     */
    public void getRootPaneInfo (JRootPane pane)
    {
	Component[] group;
	group = pane.getComponents();
	int i;
	
	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			
			getInside((Container)pane.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JLayeredPane.
     *  (Precondition: pane != null)
     *  @param pane  its the JLayeredPane we want to get the information from.
     */
    public void getLayeredPaneInfo (JLayeredPane pane)
    {
	Component[] group;
	group = pane.getComponents();
	int i;
	
	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)pane.getComponent(i));
		    }
	    }
    }

    /**
     * This is a dummy method to get BasicInternalFrameTitlePane.
     */
    public void getInternalFrameTitleInfo (BasicInternalFrameTitlePane pane)
    {
    }

    /**
     *  This method will add special column model and list selection
     *  listener to JTableHeader.
     *  (Precondition: header != null)
     *  @param header  its the JTableHeader we want to get the information from.
     */
    public void getTableHeaderInfo (JTableHeader header)
    {
	TableColumnModel tcm;
	tcm = header.getColumnModel();
	ListSelectionModel lm;
	lm = tcm.getSelectionModel();

	if (tcm != null)
	    {
		if (hash.containsKey(tcm) == false)
		    hash.put(tcm,header);
		tcm.removeColumnModelListener(m);
		tcm.addColumnModelListener(m);
	    }

	if (lm != null)
	    {
		if (hash.containsKey(lm) == false)
		    hash.put(lm,header);
		lm.removeListSelectionListener(m);
		lm.addListSelectionListener(m);
	    }
    }

    /**
     *  This method will get all components inside the JToolBar.
     *  (Precondition: tool != null)
     *  @param tool  its the JToolBar we want to get the information from.
     */
    public void getToolBarInfo (JToolBar tool)
    {
	Component[] group;
	group = tool.getComponents();
	int i;
	
	if (group != null)
	    {
		for (i = 0; i < group.length ; i++)
		    {
			getInside((Container)tool.getComponent(i));
		    }
	    }
    }

    /**
     *  This method will get all the components inside the JToolTip.
     *  (Precondition: tip != null)
     *  @param tip  its the JToolTip we want to get the information from.
     */
    public void getToolTipInfo (JToolTip tip)
    {
	Component group;
	group = tip.getComponent();
	int i;
	
	if (group != null)
	    {
		getInside((Container) group);
	    }
    }

    /**
     *  This is the dummy method to get JSeparator.
     */
    public void getSeparatorInfo (JSeparator sept)
    {
    }

    /**
     *  This method will get all the components inside the JDesktopPane.
     *  (Precondition: pane != null)
     *  @param pane  its the JDesktopPane we want to get the information from.
     */
    public void getDesktopPaneInfo (JDesktopPane pane)
    {
	JInternalFrame[]  group;
	group = pane.getAllFrames();

	if (group != null)
	    {
		int i;
		
		for ( i = 0 ; i < group.length ; i++ )
		    {
			getInside((Container) group[i]);
		    }
	    }
    }

    /**
     *  This is a dummy method to catch null components.
     */
    public void getNullInfo ()
    {
    }

    /**
     *  This method will add a special listener to a container and components inside it.
     *  This method is the gateway to all other methods in this class.
     *  @param comp its the Container we want to get the information from.
     */
    public void getInside(Container comp)
    {
	if (comp == null)
	    {
		getNullInfo();
		return;
	    }
	else if (comp instanceof JApplet)
	    {
		getAppletInfo ((JApplet) comp);
		return;
	    }
	else if (comp instanceof JSeparator)
	    {
		getSeparatorInfo ((JSeparator) comp);
		return;
	    }
	else if (comp instanceof JWindow)
	    {
		getWindowInfo((JWindow) comp);
		return;
	    }
	else if (comp instanceof JDialog)
	    {
		getDialogInfo((JDialog) comp);
		return;
	    }
	else if (comp instanceof JComboBox)
	    {
		getComboBoxInfo((JComboBox) comp);
		return;
	    }
	else if (comp instanceof JLabel)
	    {
		getLabelInfo((JLabel) comp);
		return;
	    }
	else if (comp instanceof JTextComponent)
	    {
		getTextAreaInfo((JTextComponent) comp);
		return;
	    }
	else if (comp instanceof JFrame)
	    {
		getFrameInfo((JFrame) comp);
		return;
	    }
	else if (comp instanceof JPanel)
	    {
		getPanelInfo((JPanel) comp);
		return;
	    }
	else if (comp instanceof JScrollPane)
	    {
		getScrollInfo((JScrollPane) comp);
		return;
	    }
	else if (comp instanceof JScrollBar)
	    {
		getScrollBarInfo ((JScrollBar) comp);
		return;
	    }
	else if (comp instanceof JViewport)
	    {
		getViewPortInfo((JViewport) comp);
		return;
	    }
	else if (comp instanceof JTabbedPane)
	    {
		getTabbedPaneInfo((JTabbedPane) comp);
		return;
	    }
	else if (comp instanceof Box)
	    {
		getBoxInfo((Box) comp);
		return;
	    }
	else if (comp instanceof JToggleButton)
	    {
		getToggleButtonInfo((JToggleButton) comp);
		return;
	    }
	else if (comp instanceof JSplitPane)
	    {
		getSplitPaneInfo ((JSplitPane) comp);
		return;
	    }
	else if (comp instanceof JList)
	    {
		getListInfo ((JList) comp);
		return;
	    }
	else if (comp instanceof JTree)
	    {
		getTreeInfo ((JTree) comp);
		return;
	    }
	else if (comp instanceof JTable)
	    {
		getTableInfo ((JTable) comp);
		return;
	    }
	else if (comp instanceof JSlider)
	    {
		getSliderInfo ((JSlider) comp);
		return;
	    }
	else if (comp instanceof JSpinner)
	    {
		getSpinnerInfo ((JSpinner) comp);
		return;
	    }
	else if (comp instanceof JProgressBar)
	    {
		getProgressBarInfo ((JProgressBar) comp);
		return;
	    }
	else if (comp instanceof JButton)
	    {
		getButtonInfo ((JButton) comp);
		return;
	    }
	else if (comp instanceof JMenu)
	    {
		getMenuInfo ((JMenu) comp);
		return;
	    }
	else if (comp instanceof JMenuBar)
	    {
		getMenuBarInfo ((JMenuBar) comp);
		return;
	    }
	else if (comp instanceof JMenuItem)
	    {
		getMenuItemInfo ((JMenuItem) comp);
		return;
	    }
	else if (comp instanceof JOptionPane)
	    {
		getOptionPaneInfo ((JOptionPane) comp);
		return;
	    }
	else if (comp instanceof BasicInternalFrameTitlePane)
	    {
		getInternalFrameTitleInfo ((BasicInternalFrameTitlePane) comp);
		return;
	    }
	else if (comp instanceof JColorChooser)
	    {
		getColorInfo ((JColorChooser) comp);
		return;
	    }
	else if (comp instanceof JFileChooser)
	    {
		getFileChooserInfo ((JFileChooser) comp);
		return;
	    }
	else if (comp instanceof JDesktopPane)
	    {
		getDesktopPaneInfo ((JDesktopPane) comp);
		return;
	    }
	else if (comp instanceof JInternalFrame)
	    {
		getInternalFrameInfo ((JInternalFrame) comp);
		return;
	    }
	else if (comp instanceof JLayeredPane)
	    {
		getLayeredPaneInfo ((JLayeredPane) comp);
		return;
	    }
	else if (comp instanceof JPopupMenu)
	    {
		getPopUpMenuInfo ((JPopupMenu) comp);
		return;
	    }
	else if (comp instanceof JRootPane)
	    {
		getRootPaneInfo ((JRootPane) comp);
		return;
	    }
	else if (comp instanceof JTableHeader)
	    {
		getTableHeaderInfo ((JTableHeader) comp);
		return;
	    }
	else if (comp instanceof JToolBar)
	    {
		getToolBarInfo ((JToolBar) comp);
		return;
	    }
	else if (comp instanceof JToolTip)
	    {
		getToolTipInfo ((JToolTip) comp);
		return;
	    }
	else
	    {
		getCompInfo (comp);
		return;
	    }
    }
}







