/*
 * Copyright (c) 2009, Tony Kohar. All Rights Reserved.
 *
 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 * you may not use  this file  except in  compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package org.qi4j.envisage.detail;

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import org.qi4j.envisage.event.LinkEvent;
import org.qi4j.envisage.event.LinkListener;
import org.qi4j.tools.model.descriptor.EntityDetailDescriptor;
import org.qi4j.tools.model.descriptor.ImportedServiceDetailDescriptor;
import org.qi4j.tools.model.descriptor.LayerDetailDescriptor;
import org.qi4j.tools.model.descriptor.ModuleDetailDescriptor;
import org.qi4j.tools.model.descriptor.ObjectDetailDescriptor;
import org.qi4j.tools.model.descriptor.ServiceDetailDescriptor;
import org.qi4j.tools.model.descriptor.TransientDetailDescriptor;
import org.qi4j.tools.model.descriptor.ValueDetailDescriptor;

public final class DetailModelPane
    extends JPanel
{

    protected ResourceBundle bundle = ResourceBundle.getBundle( this.getClass().getName() );

    protected JTabbedPane tabPane;
    protected GeneralPane generalPane;
    protected MethodPane methodPane;
    protected StatePane statePane;
    protected DependencyPane dependencyPane;
    protected ServiceConfigurationPane serviceConfigurationPane;
    protected ServiceUsagePane serviceUsagePane;
    protected ImportedByPane importedByPane;
    protected APIPane apiPane;
    protected SPIPane spiPane;

    protected boolean linkActivatedInProgress;

    public DetailModelPane()
    {
        tabPane = new JTabbedPane();

        this.setLayout( new BorderLayout() );
        this.add( tabPane, BorderLayout.CENTER );

        createDetailPane();
    }

    private void createDetailPane()
    {
        generalPane = new GeneralPane( this );
        generalPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        statePane = new StatePane( this );
        statePane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        methodPane = new MethodPane( this );
        methodPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        dependencyPane = new DependencyPane( this );
        dependencyPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        serviceConfigurationPane = new ServiceConfigurationPane( this );
        serviceConfigurationPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        serviceUsagePane = new ServiceUsagePane( this );
        serviceUsagePane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        importedByPane = new ImportedByPane( this );
        importedByPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        apiPane = new APIPane( this );
        apiPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );

        spiPane = new SPIPane( this );
        spiPane.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );
    }

    public void setDescriptor( final Object objectDescriptor )
    {
        SwingUtilities.invokeLater( new Runnable()
        {
            @Override
            public void run()
            {
                setDescriptorImpl( objectDescriptor );
            }
        } );
    }

    private void setDescriptorImpl( Object objectDescriptor )
    {
        Component curSelectedComp = tabPane.getSelectedComponent();
        tabPane.removeAll();

        generalPane.setDescriptor( objectDescriptor );
        dependencyPane.setDescriptor( objectDescriptor );
        methodPane.setDescriptor( objectDescriptor );
        statePane.setDescriptor( objectDescriptor );
        serviceConfigurationPane.setDescriptor( objectDescriptor );
        serviceUsagePane.setDescriptor( objectDescriptor );
        importedByPane.setDescriptor( objectDescriptor );
        apiPane.setDescriptor( objectDescriptor );
        spiPane.setDescriptor( objectDescriptor );

        if( objectDescriptor instanceof LayerDetailDescriptor
            || objectDescriptor instanceof ModuleDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_APITab.Text" ), apiPane );
            tabPane.add( bundle.getString( "CTL_SPITab.Text" ), spiPane );
        }
        else if( objectDescriptor instanceof ServiceDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_DependencyTab.Text" ), dependencyPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
            tabPane.add( bundle.getString( "CTL_StateTab.Text" ), statePane );
            tabPane.add( bundle.getString( "CTL_ServiceConfiguration.Text" ), serviceConfigurationPane );
            tabPane.add( bundle.getString( "CTL_ServiceUsage.Text" ), serviceUsagePane );
        }
        else if( objectDescriptor instanceof ImportedServiceDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
            tabPane.add( bundle.getString( "CTL_ServiceUsage.Text" ), serviceUsagePane );
            tabPane.add( bundle.getString( "CTL_ImportedBy.Text" ), importedByPane );
        }
        else if( objectDescriptor instanceof EntityDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_DependencyTab.Text" ), dependencyPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
            tabPane.add( bundle.getString( "CTL_StateTab.Text" ), statePane );
        }
        else if( objectDescriptor instanceof ValueDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_DependencyTab.Text" ), dependencyPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
            tabPane.add( bundle.getString( "CTL_StateTab.Text" ), statePane );
        }
        else if( objectDescriptor instanceof ObjectDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_DependencyTab.Text" ), dependencyPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
        }
        else if( objectDescriptor instanceof TransientDetailDescriptor )
        {
            tabPane.add( bundle.getString( "CTL_GeneralTab.Text" ), generalPane );
            tabPane.add( bundle.getString( "CTL_DependencyTab.Text" ), dependencyPane );
            tabPane.add( bundle.getString( "CTL_MethodTab.Text" ), methodPane );
            tabPane.add( bundle.getString( "CTL_StateTab.Text" ), statePane );
        }

        if( linkActivatedInProgress )
        {
            // for linking always display the first tab (General)
            linkActivatedInProgress = false;
            tabPane.setSelectedIndex( 0 );
        }
        else
        {
            // if not linking, then maintain the current selected tab
            if( curSelectedComp != null )
            {
                int index = tabPane.indexOfComponent( curSelectedComp );
                if( index != -1 )
                {
                    tabPane.setSelectedIndex( index );
                }
            }
        }
    }

    /**
     * Add a listener that's notified each time a LinkEvent occurs.
     *
     * @param listener the LinkListener to add
     */
    public void addLinkListener( LinkListener listener )
    {
        listenerList.add( LinkListener.class, listener );
    }

    /**
     * Remove a listener that's notified each time a LinkEvent occurs.
     *
     * @param listener the LinkListener to remove
     */
    public void removeLinkListener( LinkListener listener )
    {
        listenerList.remove( LinkListener.class, listener );
    }

    /* package */ void fireLinkActivated( LinkEvent evt )
    {
        linkActivatedInProgress = true;
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for( int i = listeners.length - 2; i >= 0; i -= 2 )
        {
            if( listeners[i] == LinkListener.class )
            {
                ( (LinkListener) listeners[i + 1] ).activated( evt );
            }
        }
    }
}
