/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2004 Gregor Koukkoullis ( phex <at> kouk <dot> de )
 *
 *  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
 */
package phex.gui.tabs;

import java.awt.*;
import java.awt.event.*;
import java.util.Enumeration;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.TableColumn;
import javax.xml.bind.JAXBException;

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

import phex.gui.actions.FWAction;
import phex.gui.common.*;
import phex.gui.common.table.*;
import phex.gui.dialogs.SecurityRuleConfigDialog;
import phex.gui.models.*;
import phex.gui.renderer.SecurityRuleRowRenderer;
import phex.security.*;
import phex.utils.Localizer;
import phex.xml.*;


public class SecurityTab extends FWTab
{
    private static final String SECURITY_TABLE_IDENTIFIER = "SecurityTable";
    private static final SecurityRule[] EMPTY_SECURITYRULE_ARRAY =
        new SecurityRule[0];

    private JPopupMenu securityPopup;
    private SecurityTableModel securityModel;
    private FWTableColumnModel securityColumnModel;
    private FWTable securityTable;
    private JScrollPane securityTableScrollPane;
    private PhexSecurityManager securityMgr;

    public SecurityTab()
    {
        super( MainFrame.SECURITY_TAB_ID, Localizer.getString( "Security" ),
            GUIRegistry.getInstance().getIconFactory().getIcon( "Security" ),
            Localizer.getString( "TTTSecurity" ), Localizer.getChar(
            "SecurityMnemonic"), KeyStroke.getKeyStroke( Localizer.getString(
            "SecurityAccelerator" ) ), MainFrame.SECURITY_TAB_INDEX);
        securityMgr = PhexSecurityManager.getInstance();
    }

    public void initComponent( XJBGUISettings guiSettings )
    {
        MouseHandler mouseHandler = new MouseHandler();
        
        CellConstraints cc = new CellConstraints();
        FormLayout layout = new FormLayout(
            "4dlu, fill:d:grow, 4dlu", // columns
            "3dlu, p, 3dlu, fill:d:grow, 1dlu, p, 3dlu"); //rows
        PanelBuilder tabBuilder = new PanelBuilder( this, layout );
        
        tabBuilder.addSeparator( Localizer.getString("Security"),
            cc.xy( 2, 2 ) );
            
        securityModel = new SecurityTableModel();
        XJBGUITable xjbTable = GUIUtils.getXJBGUITableByIdentifier( guiSettings,
            SECURITY_TABLE_IDENTIFIER );
        buildSecurityTableColumnModel( xjbTable );
        
        securityTable = new FWTable( new FWSortedTableModel( securityModel ),
            securityColumnModel );
        SecurityRuleRowRenderer securityRowRenderer = new SecurityRuleRowRenderer();
        Enumeration enum = securityColumnModel.getColumns();
        while ( enum.hasMoreElements() )
        {
            TableColumn column = (TableColumn)enum.nextElement();
            column.setCellRenderer( securityRowRenderer );
        }
        securityTable.getSelectionModel().addListSelectionListener(
            new SelectionHandler() );
        securityTable.activateAllHeaderActions();
        securityTable.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
        securityTable.addMouseListener( mouseHandler );

        securityTableScrollPane = FWTable.createFWTableScrollPane( securityTable );
        securityTableScrollPane.addMouseListener( mouseHandler );
        
        tabBuilder.add( securityTableScrollPane, cc.xy( 2, 4 ) );

        FWToolBar securityToolbar = new FWToolBar( JToolBar.HORIZONTAL );
        securityToolbar.setBorderPainted( false );
        securityToolbar.setFloatable( false );
        tabBuilder.add( securityToolbar, cc.xy( 2, 6 ) );

        securityPopup = new JPopupMenu();

        // TODO add actions to toolbar and popup
        FWAction action = new NewSecurityRuleAction();
        addTabAction( action );
        securityToolbar.addAction( action );
        securityPopup.add( action );

        action = new EditSecurityRuleAction();
        addTabAction( EDIT_SECURITY_RULE_ACTION_KEY, action );
        securityToolbar.addAction( action );
        securityPopup.add( action );

        action = new RemoveSecurityRuleAction();
        addTabAction( action );
        securityToolbar.addAction( action );
        securityPopup.add( action );
    }
    
    /**
     * Indicates if this tab is visible by default, when there is no known 
     * visible setting from the user.
     * @return true if visible by default false otherwise.
     */
    public boolean isVisibleByDefault()
    {
        return false;
    }

    public void updateUI()
    {
        super.updateUI();
        if ( securityTableScrollPane != null )
        {
            FWTable.updateFWTableScrollPane( securityTableScrollPane );
        }
    }

    private SecurityRule[] getSelectedSecurityRules()
    {
        if ( securityTable.getSelectedRowCount() == 0 )
        {
            return EMPTY_SECURITYRULE_ARRAY;
        }
        int[] viewIndices = securityTable.getSelectedRows();
        int[] modelIndices = securityTable.convertRowIndicesToModel( viewIndices );
        SecurityRule[] files = securityMgr.getIPAccessRulesAt( modelIndices );
        return files;
    }


    //////////////////////////////////////////////////////////////////////////
    /// XML serializing and deserializing
    //////////////////////////////////////////////////////////////////////////

    private void buildSecurityTableColumnModel( XJBGUITable tableSettings )
    {
        int[] columnIds = SecurityTableModel.getColumnIdArray();
        XJBGUITableColumnList columnList = null;
        if ( tableSettings != null )
        {
            columnList = tableSettings.getTableColumnList();
        }

        securityColumnModel = new FWTableColumnModel( securityModel, columnIds,
            columnList );
    }

