/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2006 Phex Development Group
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 *  --- CVS Information ---
 *  $Id: SearchControlPanel.java 3362 2006-03-30 22:27:26Z gregork $
 */
package phex.gui.tabs.search.cp;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

import phex.common.address.DestAddress;
import phex.common.address.IpAddress;
import phex.common.address.MalformedDestAddressException;
import phex.event.SearchDataEvent;
import phex.event.SearchDataListener;
import phex.gui.common.BoxPanel;
import phex.gui.common.table.FWTable;
import phex.gui.tabs.search.SearchResultsDataModel;
import phex.gui.tabs.search.SearchTab;
import phex.net.presentation.PresentationManager;
import phex.query.*;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public class SearchControlPanel extends JPanel implements SearchDataListener
{
    private SearchContainer searchContainer;
    private SearchResultsDataModel displayedDataModel;
    private SearchTab searchTab;
    private int prefWidth;

    private SearchActivityBox activityBox;
    
    private JPanel searchBoxContentPanel;
    private KeywordSearchBox keywordSearchBox;
    private WhatsNewSearchBox whatsNewBox;
    private BrowseHostSearchBox browseHostBox;
    
    private SearchInfoBox infoBox;
    
    private JButton filterButton;
    private JScrollPane scrollPane;
    
    public SearchControlPanel( SearchTab tab )
    {
        super( new GridBagLayout() );
        searchTab = tab;
        searchContainer = QueryManager.getInstance().getSearchContainer();
        initializeComponent();
        updateUI();
    }
    
    /**
     * Clears the search history in the search control panel and configuration.
     */
    public void clearSearchHistory()
    {
        keywordSearchBox.clearSearchHistory();
    }

    public void initializeComponent()
    {
        CellConstraints cc = new CellConstraints();
        
        // TODO who knows why the ScrollPane causes such strange jumping of the panels width...
        // cant find a way to fix it...
        
        //PanelBuilder boxBuilder = new PanelBuilder( layout, this );
         
        //scrollPane = new JScrollPane( innerPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
        //    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
        //FWTable.updateFWTableScrollPane( scrollPane );
        //boxBuilder.add( scrollPane, cc.xy( 1, 1 ) );
//        
//        FormLayout layout = new FormLayout(
//            "d", // columns
//            "fill:d:grow" ); // rows
//        PanelBuilder boxBuilder = new PanelBuilder( layout, this );
//        
//        JPanel innerPanel = new JPanel();
        //boxBuilder.add( innerPanel, cc.xy( 1, 1 ) );
        
        FormLayout layout = new FormLayout(
            "fill:d:grow", // columns
            "p, p, p" ); // rows
        PanelBuilder cpPanelBuilder = new PanelBuilder( layout, this );
        
        keywordSearchBox = new KeywordSearchBox( this );
        whatsNewBox = new WhatsNewSearchBox( this );
        browseHostBox = new BrowseHostSearchBox( this );
        
        activityBox = new SearchActivityBox( searchTab, this );
        
        infoBox = new SearchInfoBox( this );
        
        // get prefered width of all boxes to calc width for all
        // and match height of all search boxes to reduce jumping
        prefWidth = 0;
        int prefHeight = 0;
        Dimension actPref = activityBox.getPreferredSize();
        prefWidth = Math.max( prefWidth, actPref.width );
        Dimension infoPref = infoBox.getPreferredSize();
        prefWidth = Math.max( prefWidth, infoPref.width );
        
        Dimension ksbPref = keywordSearchBox.getPreferredSize();
        prefWidth = Math.max( prefWidth, ksbPref.width );
        prefHeight = Math.max( prefHeight, ksbPref.height );
        Dimension wnbPref = whatsNewBox.getPreferredSize();
        prefWidth = Math.max( prefWidth, wnbPref.width );
        prefHeight = Math.max( prefHeight, wnbPref.height );
        Dimension bhbPref = browseHostBox.getPreferredSize();
        prefWidth = Math.max( prefWidth, bhbPref.width );
        prefHeight = Math.max( prefHeight, bhbPref.height );
        
        actPref.width = prefWidth;
        keywordSearchBox.setPreferredSize( actPref );
        infoPref.width = prefWidth;
        keywordSearchBox.setPreferredSize( infoPref );
        
        ksbPref.width = prefWidth;
        ksbPref.height = prefHeight;
        keywordSearchBox.setPreferredSize( ksbPref );
        wnbPref.width = prefWidth;
        wnbPref.height = prefHeight;
        whatsNewBox.setPreferredSize( wnbPref );
        bhbPref.width = prefWidth;
        bhbPref.height = prefHeight;
        browseHostBox.setPreferredSize( bhbPref );
        
        searchBoxContentPanel = new JPanel( new BorderLayout() );
        cpPanelBuilder.add( searchBoxContentPanel, cc.xy( 1, 1 ) );
        cpPanelBuilder.add( activityBox, cc.xy( 1, 2 ) );
        cpPanelBuilder.add( infoBox, cc.xy( 1, 3 ) );
        
        activityBox.postInit();
    }
    
    public Dimension getPreferredSize()
    {
        Dimension dim = super.getPreferredSize();
        dim.width = prefWidth;
        return dim;
    }
    
    private void activateSearchBox( BoxPanel boxPanel )
    {
        searchBoxContentPanel.removeAll();
        searchBoxContentPanel.add( boxPanel, BorderLayout.CENTER );
        searchBoxContentPanel.doLayout();
        searchBoxContentPanel.revalidate();
        searchBoxContentPanel.repaint();
    }
    
    public void setDisplayedSearch( SearchResultsDataModel searchResultsDataModel )
    {
        // otherwise no need to update...
        if ( displayedDataModel != searchResultsDataModel )
        {
            if ( displayedDataModel != null )
            {
                displayedDataModel.getSearch().removeSearchChangeListener( this );
            }
            displayedDataModel = searchResultsDataModel;
            if ( displayedDataModel != null )
            {
                displayedDataModel.getSearch().addSearchChangeListener( this );
            }
            infoBox.setDisplayedSearch( displayedDataModel );
            updateControlPanel();
        }
    }
    
    public void activateKeywordSearchBox()
    {
        activateSearchBox( keywordSearchBox );
        keywordSearchBox.focusInputField();
    }
    
    public void activateBrowseHostBox()
    {
        activateSearchBox( browseHostBox );
        browseHostBox.focusInputField();
    }
    
    public void activateWhatsNewBox()
    {
        activateSearchBox( whatsNewBox );
        whatsNewBox.focusInputField();
    }

    private void updateControlPanel()
    {
        if ( displayedDataModel != null )
        {
            activityBox.displayRunningSearchPanel();
            
            Search search = displayedDataModel.getSearch();
            if ( search instanceof WhatsNewSearch )
            {
                activateSearchBox( whatsNewBox );
                whatsNewBox.updateControlPanel( (WhatsNewSearch)search );
            }
            else if ( search instanceof KeywordSearch )
            {
                activateSearchBox( keywordSearchBox );
                keywordSearchBox.updateControlPanel( (KeywordSearch)search );
            }
            else if ( search instanceof BrowseHostResults )
            {
                activateSearchBox( browseHostBox );
                browseHostBox.updateControlPanel( (BrowseHostResults)search );
            }
            else
            {
                throw new RuntimeException("Unknwon search type");
            }
        }
        else
        {// this is the case for a new search.
            activityBox.displayNewSearchPanel();
            
            whatsNewBox.updateControlPanel( null );
            keywordSearchBox.updateControlPanel( null );
            browseHostBox.updateControlPanel( null );            
        }
    }
    
    /**
     * This is overloaded to update the combo box size on
     * every UI update. Like font size change!
     */
    public void updateUI()
    {
        super.updateUI();
        
        Color shadow = UIManager.getColor( "controlDkShadow" );
        Color window = UIManager.getColor( "window" );
        setBorder( BorderFactory.createCompoundBorder(
            BorderFactory.createMatteBorder( 0, 0, 1, 1, window ),
            BorderFactory.createMatteBorder( 1, 1, 1, 1, shadow ) ) );
        setBackground( window );
        
        if ( scrollPane != null )
        {
            FWTable.updateFWTableScrollPane( scrollPane );
        }
    }
    
    /**
     * Submits a new search.
     */
    public boolean startKeywordSearch( String searchString )
    {
        if ( displayedDataModel != null && displayedDataModel.getSearch().isSearching() )
        {
            return false;
        }

        // try to find a existing and running search with the same search string
        // and select it if found.
        Search existingSearch = searchContainer.getRunningKeywordSearch( searchString );
        if ( existingSearch != null )
        {
            SearchResultsDataModel searchResultsDataModel = 
                SearchResultsDataModel.lookupResultDataModel( existingSearch );
            searchTab.setDisplayedSearch( searchResultsDataModel );
            return false;
        }
            
        if ( displayedDataModel == null )
        {
            Search newSearch = searchContainer.createSearch( searchString );
            SearchResultsDataModel searchResultsDataModel = 
                SearchResultsDataModel.registerNewSearch( newSearch );
            searchTab.setDisplayedSearch( searchResultsDataModel );
            
        }
        else
        {
            Search search = displayedDataModel.getSearch();
            if ( search instanceof KeywordSearch )
            {
                KeywordSearch keySearch = (KeywordSearch) search;
                keySearch.setSearchString( searchString );
                keySearch.startSearching();
            }
            else
            {
                assert false : "Edited none keyword search";
                return false;
            }
        }
        return true;
    }
    
    /**
     * Submits a new search.
     */
    public boolean startBrowseHost( String hostName )
    {
        if ( displayedDataModel != null && displayedDataModel.getSearch().isSearching() )
        {
            return false;
        }
        
        PresentationManager presMgr = PresentationManager.getInstance();
        DestAddress destAddress;
        try
        {
            destAddress = presMgr.createHostAddress( hostName, 
                IpAddress.DEFAULT_PORT);
        }
        catch (MalformedDestAddressException exp)
        {
            // malformed address
            return false;
        }

        // try to find a existing and running search with the same search string
        // and select it if found.
        Search existingSearch = searchContainer.getRunningBrowseHost( destAddress, 
            null );
        if ( existingSearch != null )
        {
            SearchResultsDataModel searchResultsDataModel = 
                SearchResultsDataModel.lookupResultDataModel( existingSearch );
            searchTab.setDisplayedSearch( searchResultsDataModel );
            return false;
        }

        Search newSearch = searchContainer.createBrowseHostSearch( destAddress, null );
        SearchResultsDataModel searchResultsDataModel = 
            SearchResultsDataModel.registerNewSearch( newSearch );
        searchTab.setDisplayedSearch( searchResultsDataModel );
        
        return true;
    }
    
    public void startWhatsNewSearch()
    {
        if ( displayedDataModel != null && displayedDataModel.getSearch().isSearching() )
        {
            return;
        }
        
        Search newSearch = QueryManager.getInstance().getSearchContainer().createWhatsNewSearch( );
        SearchResultsDataModel searchResultsDataModel = 
            SearchResultsDataModel.registerNewSearch( newSearch );
        searchTab.setDisplayedSearch( searchResultsDataModel );
    }
    
    public void stopSearching()
    {
        if ( displayedDataModel != null && displayedDataModel.getSearch().isSearching() )
        {
            displayedDataModel.getSearch().stopSearching();
        }
    }
    
    /////////////////////////////// Start SearchChangeListener /////////////////////////////
    
    /**
     * Notifys us about a change to the currently displayed search.
     * 
     * @see phex.event.SearchDataListener#searchDataChanged(phex.event.SearchDataEvent)
     */
    public void searchDataChanged( SearchDataEvent e )
    {
        short type = e.getType();
        switch (type)
        {
            case SearchDataEvent.SEARCH_STARTED:
            case SearchDataEvent.SEARCH_STOPED:
            case SearchDataEvent.SEARCH_CHANGED:
                updateControlPanel();            
        }
    }
    
    /////////////////////////////// End SearchChangeListener /////////////////////////////
    
    /////////////////////////////// Start Inner classes /////////////////////////////
    
    
    
    /**
     * Submits a whats new search.
     */
    private class WhatsNewSearchHandler extends AbstractAction implements ActionListener
    {
        public void actionPerformed( ActionEvent e )
        {
            if ( displayedDataModel != null && displayedDataModel.getSearch().isSearching() )
            {
                return;
            }
            
            Search newSearch = QueryManager.getInstance().getSearchContainer().createWhatsNewSearch( );
            SearchResultsDataModel searchResultsDataModel = 
                SearchResultsDataModel.registerNewSearch( newSearch );
            searchTab.setDisplayedSearch( searchResultsDataModel );            
        }
    }
/*    
    private class ButtonActionHandler extends AbstractAction implements ActionListener
    {
        public void actionPerformed( ActionEvent e )
        {
            filterSearchResults();
        }
        
        private void filterSearchResults()
        {
            if ( displayedDataModel == null )
            {
                return;
            }
            
            String searchFilter = filterTextTF.getText().trim();
            String minSizeStr = minFileSizeTF.getText().trim();
            String maxSizeStr = maxFileSizeTF.getText().trim();
            MediaType mediaType = (MediaType) mediaTypeComboBox.getSelectedItem();
            
            long finalMinSize = -1;
            try
            {
                if ( minSizeStr.length() > 0 )
                {
                    long minSize = Integer.parseInt( minSizeStr );
                    long minSizeMultiplier = minFileSizeUnitComboBox.getDefMultiplier();
                    finalMinSize = minSizeMultiplier * minSize;
                }
            }
            catch ( NumberFormatException exp )
            {
                displayWrongNumberFormatError( minFileSizeTF );
                return;
            }
            
            
            long finalMaxSize = -1;
            try
            {
                if ( maxSizeStr.length() > 0 )
                {
                    long maxSize = Integer.parseInt( maxSizeStr );
                    long maxSizeMultiplier = maxFileSizeUnitComboBox.getDefMultiplier();
                    finalMaxSize = maxSizeMultiplier * maxSize;
                }
            }
            catch ( NumberFormatException exp )
            {
                displayWrongNumberFormatError( maxFileSizeTF );
                return;
            }
            
            SearchFilter filter = displayedDataModel.getSearchFilter();
            if ( filter == null )
            {
                filter = new SearchFilter();
            }
            filter.updateSearchFilter( searchFilter, mediaType, finalMinSize, finalMaxSize );
            
            displayedDataModel.updateSearchFilter( filter );
            searchTab.getTabAction( SearchTab.REMOVE_FILTER_ACTION ).refreshActionState();
        }
        
        private void displayWrongNumberFormatError(JTextField textField)
        {
            textField.requestFocus();
            textField.selectAll();
            JOptionPane.showMessageDialog( searchTab,
                Localizer.getString( "WrongNumberFormat" ),
                Localizer.getString( "FormatError" ), JOptionPane.ERROR_MESSAGE  );
        }
    }
    */
    /////////////////////////////// End Inner classes /////////////////////////////
}
