/*++

   Copyright    (c)    1994-1998    Microsoft Corporation

   Module  Name :

        objplus.cpp

   Abstract:

        Base object classes

   Author:

        Ronald Meijer (ronaldm)

   Project:

        Internet Services Manager

   Revision History:

--*/



//
// Include Files
//
#include "stdafx.h"
#include "comprop.h"

#include <stdlib.h>
#include <memory.h>
#include <ctype.h>

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif



CObjHelper::CObjHelper()
/*++

Routine Description:

    Constructor for super object help class

Arguments:

    None

Return Value:

    N/A

--*/
    : m_ctor_err(ERROR_SUCCESS),
      m_api_err(ERROR_SUCCESS),
      m_fDirty(FALSE),
      m_time_created(::GetCurrentTime())
{
}



void
CObjHelper::ReportError(
    IN LONG errInConstruction
    )
/*++

Routine Description:

    Set the constructor error code, and dump the error message to
    the debugging context.

Arguments:

    LONG errInConstruction : Error code

Return Value:

    None

--*/
{
    TRACEEOLID("CObjectPlus construction failure, error = "
        << errInConstruction);

    m_ctor_err = errInConstruction;
}



LONG
CObjHelper::SetApiErr(
    IN LONG errApi
    )
/*++

Routine Description:

    Set the API error code.

Arguments:

    LONG errApi  : API error code

Return Value:

    The API error code

--*/
{
    return m_api_err = errApi;
}



BOOL
CObjHelper::IsValid() const
/*++

Routine Description:

    Determine if the object is in a valid state

Arguments:

    LONG errApi  : API error code

Return Value:

    TRUE if the the object is in a valid state, FALSE otherwise

--*/
{
    return QueryError() == 0;
}



DWORD
CObjHelper::QueryAge() const
/*++

Routine Description:

    Determine the age of the object.

Arguments:

    None

Return Value:

    time_t value indicating the age of the object.

--*/
{
    DWORD dwTime = ::GetCurrentTime(),
          dwDiff;

    if (dwTime < m_time_created)
    {
        dwDiff = dwTime + (((DWORD)-1) - (m_time_created - 1));
    }
    else
    {
        dwDiff = dwTime - m_time_created;
    }

    return dwDiff;
}



#ifdef _DEBUG



void
CObjHelper::AssertValid() const
/*++

Routine Description:

    Assert the object if the object is in a valid state

Arguments:

    None

Return Value:

    None

--*/
{
    ASSERT(IsValid());
}



#endif // _DEBUG



CObjectPlus::CObjectPlus()
/*++

Routine Description:

    Constructor of extended object

Arguments:

    None

Return Value:

    N/A

--*/
{
}



int
CObjectPlus::Compare(
    IN const CObjectPlus * pob
    ) const
/*++

Routine Description:

    Compare one object with another:  default implementation orders objects
    by creation time.  Return -1, 0 or 1.

Arguments:

    const CObjectPlus * pob : Object to be compared against

Return Value:

    -1 if this object is < than the compared object
     0 if this object is == to the compared object
    +1 if this object is > than the compared object

--*/
{
    return QueryCreationTime() < pob->QueryCreationTime()
        ? -1
        : QueryCreationTime() != pob->QueryCreationTime();
}



CObListPlus::CObListPlus(
    IN int nBlockSize
    )
/*++

Routine Description:

    Subclass of CObList whose default behavior is to destroy its
    contents during its own destruction

Arguments:

    int nBlockSize : Initial block size

Return Value:

    None

--*/
    : CObList(nBlockSize),
      m_fOwned(TRUE)
{
}



CObListPlus::~CObListPlus()
/*++

Routine Description:

    Destructor.  If the objects are owned, clean them up.

Arguments:

    N/A

Return Value:

    N/A

--*/
{
    RemoveAll();
}



void
CObListPlus::RemoveAll()
/*++

Routine Description:

    Remove all the objects in the list if the list owns its objects

Arguments:

    None

Return Value:

    None

--*/
{
    if (m_fOwned)
    {
        //
        // Remove and discard all the objects
        //
        while (!IsEmpty())
        {
            CObject * pob = RemoveHead();
            delete pob ;
        }
    }
    else
    {
        //
        // Just remove the object pointers
        //
        CObList::RemoveAll();
    }
}



CObject *
CObListPlus::Index(
    IN int index
    )
/*++

Routine Description:

    Get object by index

Arguments:

    int index  : The index of the object to be returned

Return Value:

    The object, or NULL if the index is invalid

--*/
{
   CObListIter obli(*this);

   CObject * pob = NULL;

   for (int i = 0; (pob = obli.Next()) && i++ < index; /**/ );

   return pob;
}



BOOL
CObListPlus::RemoveIndex(
    IN int index
    )
/*++

Routine Description:

    Remove object by index

Arguments:

    int index  : The index of the object to be removed

Return Value:

    The object, or NULL if the index is invalid

--*/
{
    int i;
    POSITION pos;
    CObListIter obli(*this);
    CObject * pob;

    for (i = 0, pos = obli.QueryPosition();
        (pob = obli.Next()) && i < index;
        i++, pos = obli.QueryPosition());

    if (pob && i == index)
    {
        RemoveAt(pos);

        return TRUE;
    }

    return FALSE;
}



BOOL
CObListPlus::Remove(
    IN CObject * pob
    )
/*++

Routine Description:

    Remove the first (and hopefully only) occurrence of an object
    pointer from this list.

Arguments:

    CObject * pob : The object to be removed

Return Value:

    TRUE if the object was found and succesfully removed, FALSE otherwise

--*/
{
    POSITION pos = Find(pob);

    if (pos == NULL)
    {
        return FALSE;
    }

    RemoveAt(pos);

    return TRUE;
}