    public void appendXJBGUISettings( XJBGUISettings xjbSettings )
        throws JAXBException
    {
        super.appendXJBGUISettings( xjbSettings );
        XJBGUITableColumnList xjbList = securityColumnModel.createXJBGUITableColumnList();
        XJBGUITable xjbTable = ObjectFactory.createXJBGUITable();
        xjbTable.setTableColumnList( xjbList );
        xjbTable.setTableIdentifier( SECURITY_TABLE_IDENTIFIER );
        xjbSettings.getTableList().getTableList().add( xjbTable );
    }

    //////////////////////////////////////////////////////////////////////////
    /// Table Listeners
    //////////////////////////////////////////////////////////////////////////

    private class SelectionHandler implements ListSelectionListener
    {
        public void valueChanged(ListSelectionEvent e)
        {
            refreshTabActions();
        }
    }

    /**
     * Handles Mouse events to display popup menues.
     */
    private class MouseHandler extends MouseAdapter implements MouseListener
    {
        public void mouseClicked(MouseEvent e)
        {
            if ( e.getClickCount() == 2 )
            {
                if ( e.getSource() == securityTable )
                {
                    getTabAction( EDIT_SECURITY_RULE_ACTION_KEY ).actionPerformed( null );
                }
            }
        }

        public void mouseReleased(MouseEvent e)
        {
            if (e.isPopupTrigger())
            {
                popupMenu((Component)e.getSource(), e.getX(), e.getY());
            }
        }

        public void mousePressed(MouseEvent e)
        {
            if ( SwingUtilities.isRightMouseButton( e ) )
            {
                Component source = (Component)e.getSource();
                if ( source == securityTable )
                {
                    Point p = e.getPoint();
                    int row = securityTable.rowAtPoint( p );
                    int column = securityTable.columnAtPoint(p);
                    securityTable.changeSelection(row, column, false, false );
                }
            }
        }

        private void popupMenu(Component source, int x, int y)
        {
            if ( source == securityTable || source == securityTableScrollPane )
            {
                securityPopup.show( source, x, y );
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //// Start Actions
    ////////////////////////////////////////////////////////////////////////////

    private static final String EDIT_SECURITY_RULE_ACTION_KEY = "EditSecurityRuleAction";

    public class NewSecurityRuleAction extends FWAction
    {
        public NewSecurityRuleAction()
        {
            super( Localizer.getString( "NewSecurityRule" ),
                GUIRegistry.getInstance().getIconFactory().getIcon( "New"  ),
                Localizer.getString( "TTTNewSecurityRule" ) );
            setEnabled( true );
        }

        public void actionPerformed( ActionEvent e )
        {
            SecurityRuleConfigDialog dialog = new SecurityRuleConfigDialog();
            dialog.show();
        }

        public void refreshActionState()
        {
        }
    }

    public class EditSecurityRuleAction extends FWAction
    {
        public EditSecurityRuleAction()
        {
            super( Localizer.getString( "EditSecurityRule" ),
                GUIRegistry.getInstance().getIconFactory().getIcon( "Edit"  ),
                Localizer.getString( "TTTEditSecurityRule" ) );
            refreshActionState();
        }

        public void actionPerformed( ActionEvent e )
        {
            if ( securityTable.getSelectedRowCount() != 1 )
            {
                return;
            }
            int viewIdx = securityTable.getSelectedRow();
            int modelIdx = securityTable.convertRowIndexToModel( viewIdx );
            IPAccessRule rule = securityMgr.getIPAccessRule( modelIdx );
            if ( rule == null || rule.isSystemRule() )
            {
                return;
            }
            SecurityRuleConfigDialog dialog = new SecurityRuleConfigDialog( rule );
            dialog.show();
        }

        public void refreshActionState()
        {
            if ( securityTable.getSelectedRowCount() == 1 )
            {
                int viewIdx = securityTable.getSelectedRow();
                int modelIdx = securityTable.convertRowIndexToModel( viewIdx );
                IPAccessRule rule = securityMgr.getIPAccessRule( modelIdx );
                if ( rule.isSystemRule() )
                {
                    setEnabled( false );
                }
                else
                {
                    setEnabled( true );
                }
            }
            else
            {
                setEnabled( false );
            }
        }
    }

    public class RemoveSecurityRuleAction extends FWAction
    {
        public RemoveSecurityRuleAction()
        {
            super( Localizer.getString( "RemoveSecurityRule" ),
                GUIRegistry.getInstance().getIconFactory().getIcon( "Remove"  ),
                Localizer.getString( "TTTRemoveSecurityRule" ) );
            refreshActionState();
        }

        public void actionPerformed( ActionEvent e )
        {
            if ( securityTable.getSelectedRow() < 0 )
            {
                setEnabled( false);
                return;
            }
            SecurityRule[] securityRules = getSelectedSecurityRules();
            for ( int i = 0; i < securityRules.length; i++ )
            {
                if ( securityRules[i] != null && !securityRules[i].isSystemRule())
                {
                    PhexSecurityManager.getInstance().removeSecurityRule(
                       securityRules[i] );
                }
            }
        }

        public void refreshActionState()
        {
            int row = securityTable.getSelectedRow();
            if ( row < 0 )
            {
                setEnabled( false );
                return;
            }

            SecurityRule[] securityRules = getSelectedSecurityRules();
            for ( int i = 0; i < securityRules.length; i++ )
            {
                if ( !securityRules[i].isSystemRule() )
                {
                    setEnabled( true );
                    return;
                }
            }
            setEnabled( false );
        }
    }

}