/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/**
 * @file pvaenodeutility.cpp
 * Utility class to perform node operations
 */

#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif
#ifndef OSCL_VECTOR_H_INCLUDED
#include "oscl_vector.h"
#endif
#ifndef PVLOGGER_H_INCLUDED
#include "pvlogger.h"
#endif
#ifndef PVAE_NODE_UTILITY_H_INCLUDED
#include "pvaenodeutility.h"
#endif
#ifndef PVAE_TUNEABLES_H_INCLUDED
#include "pvae_tuneables.h"
#endif

////////////////////////////////////////////////////////////////////////////
PVAuthorEngineNodeUtility::PVAuthorEngineNodeUtility() :
        OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVAuthorEngineNodeUtility"),
        iObserver(NULL),
        iCmdQueue(PVAE_CMD_VECTOR_RESERVE)
{
    iLogger = PVLogger::GetLoggerObject("PVAuthorEngineNodeUtility");
    AddToScheduler();
}

////////////////////////////////////////////////////////////////////////////
PVAuthorEngineNodeUtility::~PVAuthorEngineNodeUtility()
{
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Connect(PVAENodeContainer* aMasterNode, int32 aTag1,
        PVAENodeContainer* aSlaveNode, int32 aTag2,
        const PvmfMimeString& aMimeString,
        OsclAny* aContext)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::Connect: &aMasterNode=0x%x, aTag1=%d, &aSlaveNode=0x%x, aTag2=%d",
                     &aMasterNode, aTag1, &aSlaveNode, aTag2));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.ConstructConnect(aMasterNode, aTag1, aSlaveNode, aTag2, aMimeString, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Connect: Error - cmd.ConstructConnect failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Disconnect(PVAENodeContainer* aNodeContainer, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Disconnect: &aNodeContainer=0x%x, aContext=0x%x",
                     &aNodeContainer, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.ConstructDisconnect(aNodeContainer, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Disconnect: Error - cmd.ConstructDisconnect failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::QueryUUID(PVAENodeContainer* aNodeContainer,
        const PvmfMimeString& aMimeType,
        Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
        bool aExactUuidsOnly,
        OsclAny* aContext)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::QueryUUID: &aNodeContainer=0x%x, aMimeType=%s, &aUuids=0x%x, aExactUuidsOnly=%d, aContext=0x%x",
                     &aNodeContainer, aMimeType.get_cstr(), &aUuids, aExactUuidsOnly, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.ConstructQueryUUID(aNodeContainer, aMimeType, aUuids, aExactUuidsOnly, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::QueryUUID: Error - cmd.ConstructQueryUUID failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::QueryInterface(PVAENodeContainer* aNodeContainer,
        const PVUuid& aUuid,
        PVInterface*& aInterfacePtr,
        OsclAny* aContext)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::QueryInterface: &aNodeContainer=0x%x, &aUuid=0x%x, aContext=0x%x",
                     &aNodeContainer, &aUuid, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.ConstructQueryInterface(aNodeContainer, aUuid, aInterfacePtr, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::QueryInterface: Error - cmd.ConstructQueryInterface failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Init(const PVAENodeContainer* aNode, OsclAny* aContext)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::Init: aNode=0x%x, aContext=0x%x", aNode, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.ConstructInit((PVAENodeContainer*)aNode, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Init: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Init(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Init: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));


    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_INIT, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Init: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Prepare(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Prepare: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_PREPARE, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Prepare: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}


////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Start(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Start: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_START, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Start: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Stop(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Stop: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_STOP, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Stop: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Pause(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Pause: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_PAUSE, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Pause: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Flush(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Flush: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_FLUSH, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Flush: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::Reset(const PVAENodeContainerVector& aNodes, OsclAny* aContext)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::Reset: &aNodes=0x%x, aContext=0x%x", &aNodes, aContext));

    PVAENodeUtilCmd cmd;
    PVMFStatus status = cmd.Construct(PVAENU_CMD_RESET, aNodes, aContext);
    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Reset: Error - cmd.Construct failed. status=%d", status));
        return status;
    }

    return AddCmdToQueue(cmd);
}

////////////////////////////////////////////////////////////////////////////
uint32 PVAuthorEngineNodeUtility::GetCommandQueueSize()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::GetCommandQueueSize: size=%d", iCmdQueue.size()));
    return iCmdQueue.size();
}

////////////////////////////////////////////////////////////////////////////
void PVAuthorEngineNodeUtility::NodeCommandCompleted(const PVMFCmdResp& aResponse)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::NodeCommandCompleted"));

    if (iCmdQueue.empty())
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::NodeCommandCompleted: Error - Empty command queue"));
        PVMFAsyncEvent event(PVMFErrorEvent, PVMFFailure, NULL, NULL);
        iObserver->NodeUtilErrorEvent(event);
        return;
    }

    PVAENodeUtilCmd cmd = iCmdQueue[0];
    if (aResponse.GetCmdStatus() != PVMFSuccess)
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
                        (0, "PVAuthorEngineNodeUtility::NodeCommandCompleted: Command failed - context=0x%x, status=0x%x",
                         aResponse.GetContext(), aResponse.GetCmdStatus()));
        CompleteUtilityCmd(cmd, aResponse.GetCmdStatus());
        return;
    }

    PVMFStatus status = PVMFSuccess;
    switch (cmd.iType)
    {
        case PVAENU_CMD_CONNECT:
            status = CompleteConnect(cmd, aResponse);
            break;
        case PVAENU_CMD_DISCONNECT:
            status = DoDisconnect(cmd);
            break;
        case PVAENU_CMD_QUERY_UUID:
            status = PVMFSuccess;
            break;
        case PVAENU_CMD_QUERY_INTERFACE:
            status = CompleteQueryInterface(cmd);
            break;
        case PVAENU_CMD_INIT:
            status = CompleteStateTransition(cmd, EPVMFNodeInitialized);
            break;
        case PVAENU_CMD_PREPARE:
            status = CompleteStateTransition(cmd, EPVMFNodePrepared);
            break;
        case PVAENU_CMD_START:
            status = CompleteStateTransition(cmd, EPVMFNodeStarted);
            break;
        case PVAENU_CMD_PAUSE:
            status = CompleteStateTransition(cmd, EPVMFNodePaused);
            break;
        case PVAENU_CMD_STOP:
        case PVAENU_CMD_FLUSH:
            status = CompleteStateTransition(cmd, EPVMFNodePrepared);
            break;
        case PVAENU_CMD_RESET:
            status = CompleteStateTransition(cmd, EPVMFNodeIdle);
            break;
        default:
            status = PVMFFailure;
            break;
    }

    if (status != PVMFPending)
        CompleteUtilityCmd(cmd, status);
}

