package com.limegroup.gnutella.gui.search;

import java.awt.Insets;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import com.limegroup.gnutella.gui.MagnetButton;
import com.limegroup.gnutella.settings.UISettings;
import com.limegroup.gnutella.gui.themes.ThemeMediator;
import com.limegroup.gnutella.gui.themes.ThemeObserver;

/**
 * Manages input for the search, including filters for active searches.
 */
final class SearchInputManager implements ThemeObserver {
    /**
     * The panel that contains all input information for searching.
     * This includes both 'input boxes' and 'filter boxes'.
     */
    private final JPanel COMPONENT_PANEL = new JPanel(new GridBagLayout());
    
    /**
     * The card layout switching between searching or filtering.
     */
    private final CardLayout MAIN_CARDS = new CardLayout();
    
    /**
     * The panel containing either search input or filters.
     */
    private final JPanel MAIN_PANEL = new JPanel(MAIN_CARDS);

    /**
     * The search input panel.
     */
    private SearchInputPanel SEARCH;
    
    /**
     * The filter input panel.
     */
    private FilterInputPanel FILTER;

    /**
     * Constructs a new search input manager class, including all displayed
     * elements for search input.
     */
    SearchInputManager() {
        updateTheme();
        ThemeMediator.addThemeObserver(this);
    }
    
    public void updateTheme() {
        SEARCH = new SearchInputPanel();
        FILTER = new FilterInputPanel(new ShowSearchListener(), new AutoSearchListener());

        MAIN_PANEL.removeAll();       
        MAIN_PANEL.add(SEARCH, "search");
        MAIN_PANEL.add(FILTER, "filter");
        
        COMPONENT_PANEL.removeAll();
        GridBagConstraints c = new GridBagConstraints();
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1;
        c.weighty = 1;
        c.insets = new Insets(5, 0, 0, 0);
        COMPONENT_PANEL.add(MAIN_PANEL, c);
        
        c.fill = GridBagConstraints.NONE;
        c.weightx = 0;
        c.weighty = 0;
        c.insets = new Insets(0, 0, 0, 0);
        if(UISettings.MAGNETMIX_BUTTON.getValue() && !isResolutionLow())
            COMPONENT_PANEL.add(new MagnetButton(), c);
    }
    
    private boolean isResolutionLow() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return screenSize.width <= 800 || screenSize.height <= 600;
    }
    
    void rebuild() {
        updateTheme();
    }
    
    void addressChanged() {
        SEARCH.addressChanged();
    }
    
    void goToSearch() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                showSearchCard(false);
            }
        });
    }
    
    void requestSearchFocus() {
        requestSearchFocus(false);
    }
    
    /**
     * Returns the <tt>JComponent</tt> instance containing the UI elements
     * for the search input section of the search tab.
     *
     * @return the <tt>JComponent</tt> instance containing the UI elements
     *  for the search input section of the search tab
     */
    JComponent getComponent() {
        return COMPONENT_PANEL;
    }
    
    /**
     * Removes all filters from the list of filters.
     */
    void clearFilters() {
        FILTER.clearFilters();
        showSearchCard(false);
    }
    
    /**
     * Resets the FilterPanel for the specified ResultPanel.
     */
    void panelReset(ResultPanel rp) {
        FILTER.panelReset(rp);
    }
    
    /**
     * Removes the filter associated with the specified result panel.
     */
    void panelRemoved(ResultPanel rp) {
        if(FILTER.panelRemoved(rp))
            showSearchCard(false);
    }
    
    /**
     * Creates and/or displays filters for the specified result panel.
     */
    void setFiltersFor(ResultPanel rp) {
        if(UISettings.SEARCH_RESULT_FILTERS.getValue()) {
            boolean added = FILTER.setFiltersFor(rp);
            MAIN_CARDS.last(MAIN_PANEL);
            if(added)
                requestFilterFocus();
        }
    }

    /**
     * Displays the search card.
     */
    private void showSearchCard(boolean immediate) {
        MAIN_CARDS.first(MAIN_PANEL);
        requestSearchFocus(immediate);
    }      
    
    /**
     * Requests focus for the search field.
     */
    private void requestSearchFocus(boolean immediate) {
        if(immediate)
            SEARCH.requestSearchFocusImmediately();
        else
            SEARCH.requestSearchFocus();
    }
    
    /**
     * Requests focus on the correct area of the filter.
     */
    private void requestFilterFocus() {
        FILTER.requestFilterFocus();
    }    
    
    /**
     * Listener for switching back to the search from a filter.
     */
    private class ShowSearchListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            goToSearch();
        }
    }
    
    /**
     * Listener for key events.
     */
    private class AutoSearchListener implements KeyListener {
        public void keyPressed(KeyEvent e) {
            forward(e);
        }
        public void keyReleased(KeyEvent e) {
            forward(e);
        }
        public void keyTyped(KeyEvent e) { 
            if(forward(e)) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        showSearchCard(true);
                    }
                });
            }
        }
        
        /**
         * Forwards a key event to the search field.
         */
        private boolean forward(KeyEvent e) {
            if(SEARCH.isKeyEventForwardable()) {
                SEARCH.getForwardingSearchField().processKeyEvent(e);
                return true;
            } else {
                return false;
            }
        }
    }
        
}
