package com.limegroup.gnutella.gui.search;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;

import com.limegroup.gnutella.MediaType;
import com.limegroup.gnutella.gui.BoxPanel;
import com.limegroup.gnutella.gui.GUIMediator;
import com.limegroup.gnutella.gui.ImageManipulator;
import com.limegroup.gnutella.gui.themes.ThemeFileHandler;
import com.limegroup.gnutella.xml.LimeXMLSchema;

/**
 * A group of radio buttons for each schema.
 */
final class SchemaBox extends JPanel {
    
    /**
     * String for 'Select Type'
     */
    private static final String SELECT_TYPE =
        GUIMediator.getStringResource("SEARCH_SELECT_TYPE");

    /**
     * The property that the media type is stored in.
     */
    private static final String MEDIA = "NAMED_MEDIA_TYPE";
    
    /**
     * The property to store the selected icon in.
     */
    private static final String SELECTED = "SELECTED_ICON";
    
    /**
     * The property to store the unselected icon in.
     */
    private static final String DESELECTED = "DESELECTED_ICON";
    
    /**
     * The panel containing the schemas.
     */
    private final JPanel SCHEMAS = new JPanel();

    /**
     * The button group that holds the buttons together.
     */
    private final ButtonGroup GROUP = new ButtonGroup();
    
    /**
     * The listener for changing the highlighting of buttons.
     */
    private final ItemListener HIGHLIGHTER = new Highlighter();
    
    /**
     * The clicker forwarder.
     */
    private final MouseListener CLICK_FORWARDER = new Clicker();
    
    /**
     * The ditherer for highlighted buttons.
     */
    private final Ditherer DITHERER =
            new Ditherer(20,
                        ThemeFileHandler.FILTER_TITLE_TOP_COLOR.getValue(), 
                        ThemeFileHandler.FILTER_TITLE_COLOR.getValue()
                        );

    /**
     * Constructs the SchemaBox.
     */
    SchemaBox() {
        List allSchemas = NamedMediaType.getAllNamedMediaTypes();
        int cols, rows;
        cols = 2;
        rows = (int)Math.ceil((double)allSchemas.size() / 2.0);
        SCHEMAS.setBackground(ThemeFileHandler.SEARCH_GRID_COLOR.getValue());
        SCHEMAS.setLayout(new GridLayout(rows, cols, 1, 1));
        SCHEMAS.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        addSchemas(allSchemas);
        
        
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        panel.add(new JLabel(SELECT_TYPE));
        add(panel);
        
        setLayout( new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel p = new BoxPanel(BoxPanel.X_AXIS);
        p.add(SCHEMAS);
        p.add(Box.createHorizontalStrut(1));
        add(p);
    }
    
    /**
     * Adds the specified ActionListener to all possible buttons.
     */
    public void addSelectionListener(ActionListener listener) {
        Enumeration elements = GROUP.getElements();
        for(; elements.hasMoreElements(); ) {
            AbstractButton button = (AbstractButton)elements.nextElement();
            button.addActionListener(listener);
        }
    }
    
    /**
     * Returns the selected icon, or null if the selection has no icon.
     */
    public Icon getSelectedIcon() {
        NamedMediaType nmt = getSelectedMedia();
        if(nmt == null)
            return null;
            
        return nmt.getIcon();
    }        
    
    /**
     * Returns the selected schema, or null if the selected item has no schema.
     */
    public LimeXMLSchema getSelectedSchema() {
        NamedMediaType nmt = getSelectedMedia();
        if(nmt == null)
            return null;
            
        return nmt.getSchema();
    }
    
    /**
     * Returns the description of the selected item.
     */
    public String getSelectedItem() {
        NamedMediaType nmt = getSelectedMedia();
        if(nmt == null)
            return null;
        return nmt.getName();
    }
    
    /**
     * Returns the selected item's media type.
     */
    public MediaType getSelectedMediaType() {
        NamedMediaType nmt = getSelectedMedia();
        if(nmt == null)
            return null;
        return nmt.getMediaType();
    }
    
    /**
     * Adds the given schemas as radio buttons.
     */
    private void addSchemas(List schemas) {
        //We first add specific ones in a certain order.
        //After that, leave it to random chance.
        NamedMediaType current;
        
        // First add 'Any Type'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_ANY_TYPE);
        schemas.remove(current);
        addMediaType(current);
        
        // Then add 'Audio'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_AUDIO);
        schemas.remove(current);
        addMediaType(current, GUIMediator.getStringResource("SEARCH_MEDIA_AUDIO_TOOLTIP"));
        
        // Then add 'Images'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_IMAGES);
        schemas.remove(current);
        addMediaType(current, GUIMediator.getStringResource("SEARCH_MEDIA_IMAGES_TOOLTIP"));
        
        // Then add 'Video'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_VIDEO);
        schemas.remove(current);
        addMediaType(current, GUIMediator.getStringResource("SEARCH_MEDIA_VIDEO_TOOLTIP"));
        
        // Then add 'Documents'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_DOCUMENTS);
        schemas.remove(current);
        addMediaType(current, GUIMediator.getStringResource("SEARCH_MEDIA_DOCUMENTS_TOOLTIP"));
        
        // Then add 'Programs'
        current = NamedMediaType.getFromDescription(MediaType.SCHEMA_PROGRAMS);
        schemas.remove(current);
        addMediaType(current, GUIMediator.getStringResource("SEARCH_MEDIA_PROGRAMS_TOOLTIP"));
        
        // Then add anything that was left.
        for(Iterator i = schemas.iterator(); i.hasNext(); ) {
            addMediaType((NamedMediaType)i.next());
        }
    }    
    
	private void addMediaType(NamedMediaType type) {
		addMediaType(type, null);
	}
	
    /**
     * Adds the given NamedMediaType.
     *
     * Marks the 'Any Type' as selected.
     */
    private void addMediaType(NamedMediaType type, String toolTip) {
        Icon icon = type.getIcon();
        Icon disabledIcon = null;
        Icon rolloverIcon = null;
        AbstractButton button = new JRadioButton(type.getName());
        button.putClientProperty(MEDIA, type);
        button.putClientProperty(SELECTED, icon);
        if(icon != null) {
            disabledIcon = ImageManipulator.darken(icon);
            rolloverIcon = ImageManipulator.brighten(icon);
        }
        button.putClientProperty(DESELECTED, disabledIcon);
        button.setIcon(disabledIcon);
        button.setRolloverIcon(rolloverIcon);
        button.addItemListener(HIGHLIGHTER);
        button.setBorderPainted(false);
        button.setFocusPainted(false);
        button.setContentAreaFilled(false);
        button.setMargin(new Insets(0, 0, 0, 0));
        button.setOpaque(false);
        button.addMouseListener(CLICK_FORWARDER);
        button.setPreferredSize(new Dimension(100, 22));
		if (toolTip != null) {
			button.setToolTipText(toolTip);
		}
        GROUP.add(button);
        
        DitherPanel panel = new DitherPanel(DITHERER);
        panel.setDithering(false);
        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 7, 1));
        panel.add(button);
        panel.addMouseListener(CLICK_FORWARDER);
        panel.setBackground(UIManager.getColor(
                                         "TabbedPane.background"));
        SCHEMAS.add(panel);
        
