//  Copyright (c) 2001, Reson, Inc. All Rights Reserved.
//
//  Filename:   ChannelSequencer.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    
//
//  Notes:      
//

#include "StdAfx.h"
#include "ChannelSequencer.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CChannelSequencer class implementation.

CChannelSequencer::CChannelSequencer( void )
                  :CBufferedData<CHANNELITEM>()
{
}

CChannelSequencer::~CChannelSequencer( void )
{
}

CChannelSequencer::CChannelSequencer( const CChannelSequencer &rRhs )               // Not implemented.
                  :CBufferedData<CHANNELITEM>()
{
    UNREFERENCED_PARAMETER( rRhs );
    ASSERT( false );
}

CChannelSequencer & CChannelSequencer::operator = ( const CChannelSequencer &rRhs ) // Not implemented.
{
    UNREFERENCED_PARAMETER( rRhs );
    ASSERT( false );
    return *this;
}

bool CChannelSequencer::IsPingComplete( const unsigned long &rulPingNumber ) const
{
    // Search the linked list for both channels of the given ping number and if present,
    // returns true, otherwise false.

    bool    bPingComplete = false;

    int     iPortIndex = m_iInvalidIndex,
            iStbdIndex = m_iInvalidIndex;

    if ( IndexFromPingNumber( rulPingNumber, iPortIndex, iStbdIndex ) )
    {
        bPingComplete = ( ( iPortIndex != m_iInvalidIndex ) && ( iStbdIndex != m_iInvalidIndex ) );
    }

    return bPingComplete;
}

bool CChannelSequencer::GetAccumulatedPingChannels( const unsigned long    &rulPingNumber,
                                                    unsigned long          &rulTimestamp,
                                                    CDynamicBuffer<BYTE>  *&rpPort,
                                                    CDynamicBuffer<BYTE>  *&rpStbd )
{
    // Search and extract the indexes of the two channels pertaining to the given ping
    // numbers. Once found, extract pointers to the buffered channel data and return true,
    // otherwise return false.
    
    bool bSuccess = false;      // Assume failure for now.

    try
    {
        int iPortIndex,
            iStbdIndex;

        rulTimestamp = 0UL;
        rpPort       = NULL;
        rpStbd       = NULL;

        if ( ! IndexFromPingNumber( rulPingNumber, iPortIndex, iStbdIndex ) )
        {
            ThrowMessage_m( "Can't locate complete channels of accumulated ping" )
        }

        ASSERT( iPortIndex != m_iInvalidIndex );
        ASSERT( iStbdIndex != m_iInvalidIndex );

        if ( iPortIndex == m_iInvalidIndex )
        {
            ThrowMessage_m( "Port index is invalid" );
        }

        if ( iStbdIndex == m_iInvalidIndex )
        {
            ThrowMessage_m( "Stbd index is invalid" );
        }

        CHANNELITEM *psPortChannelItem = NULL;
        CHANNELITEM *psStbdChannelItem = NULL;

        if ( ! Get( iPortIndex, psPortChannelItem, rpPort ) )
        {
            ThrowMessage_m( "Can't extract port channel" )
        }

        if ( ! Get( iStbdIndex, psStbdChannelItem, rpStbd ) )
        {
            ThrowMessage_m( "Can't extract starboard channel" )
        }

        rulTimestamp = min( psPortChannelItem->m_ulTimeStamp, psStbdChannelItem->m_ulTimeStamp );
            
        bSuccess = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CChannelSequencer::GetAccumulatedPingChannels(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CChannelSequencer::GetAccumulatedPingChannels(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}

bool CChannelSequencer::RemovePingChannels( const unsigned long &rulPingNumber )
{
    bool bSuccess = false;      // Assume failure for now.

    int iPortIndex,
        iStbdIndex;

    if ( IndexFromPingNumber( rulPingNumber, iPortIndex, iStbdIndex ) )
    {
        ASSERT( iPortIndex != m_iInvalidIndex );
        ASSERT( iStbdIndex != m_iInvalidIndex );

        if ( iPortIndex != m_iInvalidIndex )
        {
            Remove( iPortIndex );
        }

        if ( iStbdIndex != m_iInvalidIndex )
        {
            Remove( iStbdIndex );
        }

        bSuccess = true;
    }

    return bSuccess;
}

///////////////////////////////////////////////////////////////////////////////
// Private service.

inline
bool CChannelSequencer::IndexFromPingNumber(    const unsigned long &rulPingNumber,
                                                int                 &riPortChannelIndex,
                                                int                 &riStbdChannelIndex ) const
{
    riPortChannelIndex = m_iInvalidIndex;
    riStbdChannelIndex = m_iInvalidIndex;

    for ( ConstItemListIterator_t pItem = m_ItemList.begin(); pItem != m_ItemList.end(); pItem++ )
    {
        if ( ( pItem->IsValid() ) && ( pItem->m_ulPingNumber == rulPingNumber ) )
        {
            switch ( pItem->m_ulChannel )
            {
                case 0:

                    riPortChannelIndex = pItem->m_iIndex;
                    break;

                case 1:

                    riStbdChannelIndex = pItem->m_iIndex;
                    break;

                default:

                    TRACE( _T( "CChannelSequencer::IndexFromPingNumber(), Invalid channel number detected." ) );
                    break;
            }
        }

        if ( ( riPortChannelIndex != m_iInvalidIndex ) && ( riStbdChannelIndex != m_iInvalidIndex ) )
        {
            break;
        }
    }

    return ( ( riPortChannelIndex != m_iInvalidIndex ) || ( riStbdChannelIndex != m_iInvalidIndex ) );
}
