package com.sptci.echo2;

import java.beans.PropertyChangeEvent;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.util.HashMap;
import java.util.logging.Logger;

import nextapp.echo2.app.ListBox;
import nextapp.echo2.app.SelectField;
import nextapp.echo2.app.button.AbstractButton;
import nextapp.echo2.app.text.TextComponent;

/**
 * A sub-class of {@link PropertyChangeListener} used to synchronise 
 * changes made to properties in Echo2 UI components to the
 * {@link #bean} java bean.
 *
 * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
 * @author Rakesh Vidyadharan 2006-01-22
 * @version $Id: ModelPropertyChangeListener.java,v 1.1 2006/02/13 23:07:28 rakesh Exp $
 */
public class ModelPropertyChangeListener extends PropertyChangeListener 
  implements Serializable
{
  /**
   * The logger used to log errors to
   */
  private static transient final Logger logger =
    Logger.getLogger( "com.sptci.echo2.ModelPropertyChangeListener" );

  /**
   * Create a new instance of the class using the specified java bean.
   *
   * @param bean The data object which is to be managed.
   * @throws IntrospectionException If errors are encountered while
   *   introspecting the {@link #bean} class.
   */
  public ModelPropertyChangeListener( Object bean )
    throws IntrospectionException
  {
    super( bean );
  }

  /**
   * Over-riddent implementation of the method defined in <code>
   * PropertyChangeListener</code>.  Checks for valid <code>Echo2
   * </code> components and ignores all other mouse and keyboard
   * events.
   *
   * @see #modify
   * @param event A <code>PropertyChangeEvent</code> object describing 
   *   the event source and the property that has changed.
   * @throws BindingException If errors are encountered while
   *   attempting to modify the {@link #bean}.
   */
  public void propertyChange( PropertyChangeEvent event )
  {
    String name = null;

    if ( event.getSource() instanceof 
        nextapp.echo2.app.text.TextComponent && 
        event.getPropertyName().equals( "text" ) )
    {
      name = ( (TextComponent) event.getSource() ).getActionCommand();
    }
    else if ( event.getSource() instanceof 
        nextapp.echo2.app.button.AbstractButton && 
        event.getPropertyName().equals( "selected" ) )
    {
      name = ( (AbstractButton) event.getSource() ).getActionCommand();
    }
    else if ( event.getSource() instanceof nextapp.echo2.app.SelectField )
    {
      SelectField field = (SelectField) event.getSource();
      name = field.getActionCommand();
      Object newValue = field.getSelectedItem();
      event = new PropertyChangeEvent( event.getSource(),
          name, event.getOldValue(), newValue );
    }
    else if ( event.getSource() instanceof nextapp.echo2.app.ListBox )
    {
      ListBox box = (ListBox) event.getSource();
      name = box.getActionCommand();
      Object newValue = box.getSelectedValues();
      event = new PropertyChangeEvent( event.getSource(),
          name, event.getOldValue(), newValue );
    }
    else
    {
      logger.warning( "unknown event source: " + event.getSource() +
          " name: " + event.getPropertyName() +
          " value: " + event.getNewValue() );
    }

    modify( name, event );
  }

  /**
   * Modify the property with the specified <code>name</code> with the 
   * new value in the specified <code>event</code>.
   *
   * @see #parseName
   * @param name The name of the field that is to be modified.
   * @param event A <code>PropertyChangeEvent</code> object describing 
   *   the event source and the property that has changed.
   * @throws BindingException If errors are encountered while
   *   attempting to modify the field with <code>name</code> in
   *   {@link #bean}.
   */
  protected void modify( String name, PropertyChangeEvent event )
  {
    name = parseName( name );
    PropertyDescriptor descriptor = properties.get( name );
    if ( descriptor != null )
    {
      if ( descriptor.getWriteMethod() == null )
      {
        throw new BindingException( "No write method for property: " +
            event.getPropertyName() + " in bean: " +
            bean.getClass().getName() );
      }

      if ( descriptor.getPropertyType().isPrimitive() )
      {
        modifyPrimitive( event, descriptor );
      }
      else
      {
        modifyObject( event, descriptor );
      }
    }
  }
}