void
CObListPlus::RemoveAt(
    IN POSITION & pos
    )
/*++

Routine Description:

    Override of RemoveAt to delete the pointer at the position
    given

Arguments:

    POSITION pos        : Position of item to delete

Return Value:

    None.

Notes:

    The item will only be deleted if this is an "owned" list.

--*/
{
    CObject * pItem = GetAt(pos);

    CObList::RemoveAt(pos);

    if (m_fOwned)
    {
        delete pItem;
    }
}



BOOL
CObListPlus::SetAll(
    IN BOOL fDirty
    )
/*++

Routine Description:

    Set all elements to dirty or clean.  Return TRUE if any element was dirty.

Arguments:

    BOOL fDirty : Dirty flag to set the objects with

Return Value:

    TRUE if any element was dirty.

--*/
{
    int cDirtyItems = 0;
    CObjectPlus * pob;
    CObListIter obli(*this);

    while (pob = (CObjectPlus *)obli.Next())
    {
        cDirtyItems += pob->IsDirty();
        pob->SetDirty(fDirty);
    }

    SetDirty(fDirty);

    return cDirtyItems > 0;
}



int
CObListPlus::FindElement(
    IN CObject * pobSought
    ) const
/*++

Routine Description:

    Find the object in the list.

Arguments:

    CObject * pobSought : Object to be looked for

Return Value:

    The index of the object, or -1 if it wasn't found.

--*/
{
    CObject * pob;
    CObListIter obli(*this);

    for (int i = 0;
        (pob = obli.Next()) && pob != pobSought;
        i++);

    return pob
        ? i
        : -1;
}


//
// Sorting structure
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

typedef struct
{
    CObjectPlus * pObj;                        // Pointer to object to be sorted
    CObjectPlus::PCOBJPLUS_ORDER_FUNC  pFunc;  // Pointer to ordering function
} CBOWNEDLIST_SORT_HELPER;



int _cdecl
CObListPlus::SortHelper(
    IN const void * pa,
    IN const void * pb
    )
/*++

Routine Description:

    This static member function is used to quick sort an array of structures
    as declared above.  Each element contains the object pointer and a
    pointer to the object's member function to be invoked for comparison.

Arguments:

    const void * pa      : Sorting help struct 1
    const void * pb      : Sorting help struct 2

Return Value:

    Sort return code

--*/
{
    CBOWNEDLIST_SORT_HELPER *pHelp1 = (CBOWNEDLIST_SORT_HELPER *)pa,
                            *pHelp2 = (CBOWNEDLIST_SORT_HELPER *)pb;

    return (pHelp1->pObj->*pHelp1->pFunc)(pHelp2->pObj);
}



/* INTRINSA suppress=null_pointers, uninitialized */
DWORD
CObListPlus::Sort(
    IN CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc
    )
/*++

Routine Description:

    Sort the list by recreating it entirely.

Arguments:

    CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc : Ordering function

Return Value:

    Error code

--*/
{
    DWORD err = ERROR_SUCCESS;
    int cItems = (int)GetCount();

    if (cItems < 2)
    {
        return err;
    }

    CObjectPlus * pObNext;
    CObListIter obli(*this);
    BOOL fOwned = SetOwnership(FALSE);
    int i;

    CBOWNEDLIST_SORT_HELPER * paSortHelpers = NULL;

    try
    {
        //
        // Allocate the helper array
        //
        paSortHelpers = AllocMemByType(cItems, CBOWNEDLIST_SORT_HELPER);

        //
        // Fill the helper array.
        //
        for (i = 0; pObNext = (CObjectPlus *)obli.Next(); i++)
        {
            paSortHelpers[i].pFunc = pOrderFunc;
            paSortHelpers[i].pObj = pObNext;
        }

        //
        // Release all object pointer references.  Note that we
        // forced "owned" to FALSE above.
        //
        RemoveAll();
        ASSERT(GetCount() == 0);

        //
        // Sort the helper array
        //
        ::qsort( (void *) paSortHelpers,
            cItems,
            sizeof(paSortHelpers[0]),
            SortHelper
            );

        //
        // Refill the list from the helper array.
        //
        for (i = 0; i < cItems; i++ )
        {
            AddTail(paSortHelpers[i].pObj);
        }

        ASSERT(GetCount() == cItems);
    }
    catch(CMemoryException * e)
    {
        err = ERROR_NOT_ENOUGH_MEMORY;
        e->Delete();
    }

    //
    // Delete the working array
    //
    FreeMem(paSortHelpers);

    //
    // Restore the object ownership state
    //
    SetOwnership(fOwned);

    return err;
}



CObListIter::CObListIter(
    IN const CObListPlus & obList
    )
/*++

Routine Description:

    Constructor of ObOwnedList iterator

Arguments:

    const CObListPlus & obList : List to be iterated

Return Value:

    N/A

--*/
    : m_obList(obList)
{
    Reset();
}



void
CObListIter::Reset()
/*++

Routine Description:

    Reset the iterator

Arguments:

    None

Return Value:

    None

--*/
{
    m_pos = m_obList.GetCount()
        ? m_obList.GetHeadPosition()
        : NULL;
}



CObject * CObListIter::Next()
/*++

Routine Description:

    Get the next object in the list, or NULL

Arguments:

    None

Return Value:

    The next object in the list, or NULL

--*/
{
    return m_pos == NULL
        ? NULL
        : m_obList.GetNext(m_pos);
}
