/*
**  Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
**
**  File:	CollisionQueue.cpp
**
**  Author: 
**
**  Description:
**
**  History:
*/
#include    "pch.h"

CollisionQueue::CollisionQueue(void)
:
    m_nCollisions(0),
    m_maxCollisions(c_maxHitTests * 20),  //? best guess
    m_fDelete(true)
{
    m_pCollisions = new CollisionEntry [m_maxCollisions];
    assert (m_pCollisions);
}

CollisionQueue::CollisionQueue(int              maxCollisions,
                               CollisionEntry*  pCollisions)
:
    m_nCollisions(0),
    m_pCollisions(pCollisions),
    m_maxCollisions(maxCollisions),
    m_fDelete(false)
{
}

CollisionQueue::~CollisionQueue(void)
{
    if (m_fDelete)
        delete [] m_pCollisions;
}

void    CollisionQueue::sort(int    start)
{
    if ((m_nCollisions - 1) > start)
    {
        if (start == 0)
        {
            CollisionEntry::longSort(m_pCollisions,
                                     &m_pCollisions[m_nCollisions - 1]);
        }
        else
        {
            CollisionEntry::shortSort(&m_pCollisions[start],
                                      &m_pCollisions[m_nCollisions - 1]);
        }
    }
}

void    CollisionQueue::flush(int       n,
                              HitTest*  pHitTest1,
                              HitTest*  pHitTest2)
{
    assert (n > 0);
    assert (n <= m_nCollisions);

    //Cheat and temporarily mark pHitTest1 & 2 as dead
    bool    oldDead1;
    if (pHitTest1)
    {
        oldDead1 = pHitTest1->GetDeadF();
        pHitTest1->AddRef();
        pHitTest1->SetDeadF(true);
    }

    bool    oldDead2;
    if (pHitTest2)
    {
        oldDead2 = pHitTest2->GetDeadF();
        pHitTest2->AddRef();
        pHitTest2->SetDeadF(true);
    }

    float   t = m_pCollisions[n - 1].m_tCollision;
    int dest = n;
    for (int source = n; (source < m_nCollisions); source++)
    {
        CollisionEntry* pentrySource = &m_pCollisions[source];

        if (pentrySource->m_pHitTest1->GetDeadF() || pentrySource->m_pHitTest2->GetDeadF())
        {
            pentrySource->m_pHitTest1->Release();
            pentrySource->m_pHitTest2->Release();

            pentrySource->m_pHitTest1 = NULL;   //NYI shouldn't be needed
            pentrySource->m_pHitTest2 = NULL;
        }
        else
        {
            CollisionEntry* pentryDest = &m_pCollisions[dest++];

            pentryDest->m_pHitTest1  = pentrySource->m_pHitTest1;
            pentryDest->m_pHitTest2  = pentrySource->m_pHitTest2;

            pentryDest->m_hts1 = pentrySource->m_hts1;
            pentryDest->m_hts2 = pentrySource->m_hts2;

            pentryDest->m_tCollision = pentrySource->m_tCollision - t;
        }
    }

    if (pHitTest2)
    {
        pHitTest2->SetDeadF(oldDead2);
        pHitTest2->Release();
    }

    if (pHitTest1)
    {
        pHitTest1->SetDeadF(oldDead1);
        pHitTest1->Release();
    }

    m_nCollisions = dest;
}

void    CollisionQueue::purge(void)
{
    int i = m_nCollisions;
    while (--i >= 0)
    {
        CollisionEntry* pentry = &m_pCollisions[i];

        pentry->m_pHitTest1->Release();
        pentry->m_pHitTest2->Release();
    }

    m_nCollisions = 0;
}

void    CollisionQueue::addCollision(float          tCollision,
                                     HitTest*       pHitTest1,
                                     HitTestShape   hts1,
                                     HitTest*       pHitTest2,
                                     HitTestShape   hts2)
{
    assert (hts1 <= pHitTest1->GetTrueShape());
    assert (hts2 <= pHitTest2->GetTrueShape());

    assert (m_nCollisions <= m_maxCollisions);
    if (m_nCollisions == m_maxCollisions)
    {
        m_maxCollisions = (m_maxCollisions << 1);
        debugf("Extending collision queue from %d to %d entries\n", m_nCollisions, m_maxCollisions);

        CollisionEntry* p = new CollisionEntry[m_maxCollisions];
        assert (p);
        
        for (int i = 0; (i < m_nCollisions); i++)
        {
            p[i] = m_pCollisions[i];
        }

        delete [] m_pCollisions;
        m_pCollisions = p;
    }

    assert (m_nCollisions < m_maxCollisions);

    assert (pHitTest1);
    assert (pHitTest2);

    pHitTest1->AddRef();
    pHitTest2->AddRef();

    CollisionEntry* pentry = &m_pCollisions[m_nCollisions++];

    pentry->m_tCollision = tCollision;

    pentry->m_pHitTest1 = pHitTest1;
    pentry->m_hts1 = hts1;
    pentry->m_pHitTest2 = pHitTest2;
    pentry->m_hts2 = hts2;
}