/******************************************************************************
*                                                                             *
*  File: SimpleConfigurator.cpp                                               *
*                                                                             *
*  Description: A concrete class that reifies dependencies between components.*
*                                                                             *
*  Project: 2K - Automatic Configuration                                      *
*  Author: Fabio Kon (f-kon@cs.uiuc.edu)                                      *
*                                                                             *
*******************************************************************************

   Revision Control Information

   $Revision: $

   $Log: $
******************************************************************************/

#include "SimpleConfigurator.h"

/* Creates a new configurator for a given object.
 *
 * @param     name             the component name.
 * @param     implementation   the object implementation.
 */
SimpleConfigurator::SimpleConfigurator (const char *name, 
                                        Object *implementation)
{
  if (name)
    name_ = ACE_OS::strdup(name);
  else
    name_ = 0;
  implementation_ = implementation;
}

/* Deletes the references to all internal data structures. */
void SimpleConfigurator::destroyComponentConfigurator ()
{
  implementation_ = 0;

  if (name_)
    ACE_OS::free (name_);   
  if (info_)
    ACE_OS::free (info_);   

  info_ = name_ = 0;
}

/* Adds a hook to the configurator. Returns -1 if the hook already exists or 
 * cannot be created. Returns 0 if successful.
 * @param   hookName  the name of the hook to be added.
 */
int SimpleConfigurator::addHook (const char *hookName)
{
  if (hookName == 0)
    return -1;
  
  HookSpecification *hs = findHook (hookName);
    
  if (hs != 0)
    return -1;// This hook already exists.

  hookList_.insert_tail (new HookSpecification(hookName));
  return 0;
}// addHook ()


/* Deletes a hook from the configurator. Returns -1 in case of failure, 0 o/w.
 * @param   hookName  the name of the hook to be deleted.
 */
int SimpleConfigurator::deleteHook (const char *hookName)
{
  HookSpecification *hs = findHook (hookName);
    
  if (hs == 0)
    return -1; // The hook does not exist.
  else
    return hookList_.remove (hs);
}

/* Attaches a ComponentConfigurator to the given hook. Note that one can only 
 * attach a component to a hook that is vacant.
 * @param  hookName  the name of the hook.
 * @param  cc        the ComponentConfigurator to be attached to the hook.
 */
int SimpleConfigurator::hook (const char *hookName, 
                              ComponentConfigurator *cc) 
{
  HookSpecification *hs = findHook (hookName);
    
  if (hs == 0)
    return -1; // The hook does not exist.
    
  if (hs->componentConfig () != 0)
    return -1; // The hook is not vacant.
  else
    {
      hs->componentConfig(cc);
      return 0;
    }
}// hook ()


/* Detaches a ComponentConfigurator from the given hook.
 * @param hookName  the name of the hook.
 * @param cc        the ComponentConfigurator to be detached.
 */
int SimpleConfigurator::unhook (const char *hookName)
{
  HookSpecification *hs = findHook (hookName);
  if (hs == 0)
    return -1; // The hook does not exist.
    
  if (hs->componentConfig () == 0)
    return -1; // The hook is vacant.
  else
    {
      hs->componentConfig(0);
      return 0;
    }
}// unhook ()


/* Adds a new component to the list of clients. 
 * Returns 0 if successful, -1 if this element is already registered.
 * @param  client  the ComponentConfigurator representing the new client.
 * @param  hookNameInClient the name of the hook to which
 *          this component is attached.
 */
int SimpleConfigurator::registerClient (ComponentConfigurator *client, 
                                        const char *hookNameInClient)
{
  if (findClientHook(client, hookNameInClient))
    return -1; // This element is already there.
  
  clientList_.insert_tail (new HookSpecification (hookNameInClient, client));
  return 0;
  
}// registerClient ()


/* 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.
 */
int SimpleConfigurator::unregisterClient (ComponentConfigurator *client, 
                                          const char *hookNameInClient)
{
  HookSpecification *hs;
  
  if ((hs = findClientHook(client, hookNameInClient)) == 0)
    return -1; // This element is not there.
  
  return clientList_.remove (hs);
  
}// unregisterClient ()


/* 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. 
 */
void 
SimpleConfigurator::eventOnHookedComponent (const ComponentConfigurator *hookedComponent,
                                            const ComponentEvent *e)
{
  printf ("Component %s "
          "received the following event from hooked component %s:\n\t\t%s\n",
          name (), 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. 
 */
void SimpleConfigurator::eventOnClient (const ComponentConfigurator *client,
                                        const ComponentEvent *e)
{
  printf("Component %s "
         "received the following event from client %s:\n\t\t %s\n",
         name (), client->name (), e->toString ());
}


/* Accessor for the component name.
 * @return a pointer to a string containing the component name. 
 */
const char *SimpleConfigurator::name () const
{
  if (name_)
    return name_;
  else 
    return "";
}

/* Accessor for the component information string.
 * @return a string containing component information.
 */
const char *SimpleConfigurator::info () const
{
  if (info_)
    return info_;
  else
    return "";
}

/*
 * Provides a list of the hooks in this component.
 * @returns a vector of HookSpecifications.
 */
const HookList *SimpleConfigurator::listHooks ()
{
  return &hookList_;
}

/*
 * Provides a list of the clients of this component.
 * @returns a vector of HookSpecifications.
 */
const HookList *SimpleConfigurator::listClients ()
{
  return &clientList_;
}


/* Sets the name of this component.  */
void SimpleConfigurator::name (const char *s)
{
  if(name_ != 0)
    ACE_OS::free(name_);
  if (s)
    name_ = ACE_OS::strdup(s);
  else
    name_ = 0;
}

/* Sets the information string for this component. */
void SimpleConfigurator::info (const char *s)
{
  if(info_ != 0)
    ACE_OS::free(info_);
  if (s)
    info_ = ACE_OS::strdup(s);
  else
    info_ = 0;
}

/*
 * Accessor for getting the component implementation.
 * @return the object implementation.
 */
Object *SimpleConfigurator::implementation ()
{
  return implementation_;
}

/* Accessor for setting the component implementation. */
void SimpleConfigurator::implementation (Object *implementation)
{
  implementation_ = implementation;
}

//////////////////////////////////////////////////////////////////////
// Returns a reference to the first hook with the name provided.
// Returns 0 if such element is not found.
//////////////////////////////////////////////////////////////////////
HookSpecification *
SimpleConfigurator::findHook (const char *hookName)
{
  if (hookName == 0)
    return 0;
  
  HookSpecIterator hi(hookList_);
    
  for (HookSpecification *hs = hi.next ();
       hs != 0;
       hi.advance (), hs = hi.next ())
    {
      if (ACE_OS::strcmp(hookName, hs->name ()) == 0)
        {
          return hs;
        }
    }

  return 0; // element not found.

}// findHook ()



////////////////////////////////////////////////////////////////////// 
// Returns a reference to the first client hook with the
// ComponentConfigurator and name provided.  
// Returns 0 if such element is not found.
//////////////////////////////////////////////////////////////////////
HookSpecification *
SimpleConfigurator::findClientHook (const ComponentConfigurator *client, 
                                    const char *hookNameInClient)
{
  HookSpecIterator hi(clientList_);
  
  for (HookSpecification *hs = hi.next ();
       hs != 0;
       hi.advance (), hs = hi.next ())
    {
      if (client == hs->componentConfig () &&
            (hookNameInClient == 0 ||
             ACE_OS::strcmp(hookNameInClient, hs->name ()) == 0
            )
         )
        {
          return hs;
        }
    }
  
  return 0; // element not found.
  
}// findClientHook ()

