/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             Stuart E. Middleton
//      Created date:           2004/04/30
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.utils.signalhandlers;

import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;


import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;

import eu.gemss.signals.negotiation.SelectSingleServiceRequest;
import eu.gemss.signals.SignalHandler;
import eu.gemss.signals.Signal;

/**
 * Sample Signal handler for SelectSingleServiceRequest signals
 */
public class SelectSingleServiceRequestHandler extends JPanel implements SignalHandler {
      // interface data
      private static final String mTitleString = "GEMSS service selector : Please select a single service";
      private JFrame mframe;
      private boolean mbExistingFrame;
      private JDialog mdialogModel;
      private JButton mbuttonSelect;
      private JButton mbuttonCancel;
      private JList mlistServices;
      private JTextArea mtextMetadata;
      private JScrollPane mscrollList;
      private JScrollPane mscrollText;
      private Dimension mdimensionBestSize;

      // request object
      private SelectSingleServiceRequest mselectServiceRequest;

      // other
      private Logger mlogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.utils.signalhandlers.SelectSingleServiceRequestHandler");

      /**
       * Default constructor that will cause a new frame object to be created just for
       * this dialogue box
       */
      public SelectSingleServiceRequestHandler()
      {
            mframe = null;
            mbExistingFrame = false;
            mdimensionBestSize = null;
      }

      /**
       * Constructor that will re-use an existing frame object when creating
       * this dialogue box
       * @param frame JFrame object to use a parent to the dialogue box
       */
      public SelectSingleServiceRequestHandler( JFrame frame ) throws Exception
      {
            if( frame == null ) throw new Exception("null frame object passed via constructor");
            mframe = frame;
            mbExistingFrame = true;
            mdimensionBestSize = null;
      }

      /**
       * Process the signal supplied by the Component Framework
       * @param signal signal to process
       */
      public void process( Signal signal )
      {
            Vector vector;
            Hashtable hash;
            Enumeration enum;
            String strWSDL;
            DefaultListModel listModel;

            try {
                  // check signal
                  if(signal instanceof eu.gemss.signals.negotiation.SelectSingleServiceRequest) {
                        // note signal
                        mselectServiceRequest = (eu.gemss.signals.negotiation.SelectSingleServiceRequest) signal;

                        // populate the controls
                        hash = mselectServiceRequest.getListOfServices();
                        if( hash == null ) throw new Exception("list of services hash = null");
                        if( hash.size() == 0 ) throw new Exception("list of services empty");

                        // make list model to hold selections
                        listModel = new DefaultListModel();
                        enum = hash.keys();
                        while( enum.hasMoreElements() ) {
                              // get key (WSDL URI) and add item to service list box
                              strWSDL = (String) enum.nextElement();
                              listModel.addElement( strWSDL );
                        }

                        // popup interface and show the list
                        initFrame();
                        initPanels( listModel );

                        // select first object (if any!) to trigger metadata dump in text area
                        if( listModel.size() > 0 ) mlistServices.setSelectedIndex( 0 );

                        // show the dialogue box and get the users selected option
                        // (model blocking call)
						mframe.toFront();
						mdialogModel.show();

                        // dispose of the gui
                        if( !mbExistingFrame ) mframe.dispose();
                        mdialogModel.dispose();

                        // tell the comp man that this signal was processed
                        mselectServiceRequest.processed();

                  } // end of signal type check
                  else mlogger.log( Level.WARNING,"SelectServiceRequestHandler was sent the wrong signal type");
            }
            catch( Exception ex ) {
                  // do nothing just return the signal unhandled
                  mlogger.log( Level.SEVERE,"SelectServiceRequest signal handler failed",ex);
                  if( mframe != null && !mbExistingFrame ) mframe.dispose();
                  if( mdialogModel != null ) mdialogModel.dispose();
            }
      }

      /*
      * return the preferred size
      * @return preferred size
      */
      public Dimension getPreferredSize()
      {
            return mdimensionBestSize;
      }