        if(type.getMediaType() == MediaType.getAnyTypeMediaType())
            button.setSelected(true);
        else
            button.setSelected(false);
    }
    
    /**
     * Iterates through all the elements in the group
     * and returns the media type of the selected button.
     */
	NamedMediaType getSelectedMedia() {
        Enumeration elements = GROUP.getElements();
        for(; elements.hasMoreElements(); ) {
            AbstractButton button = (AbstractButton)elements.nextElement();
            if(button.isSelected())
                return (NamedMediaType)button.getClientProperty(MEDIA);
        }
        return null;
    }
    
    /**
     * Listener for ItemEvent, so that the buttons can be highlighted or not
     * when selected (or not).
     */
    private static class Highlighter implements ItemListener {
        public void itemStateChanged(ItemEvent e) {
            AbstractButton button = (AbstractButton)e.getSource();
            DitherPanel parent = (DitherPanel)button.getParent();
            if(e.getStateChange() == ItemEvent.SELECTED) {
                button.setIcon((Icon)button.getClientProperty(SELECTED));
                parent.setDithering(true);
                parent.setBackground(ThemeFileHandler.FILTER_TITLE_COLOR.getValue());
            } else {
                button.setIcon((Icon)button.getClientProperty(DESELECTED));
                parent.setDithering(false);
                parent.setBackground(UIManager.getColor("TabbedPane.background"));
            }
        }
    }
    
    private static void setIfNotNull(JComponent c, String col) {
        Color color = UIManager.getColor(col);
        if(color != null)
            c.setBackground(color);
    }
    
    /**
     * Forwards click events from a panel to the panel's component.
     */
    private static class Clicker implements MouseListener {
        public void mouseEntered(MouseEvent e) {
            JComponent c = (JComponent)e.getSource();
            AbstractButton b;
            if(c instanceof AbstractButton) {
                b = (AbstractButton)c;
                c = (JComponent)c.getParent();
            } else {
                b = (AbstractButton)c.getComponent(0);
            }
            if(!b.isSelected())
                setIfNotNull(c, "TabbedPane.selected");
        }
        public void mouseExited(MouseEvent e) {
            JComponent c = (JComponent)e.getSource();
            AbstractButton b;
            if(c instanceof AbstractButton) {
                b = (AbstractButton)c;
                c = (JComponent)c.getParent();
            } else {
                b = (AbstractButton)c.getComponent(0);
            }
            if(!b.isSelected())
                setIfNotNull(c, "TabbedPane.background");
        }
        public void mouseClicked(MouseEvent e) {
            JComponent c = (JComponent)e.getSource();
            if(!(c instanceof AbstractButton)) {
                AbstractButton b = (AbstractButton)c.getComponent(0);
                b.doClick();
            }
        }
        public void mousePressed(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
    }
} 
