package org.pietschy.command.delegate;

import javax.swing.event.EventListenerList;

/**
 * DelegateMediators are used by {@link DelegatingCommand} instances to find their delegates.
 * Each mediator is bound to a specified window and is associated with a command by
 * invoking {@link DelegatingCommand#trackDelegateIn(String, java.awt.Window)}.
 * <p/>
 * DelegateMediator instances can be accessed by calling {@link DelegateManager#getMediatorFor(java.awt.Component)}
 * and {@link DelegateManager#getMediatorFor(java.awt.Window)}.
 * <p/>
 * You can customise the creation of mediators by providing a custom {@link DelegateMediatorFactory} to
 * the {@link DelegateManager}.
 */
public class DelegateMediator
{
   private EventListenerList listenerList = new EventListenerList();

   public static final DelegateContainer[] EMPTY_CONTAINER_ARRAY = new DelegateContainer[0];

   private DelegateContainer[] delegateContainers = EMPTY_CONTAINER_ARRAY;

   /**
    * This method is a convenience for {@link #setDelegateContainers(DelegateContainer[])}.
    *
    * @param container the container to use or <code>null</code> to disable all delegates.
    */
   public void setDelegateContainer(DelegateContainer container)
   {
      setDelegateContainers(nullSafeArray(container));
   }

   /**
    * Sets the current {@link DelegateContainer} to be used by all {@link DelegatingCommand}s associated
    * with this mediator.
    *
    * @param containers the containers to use, or <code>null</code> to clear all the containers.
    */
   public void setDelegateContainers(DelegateContainer[] containers)
   {
      delegateContainers = nullSafeArray(containers);
      fireDelegatesChanged(delegateContainers);
   }

   public DelegateContainer[] getDelegateContainers()
   {
      return delegateContainers;
   }

   public void addDelegateTrackerListener(DelegateMediatorListener listener)
   {
      listenerList.add(DelegateMediatorListener.class, listener);
   }

   public void removeDelegateTrackerListener(DelegateMediatorListener listener)
   {
      listenerList.remove(DelegateMediatorListener.class, listener);
   }

   /**
    * Creates an array containing the specified container.  If container is null this
    * method returns and empty array.
    *
    * @param container the container.
    * @return a non <code>null</code> array containing the container or an empty array
    *         if the container was <code>null</code>.
    */
   protected DelegateContainer[] nullSafeArray(DelegateContainer container)
   {
      return container == null ? EMPTY_CONTAINER_ARRAY : new DelegateContainer[]{container};
   }

   /**
    * Returns the specified array or and empty array if containers was <code>null</code>.
    *
    * @param containers the {@link DelegateContainer}s to use.
    * @return the specified array or and empty array if containers was <code>null</code>.
    */
   protected DelegateContainer[] nullSafeArray(DelegateContainer[] containers)
   {
      return containers == null ? EMPTY_CONTAINER_ARRAY : containers;
   }


   protected void fireDelegatesChanged(DelegateContainer[] containers)
   {
      // 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
      DelegateMediatorEvent event = null;
      for (int i = listeners.length - 2; i >= 0; i -= 2)
      {
         if (event == null)
         {
            event = new DelegateMediatorEvent(this, containers);
         }

         if (listeners[i] == DelegateMediatorListener.class)
         {
            ((DelegateMediatorListener) listeners[i + 1]).delegatesChanged(event);
         }
      }
   }


}