      /*
      * Initialize the sub panels and make all interface controls. All sub panels are
      * added to this class (a panel itself). This method will pass any exceptions
      * through to caller.
      */
      private void initPanels( DefaultListModel listModel ) throws Exception
      {
            JPanel panel;
            JScrollPane scroll;
            JLabel label;
            BorderLayout overallLayout;

            // layout
            overallLayout = new BorderLayout();
            setLayout( overallLayout );

            // make label panel
            panel = new JPanel( new BorderLayout( 5,0 ) );
            add( panel,BorderLayout.NORTH );
            label = new JLabel( " Service" );
            label.setPreferredSize( new Dimension( 200,25 ) );
            panel.add( label,BorderLayout.WEST );
            label = new JLabel( "  Service information" );
            label.setPreferredSize( new Dimension( 600,25 ) );
            panel.add( label,BorderLayout.CENTER );

            // make services panel
            panel = new JPanel( new BorderLayout( 5,0 ) );
            add( panel );

            // list of services
            mlistServices = new JList( listModel );
            mlistServices.setSelectionMode( ListSelectionModel.SINGLE_INTERVAL_SELECTION );
            mlistServices.setLayoutOrientation( JList.VERTICAL );
            mlistServices.addListSelectionListener( new ListSelector() );

            mscrollList = new JScrollPane( mlistServices );
            mscrollList.setPreferredSize( new Dimension(200, 200) );
            panel.add( mscrollList, BorderLayout.WEST );

            // metadata text area
            mtextMetadata = new JTextArea();
            mtextMetadata.setText("No information available at present");
            mtextMetadata.setEditable( false );

            mscrollText = new JScrollPane( mtextMetadata );
            mscrollText.setPreferredSize( new Dimension(600, 400) );
            panel.add( mscrollText,BorderLayout.CENTER );

            // make button panel
            panel = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
            add( panel,BorderLayout.SOUTH );

            // select
            mbuttonSelect = new JButton("Select");
            mbuttonSelect.addActionListener( new CommandAction("Select") );
            panel.add( mbuttonSelect );

            // cancel
            mbuttonCancel = new JButton("Cancel");
            mbuttonCancel.addActionListener( new CommandAction("Cancel") );
            panel.add( mbuttonCancel );

            // record best size and pack
            mdimensionBestSize = overallLayout.preferredLayoutSize( this );
            mdialogModel.pack();
            mdialogModel.setLocationRelativeTo( mframe ); // not right in top left!
      }

      /* Initialize the main frame and dialogue box. This method will pass any exceptions through to caller. */
      private void initFrame() throws Exception
      {
            // Make sure we have nice window decorations
            UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
            JDialog.setDefaultLookAndFeelDecorated( true );

            // make frame and dialogue box (use apps frame object if passed)
            if( !mbExistingFrame ) {
                  mframe = new JFrame( mTitleString );
                  mframe.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
            }
            mdialogModel = new JDialog( mframe, mTitleString, true );
            mdialogModel.getContentPane().add( this, BorderLayout.CENTER );
            mdialogModel.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE );
      }

      /* in-line class to handle button actions */
      private class CommandAction extends AbstractAction {
            // constructor
            public CommandAction( String name ) { super( name ); }
            // action handler
            public void actionPerformed(ActionEvent e)
            {
                  String strService;

                  if( e.getActionCommand().equals("Select") ) {
                        // get selected service
                        strService = (String) mlistServices.getSelectedValue();
                        mlogger.log( Level.INFO,"User selected service = "+strService );

                        // set the request signal result
                        mselectServiceRequest.setSelectedService( strService );

                        // exit
                        if( !mbExistingFrame ) mframe.dispose();
                        mdialogModel.dispose();
                  }
                  else if( e.getActionCommand().equals("Cancel") ) {
                        // set the request signal result to be null
                        mselectServiceRequest.setSelectedService( null );
                        mlogger.log( Level.INFO,"User cancelled service selection" );

                        // exit
                        if( !mbExistingFrame ) mframe.dispose();
                        mdialogModel.dispose();
                  }
                  else mlogger.log( Level.WARNING,"Unhandled action from select service interface");
            }
      }

      /* in-line class to handle button actions */
      private class ListSelector implements ListSelectionListener {
            // constructor
            public ListSelector() { ; }

            // selection changed handler
            public void valueChanged( ListSelectionEvent e )
            {
                  String strService, strMetadata;
                  Hashtable hash;
                  Vector vector;
                  int i;

                  // get selected service
                  strService = (String) mlistServices.getSelectedValue();

                  // find its metadata
                  hash = mselectServiceRequest.getListOfServices();
                  vector = (Vector) hash.get( strService );

                  // make string representation of metadata
                  if( vector != null ) {
                        strMetadata = "";
                        for( i=0;i<vector.size();i++ ) {
                              strMetadata += (String) vector.elementAt(i) + "\n";
                        }
                        if( strMetadata.equals("") ) strMetadata = "No service information available for this service";
                  }
                  else strMetadata = "Service information not available";

                  // set the metadata to appear within the text area
                  mtextMetadata.setText( strMetadata );
            }
      }
}