/*
* Copyright (c) 2000 - 2001 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include "nw_object_dynamici.h"
#include "nw_object_aggregatei.h"
#include "nwx_mem.h"
#include "BrsrStatusCodes.h"

/* ------------------------------------------------------------------------- */
NW_Bool
NW_Object_Base_IsEncapsulated (const NW_Object_Base_Class_t* objClass,
                               const NW_Object_Secondary_Class_t* secondaryClass)
{
  /* iterate through the class hierarchy */
  while (((NW_Object_Class_t*) objClass) != &NW_Object_Base_Class) {
    const void* const* secondaryList;

    /* get the interface list of the class */
    secondaryList = objClass->NW_Object_Base.secondaryList;
    if (secondaryList != NULL) {
      NW_Uint32 index;

      for (index = 0; secondaryList[index] != NULL; index++) {
        if (secondaryList[index] == secondaryClass) {
          return NW_TRUE;
        }
      }
    }

    /* the interface implementation was not found at this level of the class
       hierarchy, let's try the superclass */
    objClass = (const NW_Object_Base_Class_t*) objClass->NW_Object_Core.super;
  }

  return NW_FALSE;
}

/* ------------------------------------------------------------------------- *
   static data
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
const NW_Object_Dynamic_Class_t NW_Object_Dynamic_Class = {
  { /* NW_Object_Core    */
    /* super             */ &NW_Object_Base_Class,
    /* querySecondary    */ _NW_Object_Core_QuerySecondary
  },
  { /* NW_Object_Base    */
    /* interfaceList     */ NULL
  },
  { /* NW_Object_Dynamic */
    /* instanceSize      */ sizeof (NW_Object_Dynamic_t),
    /* construct         */ NULL,
    /* destruct          */ NULL
  }
};

/* ------------------------------------------------------------------------- *
   public/protected methods
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_Object_Dynamic_Initialize (NW_Object_Core_t* core,
                               va_list* argList)
{
  NW_TRY (status) {
    const NW_Object_Dynamic_Class_t* objClass;

    /* zero the object */
    objClass = (const NW_Object_Dynamic_Class_t*) core->objClass;
    (void) NW_Mem_memset (core, 0, objClass->NW_Object_Dynamic.instanceSize);
    core->objClass = objClass;

    /* call our superclass method */
    status = _NW_Object_Core_Initialize (core, argList);
    if (status != KBrsrSuccess) {
      NW_THROW (status);
    }

    /* call the class constructor on the newly allocated object */
    if (NW_Object_Dynamic_GetClassPart (core).construct != NULL) {
      status = NW_Object_Dynamic_Construct (core, argList);
      NW_THROW_ON_ERROR (status);
    }
  } NW_CATCH (status) {
  } NW_FINALLY {
    return status;
  } NW_END_TRY
}

/* ------------------------------------------------------------------------- */
void
_NW_Object_Dynamic_Terminate (NW_Object_Core_t* core)
{
  const NW_Object_Dynamic_Class_t* objClass;

  for (objClass = (const NW_Object_Dynamic_Class_t*) NW_Object_GetClass (core);
       objClass != &NW_Object_Dynamic_Class;
       objClass = (const NW_Object_Dynamic_Class_t*) objClass->NW_Object_Core.super) {
    /* invoke the Dynamic destruct method */
    if (objClass->NW_Object_Dynamic.destruct != NULL) {
      objClass->NW_Object_Dynamic.destruct ((NW_Object_Dynamic_t*) core);
    }

    /* does the class have secondaries? */
    if (objClass->NW_Object_Base.secondaryList != NULL) {
      size_t superOffset;
      NW_Uint32 index;

      superOffset =
        ((NW_Object_Dynamic_Class_t*) objClass->NW_Object_Core.super)->
          NW_Object_Dynamic.instanceSize;

      /* iterate through the secondary list in order to terminate immediate
         aggregates */
      for (index = 0;
           objClass->NW_Object_Base.secondaryList[index] != NULL;
           index++) {
        const NW_Object_Secondary_Class_t* secondaryClass;
        size_t secondaryOffset;
        NW_Object_Secondary_t* secondary;

        secondaryClass = (NW_Object_Secondary_Class_t*)
          objClass->NW_Object_Base.secondaryList[index];
        secondaryOffset = secondaryClass->NW_Object_Secondary.offset;
        secondary =
          (NW_Object_Secondary_t*) ((NW_Byte*) core + secondaryOffset);

        /* ignore tagged secondaries */
        if (*(void**) secondary == NULL) {
          continue;
        }

        /* ignore secondaries that are not aggregates, i.e. interfaces */
        if (!NW_Object_IsDerivedFrom (secondaryClass,
                                      &NW_Object_Aggregate_Class)) {
          /* tag the secondary such that we don't process it again */
          *(void**) secondary = NULL;
          continue;
        }

        /* traverse up the aggregate class hierarchy destroying all that are
           not referenced by our superclass secondary list */
        while (secondaryClass != (void*) &NW_Object_Aggregate_Class) {
          const NW_Object_Aggregate_Class_t* aggregateClass;

          if (secondaryOffset < superOffset && 
              NW_Object_Base_IsEncapsulated ((const NW_Object_Base_Class_t*) 
                    objClass->NW_Object_Core.super, secondaryClass)) {
            break;
          }

          aggregateClass = (NW_Object_Aggregate_Class_t*) secondaryClass;
          if (aggregateClass->NW_Object_Aggregate.destruct != NULL) {
            aggregateClass->NW_Object_Aggregate.
              destruct ((NW_Object_Aggregate_t*) secondary);
          }
          secondaryClass = (const NW_Object_Secondary_Class_t*) secondaryClass->NW_Object_Core.super;
        }

        /* if we reached the aggregate class, tag it as done */
        if (secondaryClass == (void*) &NW_Object_Aggregate_Class) {
          *(void**) secondary = NULL;
        }
      }
    }
  }
}
