/////////////////////////////////////////////////////////////////////////
//
// © 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 java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
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 javax.swing.AbstractAction;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JLabel;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.io.*;


import uk.ac.soton.itinnovation.gemss.utils.signalhandlers.DateButton;
import eu.gemss.signals.negotiation.GetQoSParametersRequest;
import eu.gemss.signals.SignalHandler;
import eu.gemss.signals.Signal;

/**
 * Sample Signal handler for GetQoSParametersRequest signals
 */
public class GetQoSParametersRequestHandler extends JPanel implements SignalHandler {
      // interface data
      private static final String mTitleString = "Negotiation criteria : ";
      private JFrame mframe;
      private boolean mbExistingFrame;
      private boolean mbAbort;
      private String mstrConfigFile;
      private JDialog mdialogModel;
      private JButton mbuttonProceed;
      private JButton mbuttonAbort;
      private Vector mvectorDynamicControls; // contains all labels, text araes etc in the Grid section of the dialogue box plus vector for date/time control pair
      private Dimension mdimensionBestSize;

      // request object
      private GetQoSParametersRequest mrequest;

      // other
      private Logger mlogger = Logger.getLogger("uk.ac.soton.itinnovation.gemss.utils.signalhandlers.GetQoSParametersRequestHandler");
      // config suffixes and prefixed
      // Prop<n>=prop URI
      // Prop<n>Weight=inportance weight between 0 and 1 (double)
      // Prop<n>Min=min value
      // Prop<n>Max=max value
      private static final String mstaticPropPrefix = "Prop";
      private static final String mstaticWeightSuffix = "Weight";
      private static final String mstaticMinSuffix = "Min";
      private static final String mstaticMaxSuffix = "Max";

