import java.util.Vector;
import java.lang.System;

/**
 * A class representing the dependencies between Java Objects.
 * It implements the <b>ComponentConfigurator</b> interface.
 * @author  Fabio Kon
 * @version 0.1
 * @see     ComponentConfigurator
 * @see     HookSpecification
*/
public class SimpleConfigurator implements ComponentConfigurator {

/////////////////////////////////////////////////////////////////
// VARIABLES
/////////////////////////////////////////////////////////////////
/**
 * The Java object implementating this component.
 */
    protected Object implementation;
/**
 * A vector containing the hooks for this component.
 */
    protected Vector hookVector;
/**
 * A vector containing the clients for this component.
 */
    protected Vector clientVector;
/** 
 * The name of this component.
 */
    protected String name;
/** 
 * Information string about this component.
 */
    protected String info;

/////////////////////////////////////////////////////////////////
// METHODS    
/////////////////////////////////////////////////////////////////

 /**
  * Creates a new configurator for a given object.
  *
  * @param     implementation   the object implementation.
  * @see       java.lang.Object
  */
    public SimpleConfigurator (String name, Object implementation)
    {
        this.name = name;
        this.implementation = implementation;
        hookVector   = new Vector(10, 10);
        clientVector = new Vector(10, 10);
    }
    
/**
 * Deletes the references to all internal data structures.
 */
    public void destroyComponentConfigurator ()
    {
        // Let's give a little hand to the garbage collector:
	implementation = null;
        hookVector.removeAllElements(); 
        hookVector = null;
        clientVector.removeAllElements(); 
        clientVector = null;
        name = null;
        info = null;
    }

    //////////////////////////////////////////////////////////////////////
    // Returns the index of the first hook with the name provided.
    // Returns -1 if such element is not found.
    //////////////////////////////////////////////////////////////////////
    private int indexOf (String hookName)
    {
        int i, size = hookVector.size();
        
        for (i = 0; i < size; i++)
            if(hookName.equals(((HookSpecification)hookVector.elementAt(i)).hook))
                return i;

        return -1; // element not found.
    }
        
/**
 * Adds a hook to the configurator.
 * @param   hookName  the name of the hook to be added.
 * @exception ElementExists if the hook already exists.
 */
    public void addHook (String hookName) throws ElementExists
    {
        int i = indexOf (hookName);

        if (i != -1)
           throw new ElementExists(hookName); // This hook exists already.
        
        hookVector.addElement(new HookSpecification(hookName, null));
    }
    
/**
 * Deletes a hook from the configurator.
 * @param   hookName  the name of the hook to be deleted.
 * @exception NotFound if the hook is not found.
 */
    public void deleteHook (String hookName) throws NotFound
    {
        int i = indexOf (hookName);

        if (i == -1)
            throw new NotFound (hookName);
        else
            hookVector.removeElementAt (i);

    }
        
/**
 * Attaches a ComponentConfigurator to the given hook.
 * @param  hookName  the name of the hook.
 * @param  cc        the ComponentConfigurator to be attached to the hook.
 * @exception HookBusy if there is already a component attached to the hook.
 * @exception NotFound if the hook does not exist.
 */
    public void hook (String hookName, ComponentConfigurator cc) 
        throws HookBusy, NotFound
    {
        int i = indexOf (hookName);

        if (i == -1)
            throw new NotFound (hookName);

        if (((HookSpecification)hookVector.elementAt(i)).component!= null)
            throw new HookBusy (hookName);
        else
            ((HookSpecification)hookVector.elementAt(i)).component = cc;
    }
    

/**
 * Detaches a ComponentConfigurator from the given hook.
 * @param hookName  the name of the hook.
 * @param cc        the ComponentConfigurator to be detached.
 * @exception HookVacant if there are no components attached to the hook.
 * @exception NotFound if the hook does not exist.
 */
    public void unhook (String hookName)
        throws HookVacant, NotFound
    {
        int i = indexOf (hookName);

        if (i == -1)
            throw new NotFound (hookName);
        
        if (((HookSpecification)hookVector.elementAt(i)).component == null)
            throw new HookVacant (hookName);
        else
            ((HookSpecification)hookVector.elementAt(i)).component = null;
    }
    
/**
 * Adds a new component to the list of clients.
 * @param  client  the ComponentConfigurator representing the new client.
 * @param  hookNameInClient the name of the hook to which this component is attached.
 * @exception ElementExists if the given pair (client, hookNameInClient) is 
 *                          already present in the client list.
 * 
 */
    public void registerClient (ComponentConfigurator client, 
                               String hookNameInClient)
                               throws ElementExists
    {
        HookSpecification hs = new HookSpecification (hookNameInClient, client);

        if (clientVector.contains (hs))
            throw new ElementExists ();
        else
            clientVector.addElement (hs);
    }
    
/**
 * Removes a pair (client, hook) from the list of clients.
 * @param  client  the ComponentConfigurator representing the new client.
 * @param  hookNameInClient the name of the hook to which this component is attached.
 * @exception NotFound if the given pair (client, hookNameInClient) is not 
 *                     present in the client list.
 * 
 */
    public void unregisterClient (ComponentConfigurator client, 
                                  String hookNameInClient)
        throws NotFound
    
    {
        int i;
        
        HookSpecification hs = new HookSpecification (hookNameInClient, client);

        if (clientVector.removeElement (hs) == false)
             throw new NotFound ();
    }
    
/**
 * This implementation simply prints the event to the standard output.
 * @param  hookedComponent the ComponentConfigurator that generated the event.
 * @param  e               the event that was generated. 
 */
    public void eventOnHookedComponent (ComponentConfigurator hookedComponent,
                                        ComponentEvent e)
    {
        System.out.println("Component " + name + 
                           "received the following event from hooked component " +
                           hookedComponent.name ()+ ": " + e.toString ());
    }
    
/**
 * This implementation simply prints the event to the standard output.
 * @param  client  the ComponentConfigurator that generated the event.
 * @param  e       the event that was generated. 
 */
    public void eventOnClient (ComponentConfigurator client,
                              ComponentEvent e)
    {
        System.out.println("Component " + name + 
                           "received the following event from client " +
                           client.name () + ": " + e.toString ());
    }
    
    
/**
 * Accessor for the component name.
 * @return a string containing the component name. 
 */
    public String name () 
    {
        return name;
    }
    
/**
 * Accessor for the component information string.
 * @return a string containing component information.
 */
    public String info ()
    {
        return info;
    }
    
/**
 * Provides a list of the hooks in this component.
 * @returns a vector of HookSpecifications.
 * @see HookSpecifications
 * @see java.util.Vector 
 */
    public Vector listHooks ()
    {
        return hookVector;
    }
/**
 * Provides a list of the clients of this component.
 * @returns a vector of HookSpecifications.
 * @see HookSpecifications
 * @see java.util.Vector 
 */
    public Vector listClients ()
    {
        return clientVector;
    }
    
    
/**
 * Sets the name of this component.
 */
    public void name (String s)
    {
        name = s;
    }
    
/**
 * Sets the information string for this component.
 */
    public void info (String s)
    {
        info = s;
    }
        
/**
 * Accessor for getting the component implementation.
 * @return the object implementation.
 */
    public Object implementation ()
    {
        return implementation;
    }

/**
 * Accessor for setting the component implementation.
 */
    public void implementation (Object implementation)
    {
        this.implementation = implementation;
    }
    
};