////////////////////////////////////////////////////////////////////////////
void PVAuthorEngineNodeUtility::Run()
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::Run: Enter"));

    if (iCmdQueue.empty())
        return;

    PVAENodeUtilCmd cmd = iCmdQueue[0];
    if (cmd.iNodes.empty())
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::Run: Error - cmd.iNodes is empty"));
        CompleteUtilityCmd(cmd, PVMFFailure);
        return;
    }

    PVMFStatus status = PVMFFailure;
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::Run: cmd.iType=%d", cmd.iType));
    switch (cmd.iType)
    {
        case PVAENU_CMD_CONNECT:
            status = DoConnect(cmd);
            break;
        case PVAENU_CMD_DISCONNECT:
            status = DoDisconnect(cmd);
            break;
        case PVAENU_CMD_QUERY_UUID:
            status = DoQueryUuid(cmd);
            break;
        case PVAENU_CMD_QUERY_INTERFACE:
            status = DoQueryInterface(cmd);
            break;
        case PVAENU_CMD_INIT:
            status = DoInit(cmd);
            break;
        case PVAENU_CMD_PREPARE:
            status = DoPrepare(cmd);
            break;
        case PVAENU_CMD_START:
            status = DoStart(cmd);
            break;
        case PVAENU_CMD_PAUSE:
            status = DoPause(cmd);
            break;
        case PVAENU_CMD_STOP:
            status = DoStop(cmd);
            break;
        case PVAENU_CMD_FLUSH:
            status = DoFlush(cmd);
            break;
        case PVAENU_CMD_RESET:
            status = DoReset(cmd);
            break;
        default:
            status = PVMFFailure;
            break;
    }

    if (status != PVMFPending)
        CompleteUtilityCmd(cmd, status);

    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::Run: Exit"));
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::AddCmdToQueue(PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::AddCmdToQueue"));

    int32 err = 0;
    OSCL_TRY(err, iCmdQueue.push_back(aCmd););
    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::AddCmdToQueue: Error - iCmdQueue.push_back() failed"));
                         return PVMFErrNoMemory;
                        );

    if (iCmdQueue.size() == 1)
    {
        // Call RunIfNotReady() only if there are no other commands
        // in the queue. Otherwise, wait for the previous one(s)
        // to complete. RunIfNotReady() will be called in
        // CompleteUtilityCmd()
        RunIfNotReady();
    }

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
void PVAuthorEngineNodeUtility::CompleteUtilityCmd(const PVAENodeUtilCmd& aCmd, PVMFStatus aStatus)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: aCmd.iType=%d,  aStatus=0x%x", aCmd.iType, aStatus));

    if (!iObserver)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Observer not set"));
        OSCL_LEAVE(OsclErrGeneral);
        // return;  This statement was removed to avoid compiler warning for Unreachable Code
    }

    if (iCmdQueue.empty() || aCmd.iType != iCmdQueue[0].iType)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Empty command queue or mismatched command"));
        PVMFAsyncEvent event(PVMFErrorEvent, PVMFFailure, NULL, NULL);
        iObserver->NodeUtilErrorEvent(event);
        return;
    }

    // Remove command from queue
    iCmdQueue.erase(iCmdQueue.begin());

    // Callback to engine
    PVMFCmdResp resp(0, aCmd.iContext, aStatus);
    iObserver->NodeUtilCommandCompleted(resp);

    // Run next command when needed
    if (!iCmdQueue.empty())
        RunIfNotReady();
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoConnect(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoConnect"));
    int32 err = 0;
    OSCL_TRY(err,
             int32 tag1 = 0;
             int32 tag2 = 0;
             OSCL_HeapString<OsclMemAllocator> mimeType;
             PVMFStatus status = ((PVAENodeUtilCmd)aCmd).ParseConnect(tag1, tag2, mimeType);
             if (status != PVMFSuccess)
{
    LOG_ERR((0, "PVAuthorEngineNodeUtility::DoConnect: Error - cmd.ParseConnect failed. status=%d", status));
        return status;
    }

    if (mimeType.get_size() > 0)
{
    // Request a port from the master node
    aCmd.iNodes[0]->iNode->RequestPort(aCmd.iNodes[0]->iSessionId, tag1,
                                           &mimeType, (OsclAny*)aCmd.iNodes[0]);
    }
    else
    {
        // Request a port from the master node
        aCmd.iNodes[0]->iNode->RequestPort(aCmd.iNodes[0]->iSessionId, tag1,
                                           NULL, (OsclAny*)aCmd.iNodes[0]);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoConnect: Error - RequestPort failed. node=0x%x",
                                  aCmd.iNodes[0]->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}


// This is a work-around function to eliminate the compiler warning on certain platforms:
// "Variable might be clobbered by 'longjmp' or vfork'
static int32 requestport(PVMFNodeInterface* n, int32 id, int32 t2, OSCL_String& mt, OsclAny* p)
{
    int32 err;
    OSCL_TRY(err,
             if (mt.get_size() > 0)
{
    n->RequestPort(id, t2, &mt, p);
    }
    else
    {
        n->RequestPort(id, t2, NULL, p);
    }
            );
    return err;
}


////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::CompleteConnect(const PVAENodeUtilCmd& aCmd, const PVMFCmdResp& aResponse)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteConnect"));

    PVAENodeContainer* nodeContainer = OSCL_REINTERPRET_CAST(PVAENodeContainer*, aResponse.GetContext());
    PVMFPortInterface* port = OSCL_REINTERPRET_CAST(PVMFPortInterface*, aResponse.GetEventData());
    if (!port || !nodeContainer)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - Invalid port or node container"));
        return PVMFFailure;
    }

    int32 tag1 = 0;
    int32 tag2 = 0;
    OSCL_HeapString<OsclMemAllocator> mimeType;
    PVMFStatus status = ((PVAENodeUtilCmd)aCmd).ParseConnect(tag1, tag2, mimeType);

    if (status != PVMFSuccess)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - cmd.ParseConnect failed. status=%d", status));
        return status;
    }

    int32 err = 0;
    // Add port to port vector of node container
    switch (tag1)
    {
        case PVAE_NODE_INPUT_PORT_TAG:
            nodeContainer->iInputPorts.push_back(port);
            break;
        case PVAE_NODE_OUTPUT_PORT_TAG:
            nodeContainer->iOutputPorts.push_back(port);
            break;
        default:
            LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - Unsupported port tag"));
            OSCL_LEAVE(OsclErrNotSupported);
            break;
    }

    if (nodeContainer == aCmd.iNodes[0])
    {
        err = requestport(aCmd.iNodes[1]->iNode, aCmd.iNodes[1]->iSessionId, tag2, mimeType, (OsclAny*)aCmd.iNodes[1]);

        OSCL_FIRST_CATCH_ANY(err,
                             LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - RequestPort failed. node=0x%x",
                                      aCmd.iNodes[1]->iNode));
                             return PVMFFailure;
                            );

        status = PVMFPending;
    }
    else if (nodeContainer == aCmd.iNodes[1])
    {
        // Connect the ports
        PVMFPortInterface* masterPort = NULL;
        switch (tag1)
        {
            case PVAE_NODE_INPUT_PORT_TAG:
                masterPort = aCmd.iNodes[0]->iInputPorts.back();
                break;
            case PVAE_NODE_OUTPUT_PORT_TAG:
                masterPort = aCmd.iNodes[0]->iOutputPorts.back();
                break;
            default:
                LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - Unsupported port tag"));
                return PVMFErrNotSupported;
        }

        if (!masterPort)
        {
            LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - Master port unavailable"));
            return PVMFFailure;
        }
        status = masterPort->Connect(port);
    }
    else
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteConnect: Error - Invalid port"));
        status = PVMFFailure;
    }

    return status;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoDisconnect(const PVAENodeUtilCmd& aCmd)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVAuthorEngineNodeUtility::DoDisconnect"));

    PVMFPortInterface* port = NULL;
    PVAENodeContainer* container = aCmd.iNodes[0];

    if (!container->iInputPorts.empty())
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                        (0, "PVAuthorEngineNodeUtility::DoDisconnect: Release input port=0x%x", port));
        port = container->iInputPorts[0];
        container->iInputPorts.erase(container->iInputPorts.begin());
    }
    else if (!container->iOutputPorts.empty())
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                        (0, "PVAuthorEngineNodeUtility::DoDisconnect: Release output port=0x%x", port));
        port = container->iOutputPorts[0];
        container->iOutputPorts.erase(container->iOutputPorts.begin());
    }
    else
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_DEBUG,
                        (0, "PVAuthorEngineNodeUtility::DoDisconnect: All ports are released"));
        return PVMFSuccess;
    }

    if (PVMFFailure == ReleasePort(container, port))
        return PVMFFailure;

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoQueryUuid(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoQueryUuid"));

    Oscl_Vector<PVUuid, OsclMemAllocator>* uuids = NULL;
    bool exactUuidsOnly = false;
    PVMFStatus status = ((PVAENodeUtilCmd)aCmd).ParseQueryUUID(uuids, exactUuidsOnly);
    if (status != PVMFSuccess || !uuids)
    {
        LOG_ERR((0, "PVAuthorEngineNodeUtility::DoQueryUuid: Error - aCmd.ParseQueryUUID failed. status=%d", status));
        return status;
    }

    int32 err = 0;
    OSCL_TRY(err,
             aCmd.iNodes[0]->iNode->QueryUUID(aCmd.iNodes[0]->iSessionId, aCmd.iMimeType,
                                              *uuids, exactUuidsOnly, aCmd.iContext);
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoQueryUuid: Error - QueryUUID failed. node=0x%x",
                                  aCmd.iNodes[0]->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoQueryInterface(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoQueryInterface"));

    int32 err = 0;
    OSCL_TRY(err,
             PVInterface** interfacePtr = NULL;
             PVMFStatus status = ((PVAENodeUtilCmd)aCmd).ParseQueryInterface(interfacePtr);
             if (status != PVMFSuccess || !interfacePtr)
{
    LOG_ERR((0, "PVAuthorEngineNodeUtility::DoQueryInterface: Error - aCmd.ParseQueryInterface failed"));
        return PVMFFailure;
    }

    aCmd.iNodes[0]->iNode->QueryInterface(aCmd.iNodes[0]->iSessionId, aCmd.iUuid,
                                          (PVInterface*&)*interfacePtr, aCmd.iContext);
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoQueryInterface: Error - QueryInterface failed. node=0x%x",
                                  aCmd.iNodes[0]->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::CompleteQueryInterface(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteQueryInterface"));

    int32 err = 0;
    OSCL_TRY(err,
             PVInterface** interfacePtr = NULL;
             PVMFStatus status = ((PVAENodeUtilCmd)aCmd).ParseQueryInterface(interfacePtr);
             if (status != PVMFSuccess || !interfacePtr)
{
    LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteQueryInterface: Error - aCmd.ParseQueryInterface failed"));
        return PVMFFailure;
    }
    aCmd.iNodes[0]->iExtensionUuids.push_back(aCmd.iUuid);
    (*interfacePtr)->addRef();
    aCmd.iNodes[0]->iExtensions.push_back(*interfacePtr);
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteQueryInterface: Error - Adding extension to node container failed."));
                         return PVMFFailure;
                        );

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoInit(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoInit"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Init(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoInit: Error - Init failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoPrepare(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoPrepare"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Prepare(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoPrepare: Error - Prepare failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoStart(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoStart"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Start(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoStart: Error - Start failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoPause(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoPause"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Pause(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoPause: Error - Pause failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoStop(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoStop"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Stop(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoStop: Error - Stop failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoFlush(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoFlush"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        nodeContainer->iNode->Flush(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoFlush: Error - Flush failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::DoReset(const PVAENodeUtilCmd& aCmd)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::DoReset"));

    int32 err = 0;
    PVAENodeContainer* nodeContainer = NULL;
    OSCL_TRY(err,
             for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
{
    nodeContainer = aCmd.iNodes[i];
        for (uint32 j = 0; j < nodeContainer->iExtensions.size(); j++)
            nodeContainer->iExtensions[j]->removeRef();
        nodeContainer->iExtensions.clear();
        nodeContainer->iExtensionUuids.clear();
        nodeContainer->iNode->Reset(nodeContainer->iSessionId, aCmd.iContext);
    }
            );

    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoReset: Error - Reset failed. node=0x%x",
                                  nodeContainer->iNode));
                         return PVMFFailure;
                        );

    return PVMFPending;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::CompleteStateTransition(const PVAENodeUtilCmd& aCmd,
        TPVMFNodeInterfaceState aState)
{
    LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: aState=%d", aState));

    //Handle reset differently since we need to thread logoff here
    //if a node state is EPVMFNodeIdle (which is what aState would be if aCmd.iType is PVAENU_CMD_RESET)
    //do threadlogoff and take the node back to created
    if (aCmd.iType == PVAENU_CMD_RESET)
    {
        for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
        {
            if (aCmd.iNodes[i]->iNode->GetState() == aState)
            {
                // reset completed, perform threadlogoff on the node.
                PVMFStatus status = aCmd.iNodes[i]->iNode->ThreadLogoff();
                if (PVMFSuccess != status)
                {
                    LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: Error - Node ThreadLogoff failed for node=0x%x", aCmd.iNodes[i]->iNode));
                    OSCL_ASSERT(false);
                }
            }
        }
        //now that we have taken the nodes in idle back to created,
        //override aState to EPVMFNodeCreated
        aState = EPVMFNodeCreated;
    }
    for (uint32 i = 0; i < aCmd.iNodes.size(); i++)
    {
        if (aCmd.iNodes[i]->iNode->GetState() != aState)
        {
            // Some nodes have not completed this command. Continue to wait
            return PVMFPending;
        }
    }
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PVAuthorEngineNodeUtility::ReleasePort(PVAENodeContainer*& aContainer, PVMFPortInterface*& aPort)
{
    int32 err = 0;
    OSCL_TRY(err,
             aPort->Disconnect();
             aContainer->iNode->ReleasePort(aContainer->iSessionId, *aPort, (OsclAny*)aContainer);
            );
    OSCL_FIRST_CATCH_ANY(err,
                         LOG_ERR((0, "PVAuthorEngineNodeUtility::DoDisconnect: Error - ReleasePort failed"));
                         return PVMFFailure;
                        );
    return PVMFSuccess;
}