      /**
       * Default constructor that will cause a new frame object to be created just for
       * this dialogue box
       */
      public GetQoSParametersRequestHandler()
      {
            mframe = null;
            mbExistingFrame = false;
            mbAbort = false;
            mvectorDynamicControls = new Vector();
            mdimensionBestSize = null;
            mstrConfigFile = 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 GetQoSParametersRequestHandler( JFrame frame ) throws Exception
      {
            if( frame == null ) throw new Exception("null frame object passed via constructor");
            mframe = frame;
            mbAbort = false;
            mbExistingFrame = true;
            mvectorDynamicControls = new Vector();
            mdimensionBestSize = null;
            mstrConfigFile = null;
      }

      /**
       * Constructor that will fill in all values from a config file
       * @param strConfig filename with all parameter values pre-set (no need for a dialogue box)
       */
      public GetQoSParametersRequestHandler( String strConfigFile ) throws Exception
      {
            // TODO read config properties from config file
            mframe = null;
            mbExistingFrame = false;
            mbAbort = false;
            mvectorDynamicControls = null;
            mdimensionBestSize = null;
            mstrConfigFile = strConfigFile;
      }

      /**
       * 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;
            boolean bOk;

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

                        // check for config file pre-set values
                        if( mstrConfigFile != null ) {
                              LoadConfig( mrequest );
                              mrequest.processed();
                        }
                        else {
                              // popup interface and show the list
                              initFrame();
                              initPanels();

                              // loop until abort or good values entered
                              bOk = false;
                              while( !bOk ) {
                                    // show the dialogue box and get the users selected option
                                    // (model blocking call)
									mframe.toFront();
									mdialogModel.show();

                                    // extract values from controls into the request object
                                    if( !mbAbort ) {
                                          // get values from the UI controls
                                          bOk = extractValuesFromUI();
                                          if( bOk ) {
                                                // tell the comp man that this signal was processed
                                                // or leave unprocessed if abort called
                                                mrequest.processed();
                                          }
                                    }
                                    else {
                                          mrequest.setFailed();
                                          bOk = true;
                                    }
                              }

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

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

      /**
       * Loads a config file with neg parameters and sets the signal values to these config values
       * @param strConfig filename with all parameter values pre-set
       */
      public void LoadConfig( GetQoSParametersRequest request ) throws Exception
      {
            Properties props;
            String strValue, strPropName, strPropURI;
            int i,j;
            boolean bFound;
            Vector vector;

            // check param
            if( mstrConfigFile == null ) throw new IOException("null config filename parameter");

            // read the configuration options from the config file
            props = new Properties();
            props.load( new FileInputStream( mstrConfigFile ) );

            // loop on props
            i = 1;
            while( i != -1 ) {
                  // get prop name from config file
                  strPropURI = props.getProperty( mstaticPropPrefix + i );
                  if( strPropURI != null ) {
                        // set found flag
                        bFound = false;

                        // find prop name in vector
                        for( j=0;j<request.getSize();j++ ) {
                              // get property vector (name, desc, unit type, unit desc, weight, min, max)
                              vector = mrequest.getPropertyByIndex(j);

                              // get prop name
                              strPropName = (String) vector.elementAt(0);
                              if( strPropName == null ) throw new Exception("null property in request vector");

                              // match?
                              if( strPropURI.equals( strPropName ) ) {
                                    // read property weight (URI+Suffix=Value)
                                    strValue = props.getProperty( mstaticPropPrefix + i + mstaticWeightSuffix,"" );
                                    vector.setElementAt( strValue,4 );

                                    // read property min (URI+Suffix=Value)
                                    strValue = props.getProperty( mstaticPropPrefix + i + mstaticMinSuffix,"" );
                                    vector.setElementAt( strValue,5 );

                                    // read property max (URI+Suffix=Value)
                                    strValue = props.getProperty( mstaticPropPrefix + i + mstaticMaxSuffix,"" );
                                    vector.setElementAt( strValue,6 );

                                    bFound = true;
                              } // match check
                        } // next prop in vector

                        // check found and warn if not
                        if( !bFound ) mlogger.log( Level.WARNING,"Property "+strPropURI+" not found in WSLA vector, ignoring");
                        i++; // next

                  } // null check
                  else {
                        i = -1; // stop looking, no more prop entries in config file
                  }
            } // next prop
      }

      /*
      * return the preferred size based on the number of properties in the request object
      * @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() throws Exception
      {
            JPanel panel, panel2, panel3;
            JLabel label;
            JTextField textField;
            JFormattedTextField formatField;
            JSlider slider;
            JCheckBox checkBox;
            DateButton dateButton;
            Font fontHeader, fontBody;
            int i, nHeight;
            String strDefault;
            Integer nUnitType;
            Number number;
            Vector vector, vectorPair;
            BorderLayout overallLayout;
            Date dateNow;

            // init
            dateNow = new Date( System.currentTimeMillis() +10*60*1000 ); // give 10 mins time to upload data etc
            nHeight = 27;

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

            // make header panel
            panel = new JPanel( new FlowLayout( FlowLayout.LEFT ) );
            add( panel,BorderLayout.NORTH );
            label = new JLabel( " Quality of service objectives [allow some upload time before you start the job]" );
            panel.add( label );

            // make flow panel for columns
            panel = new JPanel( new FlowLayout( FlowLayout.LEFT,10,0 ) );
            add( panel,BorderLayout.CENTER );
            fontHeader = new Font( "Helvetica",Font.ITALIC,14 );
            fontBody = new Font( "Helvetica",Font.PLAIN,12 );

            // QoS property column
            panel2 = new JPanel( new GridLayout( mrequest.getSize()+1,1,0,5 ) );
            panel.add( panel2 );
            label = new JLabel( "QoS Property",JLabel.RIGHT );
            label.setFont( fontHeader );
            label.setPreferredSize( new Dimension( 100,nHeight ) );
            panel2.add( label );

            // loop on all properties (if any)
            for( i=0;i<mrequest.getSize();i++ ) {
                  // get property vector (name, desc, unit type, unit desc, weight, min, max)
                  vector = mrequest.getPropertyByIndex(i);

                  // prop name (desc) label
                  label = new JLabel( (String) vector.elementAt(1),JLabel.RIGHT );
                  label.setFont( fontBody );
                  mvectorDynamicControls.addElement( label );
                  panel2.add( label );
            } // next property

            // importance column
            panel2 = new JPanel( new GridLayout( mrequest.getSize()+1,1,0,5 ) );
            panel.add( panel2 );
            label = new JLabel( "[-]  Importance  [+]" );
            label.setFont( fontHeader );
            label.setPreferredSize( new Dimension( 110,nHeight ) );
            panel2.add( label );

            // loop on all properties (if any)
            for( i=0;i<mrequest.getSize();i++ ) {
                  // importance slider
                  slider = new JSlider( 0,100 );
                  slider.setValue(100); // default value
                  slider.setPreferredSize( new Dimension( 50,25 ) );
                  mvectorDynamicControls.addElement( slider );
                  panel2.add( slider );
            } // next property

            // min column
            panel2 = new JPanel( new GridLayout( mrequest.getSize()+1,1,0,5 ) );
            panel.add( panel2 );
            label = new JLabel( "Min" );
            label.setFont( fontHeader );
            label.setPreferredSize( new Dimension( 25,nHeight ) );
            panel2.add( label );

            // loop on all properties (if any)
            for( i=0;i<mrequest.getSize();i++ ) {
                  // get property vector (name, desc, unit type, unit desc, weight, min, max)
                  vector = mrequest.getPropertyByIndex(i);

                  // get unit type
                  nUnitType = (Integer) vector.elementAt(2);
                  if( nUnitType.intValue() == GetQoSParametersRequest.mstaticGMT2000DateOffsetUnitFlag ) {
                        // date/time control pair
                        vectorPair = new Vector();
                        mvectorDynamicControls.addElement( vectorPair );
                        panel3 = new JPanel( new FlowLayout( FlowLayout.LEFT,0,0 ) );

                        // date control
                        dateButton = new DateButton( mframe );
                        dateButton.setDate( dateNow );
                        dateButton.setFont( fontBody );
                        panel3.add( dateButton );
                        vectorPair.addElement( dateButton );

                        // time control
                        formatField = new JFormattedTextField( DateFormat.getTimeInstance( DateFormat.SHORT ) ); // time for default locale
                        formatField.setValue( dateNow ); // default current time
                        formatField.setFont( fontBody );
                        panel3.add( formatField );
                        vectorPair.addElement( formatField );

                        // add to main panel
                        panel2.add( panel3 );
                  }
                  else {
                        if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag  ||
                            nUnitType.intValue() == GetQoSParametersRequest.mstaticLongUnitFlag ) {
                              // min edit box (double, long)
                              formatField = new JFormattedTextField( NumberFormat.getNumberInstance() ); // general number formatter
                              formatField.setFont( fontBody );
                              if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag ) formatField.setValue( new Double(0.0) );
                              else formatField.setValue( new Long(0) );
                              mvectorDynamicControls.addElement( formatField );
                              panel2.add( formatField );
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticBooleanUnitFlag ) {
                              // check box (boolean)
                              checkBox = new JCheckBox("enable");
                              checkBox.setFont( fontBody );
                              checkBox.setPreferredSize( new Dimension( 20,12 ) ); // too hight otherwise
                              mvectorDynamicControls.addElement( checkBox );
                              panel2.add( checkBox );
                        }
                  }
            } // next property

            // max column
            panel2 = new JPanel( new GridLayout( mrequest.getSize()+1,1,0,5 ) );
            panel.add( panel2 );
            label = new JLabel( "Max" );
            label.setFont( fontHeader );
            label.setPreferredSize( new Dimension( 25,nHeight ) );
            panel2.add( label );

            // loop on all properties (if any)
            for( i=0;i<mrequest.getSize();i++ ) {
                  // get property vector (name, desc, unit type, unit desc, weight, min, max)
                  vector = mrequest.getPropertyByIndex(i);

                  // get unit type
                  nUnitType = (Integer) vector.elementAt(2);
                  if( nUnitType.intValue() == GetQoSParametersRequest.mstaticGMT2000DateOffsetUnitFlag ) {
                        // date/time control pair
                        vectorPair = new Vector();
                        mvectorDynamicControls.addElement( vectorPair );
                        panel3 = new JPanel( new FlowLayout( FlowLayout.LEFT,0,0 ) );

                        // date control
                        dateButton = new DateButton( mframe );
                        dateButton.setDate( dateNow );
                        dateButton.setFont( fontBody );
                        panel3.add( dateButton );
                        vectorPair.addElement( dateButton );

                        // time control
                        formatField = new JFormattedTextField( DateFormat.getTimeInstance( DateFormat.SHORT ) ); // time for default locale
                        formatField.setValue( dateNow ); // default current time
                        formatField.setFont( fontBody );
                        panel3.add( formatField );
                        vectorPair.addElement( formatField );

                        // add to main panel
                        panel2.add( panel3 );
                  }
                  else {
                        if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag  ||
                            nUnitType.intValue() == GetQoSParametersRequest.mstaticLongUnitFlag ) {
                              // min edit box (double, long)
                              formatField = new JFormattedTextField( NumberFormat.getNumberInstance() ); // general number formatter
                              formatField.setFont( fontBody );
                              if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag ) formatField.setValue( new Double(0.0) );
                              else formatField.setValue( new Long(0) );
                              mvectorDynamicControls.addElement( formatField );
                              panel2.add( formatField );
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticBooleanUnitFlag ) {
                              // blank label (boolean) since only need one field for boolean
                              label = new JLabel();
                              mvectorDynamicControls.addElement( label );
                              panel2.add( label );
                        }
                  }
            } // next property

            // unit column
            panel2 = new JPanel( new GridLayout( mrequest.getSize()+1,1,0,5 ) );
            panel.add( panel2 );
            label = new JLabel( "Unit" );
            label.setFont( fontHeader );
            label.setPreferredSize( new Dimension( 30,nHeight ) );
            panel2.add( label );

            // loop on all properties (if any)
            for( i=0;i<mrequest.getSize();i++ ) {
                  // get property vector (name, desc, unit type, unit desc, weight, min, max)
                  vector = mrequest.getPropertyByIndex(i);

                  // unit decription label
                  label = new JLabel( (String) vector.elementAt(3) );
                  label.setFont( fontBody );
                  mvectorDynamicControls.addElement( label );
                  panel2.add( label );
            } // next property

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

            // label
            label = new JLabel( "Click PROCEED to start negotiation, or ABORT to halt negotiation " );
            panel.add( label );

            // proceed
            mbuttonProceed = new JButton("Proceed");
            mbuttonProceed.addActionListener( new CommandAction("Proceed") );
            panel.add( mbuttonProceed );

            // abort
            mbuttonAbort = new JButton("Abort");
            mbuttonAbort.addActionListener( new CommandAction("Abort") );
            panel.add( mbuttonAbort );

            // 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
      {
            String strTitle;

            // Make sure we have nice window decorations
            UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
            JDialog.setDefaultLookAndFeelDecorated( true );

            // make title
            if( mrequest.getOverallDescription() != null ) {
                  strTitle = mTitleString + mrequest.getOverallDescription();
            }
            else {
                  strTitle = mTitleString + "---";
            }

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

      /* extract values from the UI controls and set these values into the request signal
      * @return false if the fields apear invalid (e.g. start time > end time)
      */

      private boolean extractValuesFromUI() throws Exception
      {
            JTextField textField;
            JFormattedTextField formatField;
            JSlider slider;
            JCheckBox checkBox;
            JLabel label;
            DateButton dateButton;
            int i, nIndex, nValue;
            long nDateOffset, nMin, nMax;
            boolean bOk, bCheck;
            String strValue;
            Integer nUnitType;
            Number n;
            Vector vector, vectorPair;
            Date date1, date2, date2000GMT;
            Calendar calendar1, calendar2;

            // set to true unless we see a problem
            bOk = true;
            mbuttonProceed.setForeground( Color.BLACK );

            try {
                  // loop on all properties (if any) and extract the values
                  for( i=0;i<mrequest.getSize();i++ ) {
                        // get property vector (name, desc, unit type, unit desc, weight, min, max)
                        vector = mrequest.getPropertyByIndex(i);
                        nMin = 0;
                        nMax = 0;
                        bCheck = false;

                        // set colour of label to black initially
                        label = (JLabel) mvectorDynamicControls.elementAt( i );
                        label.setForeground( Color.BLACK );

                        // dynamic control vector contains sets of (n*label, n*slider, n*text, n*text, n*label)

                        // get importance
                        slider = (JSlider) mvectorDynamicControls.elementAt( mrequest.getSize() + i );
                        nValue = slider.getValue(); // 0 to 100
                        strValue = "" + ((1.0 * nValue) / 100.0); // weight = 0 -> 1 (double)
                        vector.setElementAt( strValue,4 );

                        // get unit type
                        nUnitType = (Integer) vector.elementAt(2);

                        // get min
                        if( nUnitType.intValue() == GetQoSParametersRequest.mstaticGMT2000DateOffsetUnitFlag ) {
                              // check dates
                              bCheck = true;
                              // get vector pair
                              vectorPair = (Vector) mvectorDynamicControls.elementAt( mrequest.getSize()*2 + i );

                              // get date button and its value
                              dateButton = (DateButton) vectorPair.elementAt(0);
                              date1 = dateButton.getDate();

                              // get time field
                              formatField = (JFormattedTextField) vectorPair.elementAt(1);
                              date2 = (Date) formatField.getValue(); // get time

                              // add time to date
                              calendar2 = new GregorianCalendar();
                              calendar2.setTime( date2 );
                              calendar1 = new GregorianCalendar();
                              calendar1.setTime( date1 );
                              calendar1.set( Calendar.HOUR_OF_DAY, calendar2.get( Calendar.HOUR_OF_DAY ) );
                              calendar1.set( Calendar.MINUTE, calendar2.get( Calendar.MINUTE ) );
                              calendar1.set( Calendar.SECOND, 0 );
                              date1 = calendar1.getTime();

                              // get date offset
                              if( date1 == null ) {
                                    strValue = "-1"; // default date offset
                                    bOk = false;
                                    nMin = -1;
                              }
                              else {
                                    // get millisecond offset from 2000.1.1 GMT
                                    calendar1 = new GregorianCalendar( TimeZone.getTimeZone("GMT") );
                                    calendar1.set( 2000,0,1,0,0,0 );
                                    date2000GMT = calendar1.getTime();
                                    nDateOffset = date1.getTime() - date2000GMT.getTime();
                                    strValue = "" + nDateOffset;
                                    nMin = nDateOffset;
                              }
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag ) {
                              // check doubles
                              bCheck = true;
                              // get number field (double)
                              formatField = (JFormattedTextField) mvectorDynamicControls.elementAt( mrequest.getSize()*2 + i );
                              n = (Number) formatField.getValue();
                              strValue = n.toString();
                              nMin = Math.round( n.doubleValue() );
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticLongUnitFlag ) {
                              // check longs
                              bCheck = true;
                              // get number field (long)
                              formatField = (JFormattedTextField) mvectorDynamicControls.elementAt( mrequest.getSize()*2 + i );
                              n = (Number) formatField.getValue();
                              strValue = n.toString();
                              nMin = n.longValue();
                        }
                        else {
                              // do not check boolean
                              bCheck = false;
                              // boolean checkbox - need a true or false value
                              checkBox = (JCheckBox) mvectorDynamicControls.elementAt( mrequest.getSize()*2 + i );
                              if( checkBox.isSelected() ) strValue = "true";
                              else strValue = "false";
                              nMin = 0;
                        }
                        vector.setElementAt( strValue,5 );

                        // get max
                        if( nUnitType.intValue() == GetQoSParametersRequest.mstaticGMT2000DateOffsetUnitFlag ) {
                              // check dates
                              bCheck = true;
                              // get vector pair
                              vectorPair = (Vector) mvectorDynamicControls.elementAt( mrequest.getSize()*3 + i );

                              // get date button and its value
                              dateButton = (DateButton) vectorPair.elementAt(0);
                              date1 = dateButton.getDate();

                              // get time field
                              formatField = (JFormattedTextField) vectorPair.elementAt(1);
                              date2 = (Date) formatField.getValue(); // get time

                              // add time to date
                              calendar2 = new GregorianCalendar();
                              calendar2.setTime( date2 );
                              calendar1 = new GregorianCalendar();
                              calendar1.setTime( date1 );
                              calendar1.set( Calendar.HOUR_OF_DAY, calendar2.get( Calendar.HOUR_OF_DAY ) );
                              calendar1.set( Calendar.MINUTE, calendar2.get( Calendar.MINUTE ) );
                              calendar1.set( Calendar.SECOND, 0 );
                              date1 = calendar1.getTime();

                              // get date offset
                              if( date1 == null ) {
                                    strValue = "-1"; // default date offset
                                    bOk = false;
                                    nMax = -1;
                              }
                              else {
                                    // get millisecond offset from 2000.1.1 GMT
                                    calendar1 = new GregorianCalendar( TimeZone.getTimeZone("GMT") );
                                    calendar1.set( 2000,0,1,0,0,0 );
                                    date2000GMT = calendar1.getTime();
                                    nDateOffset = date1.getTime() - date2000GMT.getTime();
                                    strValue = "" + nDateOffset;
                                    nMax = nDateOffset;
                              }
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticDoubleUnitFlag ) {
                              // check doubles
                              bCheck = true;
                              // get number field (double)
                              formatField = (JFormattedTextField) mvectorDynamicControls.elementAt( mrequest.getSize()*3 + i );
                              n = (Number) formatField.getValue();
                              strValue = n.toString();
                              nMax = Math.round( n.doubleValue() );
                        }
                        else if( nUnitType.intValue() == GetQoSParametersRequest.mstaticLongUnitFlag ) {
                              // check longs
                              bCheck = true;
                              // get number field (long)
                              formatField = (JFormattedTextField) mvectorDynamicControls.elementAt( mrequest.getSize()*3 + i );
                              n = (Number) formatField.getValue();
                              strValue = n.toString();
                              nMax = n.longValue();
                        }
                        else {
                              // do not check boolean
                              bCheck = false;
                              // ignore blank for boolean
                              strValue = "";
                              nMax = 0;
                        }
                        vector.setElementAt( strValue,6 );

                        // validity check for min/max and make label red if invalid
                        if( bCheck ) {
                              if( nMin >= nMax ) {
                                    bOk = false;
                                    System.out.println("Min >= Max in UI for property "+(i+1));
                                    label = (JLabel) mvectorDynamicControls.elementAt( i );
                                    label.setForeground( Color.RED );
                              }
                        }
                  } // next property
            }
            catch( Exception ex ) {
                  bOk = false;
                  System.out.println("UI error extracting values : "+ex.getMessage());
                  mbuttonProceed.setForeground( Color.RED );
            }

            return bOk;
      }

       /* 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;

				try
				{
                  if( e.getActionCommand().equals("Proceed") ) {
                        // exit (current values will be taken)
                        mdialogModel.dispose();
                  }
                  else if( e.getActionCommand().equals("Abort") ) {
                        // set abort flag
                        mbAbort = true;

                        // exit
                        mdialogModel.dispose();
                  }
                  else mlogger.log( Level.WARNING,"Unhandled action from get QoS property handler interface");
				}
				catch ( Exception ex )
				{
					mlogger.log( Level.SEVERE, "Error on proceed event in UI",ex );
					return; // nothing we can do but ignore (UI failure for some reason)
				}
            }
      }
}