/* ------------------------------------------------------------------
 * Copyright (C) 1998-2010 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.
 * -------------------------------------------------------------------
 */
#ifndef PVMF_MP4FFPARSER_NODE_H_INCLUDED
#include "pvmf_mp4ffparser_node.h"
#endif
#ifndef OSCL_MIME_STRING_UTILS_H_INCLUDED
#include "pv_mime_string_utils.h"
#endif
#ifndef PVMI_FILEIO_KVP_H_INCLUDED
#include "pvmi_fileio_kvp.h"
#endif

///////////////////////////////////////////////////////////////////////////////
//
// Capability and config interface related constants and definitions
//   - based on pv_player_engine.h
//
///////////////////////////////////////////////////////////////////////////////
struct MP4ParserNodeKeyStringData
{
    char iString[64];
    PvmiKvpType iType;
    PvmiKvpValueType iValueType;
};


// The number of characters to allocate for the key string
#define MP4CONFIG_KEYSTRING_SIZE 128

//The base selection keys for file IO,leading tag needs to be fileio
static const MP4ParserNodeKeyStringData MP4ParserNodeConfig_FileIO_Keys[] =
{
    {"pv-cache-size", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
    {"async-read-buffer-size", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
    {"logger-enable", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_BOOL},
    {"logger-stats-enable", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_BOOL},
    {"native-access-mode", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
    {"file-handle", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_KSV}
};

//The base selection keys for file IO,leading tag needs to be x-pvmf\net
static const MP4ParserNodeKeyStringData MP4ParserNodeConfig_Net_Keys[] =
{
    {"delay", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32}
};

static const MP4ParserNodeKeyStringData MP4ParserNodeConfig_Parser_Keys[] =
{
    {"enable-I-frame-playback-mode", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_BOOL},
};

static const uint MP4ParserNodeConfig_Num_FileIO_Keys =
    (sizeof(MP4ParserNodeConfig_FileIO_Keys) /
     sizeof(MP4ParserNodeKeyStringData));

static const uint MP4ParserNodeConfig_Num_Net_Keys =
    (sizeof(MP4ParserNodeConfig_Net_Keys) /
     sizeof(MP4ParserNodeKeyStringData));

static const uint MP4ParserNodeConfig_Num_Parser_Keys =
    (sizeof(MP4ParserNodeConfig_Parser_Keys) /
     sizeof(MP4ParserNodeKeyStringData));


enum BaseFileIOKeys_IndexMapType
{
    PV_CACHE_SIZE = 0,
    ASYNC_READ_BUFFER_SIZE,
    BASEKEY_PVLOGGER_ENABLE,
    PVLOGGER_STATS_ENABLE,
    NATIVE_ACCESS_MODE,
    FILE_HANDLE,
};

enum BaseNetKeys_IndexMapType
{
    DELAY = 0
};

enum BaseParserKeys_IndexMapType
{
    ENABLE_I_FRAME_PLAYBACK_MODE = 0,
};

///////////////////////////////////////////////////////////////////////////////

PVMFStatus PVMFMP4FFParserNode::getParametersSync(
    PvmiMIOSession aSession, PvmiKeyType aIdentifier,
    PvmiKvp*& aParameters, int& aNumParamElements,
    PvmiCapabilityContext aContext)
{


    OSCL_UNUSED_ARG(aSession);
    OSCL_UNUSED_ARG(aContext);

    // Initialize the output parameters
    aNumParamElements = 0;
    aParameters = NULL;

    // Count the number of components and parameters in the key
    int compcount = pv_mime_string_compcnt(aIdentifier);
    // Retrieve the first component from the key string
    char* compstr = NULL;
    pv_mime_string_extract_type(0, aIdentifier, compstr);

    iBaseKey = INVALID;

    if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("fileio")) < 0) || compcount < 2)
    {
        if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) < 0) || compcount < 2)
        {

            // First component should be "fileio" or "x-pvmf" and there must
            // be at least two components to go past fileio and x-pvmf
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::getParametersSync() Invalid key string"));
            return PVMFErrArgument;

        }
        else
        {
            // Retrieve the second component from the key string
            pv_mime_string_extract_type(1, aIdentifier, compstr);

            // Check if it is key string for streaming
            if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) < 0)
            {

                if (pv_mime_strcmp(compstr, _STRLIT_CHAR("parser")) < 0)
                {
                    PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP4FFParserNode::getParametersSync() Unsupported key"));
                    return PVMFFailure;
                }
                else
                {

                    iBaseKey = PARSER;
                }
            }
            else
            {
                iBaseKey = NET;
            }
        }
    }
    else
    {
        //Since the key string matches that of fileio
        iBaseKey = FILE_IO;
    }

    //If the leading tag is fileio then component count should be 2
    if ((iBaseKey == FILE_IO) && (compcount == 2))
    {
        //BaseKey's leading tag is fileio;
        pv_mime_string_extract_type(1, aIdentifier, compstr);

        // Determine what is requested
        PvmiKvpAttr reqattr = GetAttrTypeFromKeyString(aIdentifier);
        if (reqattr == PVMI_KVPATTR_UNKNOWN)
        {
            reqattr = PVMI_KVPATTR_CUR;
        }
        uint i;
        for (i = 0; i < MP4ParserNodeConfig_Num_FileIO_Keys; i++)
        {

            if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_FileIO_Keys[i].iString)) >= 0)
            {
                break;
            }
        }

        if (i == MP4ParserNodeConfig_Num_FileIO_Keys)
        {
            // no match found
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::getParametersSync() Unsupported key"));
            return PVMFErrNoMemory;
        }

        PVMFStatus retval = GetConfigParameter(aParameters, aNumParamElements, i, reqattr);
        if (retval != PVMFSuccess)
        {
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::getParametersSync() "
                                          "Retrieving mp4 parser node parameter failed"));
            return retval;
        }
    }
    else if ((iBaseKey == PARSER) && (compcount == 3))
    {
        pv_mime_string_extract_type(2, aIdentifier, compstr);

        // Determine what is requested
        PvmiKvpAttr reqattr = GetAttrTypeFromKeyString(aIdentifier);
        if (reqattr == PVMI_KVPATTR_UNKNOWN)
        {
            reqattr = PVMI_KVPATTR_CUR;
        }
        int32 i;
        for (i = 0; i < (int32)MP4ParserNodeConfig_Num_Parser_Keys; i++)
        {
            if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_Parser_Keys[i].iString)) >= 0)
            {
                break;
            }
        }

        if (i == (int32)MP4ParserNodeConfig_Num_Parser_Keys)
        {
            // no match found
            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
                            (0, "PVMFMP4FFParserNode::getParametersSync() Unsupported key"));
            return PVMFErrNoMemory;
        }

        PVMFStatus retval = GetConfigParameter(aParameters, aNumParamElements, i, reqattr);
        if (retval != PVMFSuccess)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
                            (0, "PVMFMP4FFParserNode::getParametersSync() "
                             "Retrieving streaming manager parameter failed"));
            return retval;
        }

    }
    else if ((iBaseKey == NET) && ((compcount == 2) || (compcount == 3)))
    {
        //  //BaseKey's leading tag is x-pvmf\net

        if (compcount == 2)
        {
            // Since key is "x-pvmf/net" return all
            // nodes available at this level. Ignore attribute
            // since capability is only allowed

            // Allocate memory for the KVP list
            aParameters = (PvmiKvp*)oscl_malloc(MP4ParserNodeConfig_Num_Net_Keys * sizeof(PvmiKvp));
            if (aParameters == NULL)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP4FFParserNode::getParametersSync() Memory allocation for KVP failed"));
                return PVMFErrNoMemory;
            }
            oscl_memset(aParameters, 0, MP4ParserNodeConfig_Num_Net_Keys*sizeof(PvmiKvp));
            // Allocate memory for the key strings in each KVP
            PvmiKeyType memblock = (PvmiKeyType)oscl_malloc(MP4ParserNodeConfig_Num_Net_Keys * MP4CONFIG_KEYSTRING_SIZE * sizeof(char));
            if (memblock == NULL)
            {
                oscl_free(aParameters);
                PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP4FFParserNode::getParametersSync() Memory allocation for key string failed"));
                return PVMFErrNoMemory;
            }
            oscl_strset(memblock, 0, MP4ParserNodeConfig_Num_Net_Keys*MP4CONFIG_KEYSTRING_SIZE*sizeof(char));
            // Assign the key string buffer to each KVP
            int32 j;
            for (j = 0; j < (int32)MP4ParserNodeConfig_Num_Net_Keys; ++j)
            {
                aParameters[j].key = memblock + (j * MP4CONFIG_KEYSTRING_SIZE);
            }
            // Copy the requested info
            for (j = 0; j < (int32)MP4ParserNodeConfig_Num_Net_Keys; ++j)
            {
                oscl_strncat(aParameters[j].key, _STRLIT_CHAR("x-pvmf/net/"), 11);
                oscl_strncat(aParameters[j].key, MP4ParserNodeConfig_Net_Keys[j].iString, oscl_strlen(MP4ParserNodeConfig_Net_Keys[j].iString));
                oscl_strncat(aParameters[j].key, _STRLIT_CHAR(";type="), 6);
                switch (MP4ParserNodeConfig_Net_Keys[j].iType)
                {
                    case PVMI_KVPTYPE_AGGREGATE:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_AGGREGATE_STRING), oscl_strlen(PVMI_KVPTYPE_AGGREGATE_STRING));
                        break;

                    case PVMI_KVPTYPE_POINTER:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_POINTER_STRING), oscl_strlen(PVMI_KVPTYPE_POINTER_STRING));
                        break;

                    case PVMI_KVPTYPE_VALUE:
                    default:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_VALUE_STRING), oscl_strlen(PVMI_KVPTYPE_VALUE_STRING));
                        break;
                }
                oscl_strncat(aParameters[j].key, _STRLIT_CHAR(";valtype="), 9);
                switch (MP4ParserNodeConfig_Net_Keys[j].iValueType)
                {
                    case PVMI_KVPVALTYPE_RANGE_INT32:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_INT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_RANGE_INT32_STRING));
                        break;

                    case PVMI_KVPVALTYPE_KSV:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_KSV_STRING), oscl_strlen(PVMI_KVPVALTYPE_KSV_STRING));
                        break;

                    case PVMI_KVPVALTYPE_CHARPTR:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_CHARPTR_STRING), oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING));
                        break;

                    case PVMI_KVPVALTYPE_BOOL:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING), oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));
                        break;

                    case PVMI_KVPVALTYPE_UINT32:
                    default:
                        oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_UINT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING));
                        break;
                }
                aParameters[j].key[MP4CONFIG_KEYSTRING_SIZE-1] = 0;
            }

            aNumParamElements = MP4ParserNodeConfig_Num_Net_Keys;
        }
        else if (compcount == 3)
        {
            pv_mime_string_extract_type(2, aIdentifier, compstr);

            // Determine what is requested
            PvmiKvpAttr reqattr = GetAttrTypeFromKeyString(aIdentifier);
            if (reqattr == PVMI_KVPATTR_UNKNOWN)
            {
                reqattr = PVMI_KVPATTR_CUR;
            }
            int32 i;
            for (i = 0; i < (int32)MP4ParserNodeConfig_Num_Net_Keys; i++)
            {
                if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_Net_Keys[i].iString)) >= 0)
                {
                    break;
                }
            }

            if (i == (int32)MP4ParserNodeConfig_Num_Net_Keys)
            {
                // no match found
                PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
                                (0, "PVMFMP4FFParserNode::getParametersSync() Unsupported key"));
                return PVMFErrNoMemory;
            }

            PVMFStatus retval = GetConfigParameter(aParameters, aNumParamElements, i, reqattr);
            if (retval != PVMFSuccess)
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
                                (0, "PVMFMP4FFParserNode::getParametersSync() "
                                 "Retrieving streaming manager parameter failed"));
                return retval;
            }
        }
    }
    else
    {
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::getParametersSync() Unsupported key"));
        return PVMFErrArgument;
    }

    return PVMFSuccess;
}

PVMFStatus PVMFMP4FFParserNode::releaseParameters(PvmiMIOSession aSession,
        PvmiKvp* aParameters,
        int num_elements)
{
    OSCL_UNUSED_ARG(aSession);
    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::releaseParameters() In"));

    if (aParameters == NULL || num_elements < 1)
    {
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::releaseParameters() KVP list is NULL or number of elements is 0"));
        return PVMFErrArgument;
    }

    int32 compcount = pv_mime_string_compcnt(aParameters[0].key);

    // Retrieve the first component from the key string
    char* compstr = NULL;

    pv_mime_string_extract_type(0, aParameters[0].key, compstr);

    if ((compcount < 2) || ((pv_mime_strcmp(compstr, _STRLIT_CHAR("fileio")) < 0) && (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) < 0)))
        return PVMFErrArgument;

    //It does not effect in releasing memory what are the base keys either fileio or x-pvmf.
    if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("fileio")) >= 0) || (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) >= 0))
    {
        // Go through each KVP and release memory for value if allocated from heap
        for (int32 i = 0; i < num_elements; ++i)
        {
            // Next check if it is a value type that allocated memory
            PvmiKvpType kvptype = GetTypeFromKeyString(aParameters[i].key);
            if (kvptype == PVMI_KVPTYPE_VALUE || kvptype == PVMI_KVPTYPE_UNKNOWN)
            {
                PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[i].key);
                if (keyvaltype == PVMI_KVPVALTYPE_UNKNOWN)
                {
                    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::releaseParameters() Valtype not specified in key string"));
                    return PVMFErrArgument;
                }

                if (keyvaltype == PVMI_KVPVALTYPE_CHARPTR && aParameters[i].value.pChar_value != NULL)
                {
                    oscl_free(aParameters[i].value.pChar_value);
                    aParameters[i].value.pChar_value = NULL;
                }
                else if (keyvaltype == PVMI_KVPVALTYPE_WCHARPTR && aParameters[i].value.pWChar_value != NULL)
                {
                    oscl_free(aParameters[i].value.pWChar_value);
                    aParameters[i].value.pWChar_value = NULL;
                }
                else if (keyvaltype == PVMI_KVPVALTYPE_CHARPTR && aParameters[i].value.pChar_value != NULL)
                {
                    oscl_free(aParameters[i].value.pChar_value);
                    aParameters[i].value.pChar_value = NULL;
                }
                else if (keyvaltype == PVMI_KVPVALTYPE_KSV && aParameters[i].value.key_specific_value != NULL)
                {
                    oscl_free(aParameters[i].value.key_specific_value);
                    aParameters[i].value.key_specific_value = NULL;
                }
                else if (keyvaltype == PVMI_KVPVALTYPE_RANGE_INT32 && aParameters[i].value.key_specific_value != NULL)
                {
                    range_int32* ri32 = (range_int32*)aParameters[i].value.key_specific_value;
                    aParameters[i].value.key_specific_value = NULL;
                    oscl_free(ri32);
                }
                else if (keyvaltype == PVMI_KVPVALTYPE_RANGE_UINT32 && aParameters[i].value.key_specific_value != NULL)
                {
                    range_uint32* rui32 = (range_uint32*)aParameters[i].value.key_specific_value;
                    aParameters[i].value.key_specific_value = NULL;
                    oscl_free(rui32);
                }
            }
        }

        oscl_free(aParameters[0].key);

        // Free memory for the parameter list
        oscl_free(aParameters);
        aParameters = NULL;
    }
    else
    {
        // Unknown key string
        return PVMFErrArgument;
    }

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::releaseParameters() Out"));
    return PVMFSuccess;
}


void PVMFMP4FFParserNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
        int num_elements, PvmiKvp* &aRet_kvp)
{
    OSCL_UNUSED_ARG(aSession);

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() In"));


    // Go through each parameter
    for (int32 paramind = 0; paramind < num_elements; ++paramind)
    {
        // Count the number of components and parameters in the key
        int compcount = pv_mime_string_compcnt(aParameters[paramind].key);

        // Retrieve the first component from the key string
        char* compstr = NULL;
        pv_mime_string_extract_type(0, aParameters[paramind].key, compstr);

        // First check if it is key string for the mp4 parser node
        if (pv_mime_strcmp(compstr, _STRLIT_CHAR("fileio")) >= 0)
        {
            iBaseKey = FILE_IO;
            if (compcount == 2)
            {
                pv_mime_string_extract_type(1, aParameters[paramind].key, compstr);
                uint i;
                for (i = 0; i < MP4ParserNodeConfig_Num_FileIO_Keys; i++)
                {
                    if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_FileIO_Keys[i].iString)) >= 0)
                    {
                        break;
                    }
                }

                if (MP4ParserNodeConfig_Num_FileIO_Keys == i)
                {
                    // invalid third component
                    aRet_kvp = &aParameters[paramind];
                    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
                    return;
                }

                // Verify and set the passed-in setting
                PVMFStatus retval = VerifyAndSetConfigParameter(i, aParameters[paramind], true);
                if (retval != PVMFSuccess)
                {
                    aRet_kvp = &aParameters[paramind];
                    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Setting "
                                                  "parameter %d failed", paramind));
                    return;
                }
            }
            else
            {
                // Do not support more than 2 components right now
                aRet_kvp = &aParameters[paramind];
                PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
                return;
            }
        }
        else if (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) >= 0)
        {
            if (compcount == 3)
            {
                // Retrieve the second component from the key string
                pv_mime_string_extract_type(1, aParameters[paramind].key, compstr);
                // First check if it is key string for the streaming manager
                if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) >= 0)
                {
                    iBaseKey = NET;
                    int32 i;
                    //Extract the third component from the key string
                    pv_mime_string_extract_type(2, aParameters[paramind].key, compstr);
                    for (i = 0; i < (int32)MP4ParserNodeConfig_Num_Net_Keys; i++)
                    {
                        if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_Net_Keys[i].iString)) >= 0)
                        {
                            break;
                        }
                    }

                    if ((int32)MP4ParserNodeConfig_Num_Net_Keys == i)
                    {
                        // invalid third component
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
                        return;
                    }

                    // Verify and set the passed-in setting
                    PVMFStatus retval = VerifyAndSetConfigParameter(i, aParameters[paramind], true);
                    if (retval != PVMFSuccess)
                    {
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Setting "
                                                      "parameter %d failed", paramind));
                        return;
                    }
                }
                else if (pv_mime_strcmp(compstr, _STRLIT_CHAR("parser/ff_noaudio")) >= 0)
                {
                    // Make sure its a bool value
                    PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[paramind].key);
                    if (PVMI_KVPVALTYPE_BOOL != keyvaltype)
                    {
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync Setting "
                                                      "ff_noaudio valtype error"));
                        return;
                    }
                    iParseAudioDuringFF = aParameters[paramind].value.bool_value;
                }
                else if (pv_mime_strcmp(compstr, _STRLIT_CHAR("parser/rew_noaudio")) >= 0)
                {
                    // Make sure its a bool value
                    PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[paramind].key);
                    if (PVMI_KVPVALTYPE_BOOL != keyvaltype)
                    {
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync Setting "
                                                      "ff_noaudio valtype error"));
                        return;
                    }
                    iParseAudioDuringREW = aParameters[paramind].value.bool_value;
                }
                else if (pv_mime_strcmp(compstr, _STRLIT_CHAR("parser/mp4ff-open-file-once-per-track")) >= 0)
                {
                    // Make sure its a bool value
                    PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[paramind].key);
                    if (PVMI_KVPVALTYPE_BOOL != keyvaltype)
                    {
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync Setting "
                                                      "ff_noaudio valtype error"));
                        return;
                    }
                    iOpenFileOncePerTrack = aParameters[paramind].value.bool_value;
                }
                else if (pv_mime_strcmp(compstr, _STRLIT_CHAR("parser/enable-I-frame-playback-mode")) >= 0)
                {
                    // Make sure its a bool value
                    PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[paramind].key);
                    if (PVMI_KVPVALTYPE_BOOL != keyvaltype)
                    {
                        aRet_kvp = &aParameters[paramind];
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync Setting "
                                                      "x-pvmf/parser/enable-I-frame-playback-mode valtype error"));
                        return;
                    }
                    iIFrameOnlyFwdPlayback = aParameters[paramind].value.bool_value;
                    iStartForNextTSSearch = 0;
                }

                else
                {
                    // Unknown key string
                    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
                    return;
                }
            }
            else
            {
                // Do not support more than 3 components right now
                aRet_kvp = &aParameters[paramind];
                PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
                return;
            }
        }
        else
        {
            // Unknown key string
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Unsupported key"));
            return;
        }
    }

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::setParametersSync() Out"));
}


PVMFStatus PVMFMP4FFParserNode::verifyParametersSync(PvmiMIOSession aSession,
        PvmiKvp* aParameters,
        int num_elements)
{
    OSCL_UNUSED_ARG(aSession);

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::verifyParametersSync() In"));

    if (aParameters == NULL || num_elements < 1)
    {
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::verifyParametersSync() Passed in parameter invalid"));
        return PVMFErrArgument;
    }

    // Go through each parameter and verify
    for (int32 paramind = 0; paramind < num_elements; ++paramind)
    {
        // Retrieve the first component from the key string
        char* compstr = NULL;

        // Retrieve the second component from the key string
        pv_mime_string_extract_type(0, aParameters[paramind].key, compstr);

        // First check if it is key string for this node
        if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("fileio")) >= 0))
        {
            iBaseKey = FILE_IO;
            pv_mime_string_extract_type(1, aParameters[paramind].key, compstr);
            int32 i;
            for (i = 0; i < (int32)MP4ParserNodeConfig_Num_FileIO_Keys; i++)
            {
                if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_FileIO_Keys[i].iString)) >= 0)
                {
                    break;
                }
            }

            if ((int32)MP4ParserNodeConfig_Num_FileIO_Keys == i)
            {
                return PVMFErrArgument;
            }

            // Verify the passed-in player setting
            PVMFStatus retval = VerifyAndSetConfigParameter(i, aParameters[paramind], false);
            if (retval != PVMFSuccess)
            {
                PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoCapConfigVerifyParameters() Verifying parameter %d failed", paramind));
                return retval;
            }
        }
        // First check if it is key string for this node
        else if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) >= 0))
        {
            pv_mime_string_extract_type(1, aParameters[paramind].key, compstr);
            if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) >= 0)
            {
                iBaseKey = NET;
                int32 i;
                pv_mime_string_extract_type(2, aParameters[paramind].key, compstr);
                for (i = 0; i < (int32)MP4ParserNodeConfig_Num_Net_Keys; i++)
                {
                    if (pv_mime_strcmp(compstr, (char*)(MP4ParserNodeConfig_Net_Keys[i].iString)) >= 0)
                    {
                        break;
                    }
                }

                if ((int32)MP4ParserNodeConfig_Num_Net_Keys == i)
                {
                    return PVMFErrArgument;
                }

                // Verify the passed-in player setting
                PVMFStatus retval = VerifyAndSetConfigParameter(i, aParameters[paramind], false);
                if (retval != PVMFSuccess)
                {
                    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoCapConfigVerifyParameters() Verifying parameter %d failed", paramind));
                    return retval;
                }
            }
            else
            {
                // Unknown key string
                return PVMFErrArgument;
            }
        }
        else
        {
            // Unknown key string
            return PVMFErrArgument;
        }

    }

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoCapConfigVerifyParameters() Out"));
    return PVMFSuccess;
}

PVMFStatus PVMFMP4FFParserNode::GetConfigParameter(PvmiKvp*& aParameters,
        int& aNumParamElements,
        int32 aIndex, PvmiKvpAttr reqattr)
{
    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() In"));

    aNumParamElements = 0;

    // Allocate memory for the KVP
    aParameters = (PvmiKvp*)oscl_malloc(sizeof(PvmiKvp));
    if (aParameters == NULL)
    {
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() Memory allocation for KVP failed"));
        return PVMFErrNoMemory;
    }
    oscl_memset(aParameters, 0, sizeof(PvmiKvp));

    // Allocate memory for the key string in KVP
    PvmiKeyType memblock = (PvmiKeyType)oscl_malloc(MP4CONFIG_KEYSTRING_SIZE * sizeof(char));
    if (memblock == NULL)
    {
        oscl_free(aParameters);
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() Memory allocation for key string failed"));
        return PVMFErrNoMemory;
    }
    oscl_strset(memblock, 0, MP4CONFIG_KEYSTRING_SIZE*sizeof(char));

    // Assign the key string buffer to KVP
    aParameters[0].key = memblock;

    // Copy the key string
    if (iBaseKey == FILE_IO)
    {
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR("fileio/"), 7);
        oscl_strncat(aParameters[0].key, MP4ParserNodeConfig_FileIO_Keys[aIndex].iString,
                     oscl_strlen(MP4ParserNodeConfig_FileIO_Keys[aIndex].iString));
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR(";type=value;valtype="), 20);
        switch (MP4ParserNodeConfig_FileIO_Keys[aIndex].iValueType)
        {
            case PVMI_KVPVALTYPE_RANGE_INT32:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_INT32_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_RANGE_INT32_STRING));
                break;

            case PVMI_KVPVALTYPE_KSV:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_KSV_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_KSV_STRING));
                break;

            case PVMI_KVPVALTYPE_CHARPTR:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_CHARPTR_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING));
                break;

            case PVMI_KVPVALTYPE_WCHARPTR:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_WCHARPTR_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_WCHARPTR_STRING));
                break;

            case PVMI_KVPVALTYPE_BOOL:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));
                break;

            case PVMI_KVPVALTYPE_UINT32:
            default:
                if (reqattr == PVMI_KVPATTR_CAP)
                {
                    oscl_strncat(aParameters[0].key,
                                 _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_UINT32_STRING),
                                 oscl_strlen(PVMI_KVPVALTYPE_RANGE_UINT32_STRING));
                }
                else
                {
                    oscl_strncat(aParameters[0].key,
                                 _STRLIT_CHAR(PVMI_KVPVALTYPE_UINT32_STRING),
                                 oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING));
                }
                break;
        }
        aParameters[0].key[MP4CONFIG_KEYSTRING_SIZE-1] = 0;

        // Copy the requested info
        switch (aIndex)
        {
            case PV_CACHE_SIZE:
                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    aParameters[0].value.uint32_value = iCacheSize;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    // Return default
                    aParameters[0].value.uint32_value = DEFAULT_CAHCE_SIZE;
                }
                else
                {
                    // Return capability
                    range_uint32* rui32 = (range_uint32*)oscl_malloc(sizeof(range_uint32));
                    if (rui32 == NULL)
                    {
                        oscl_free(aParameters[0].key);
                        oscl_free(aParameters);
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() "
                                                      "Memory allocation for range uint32 failed"));
                        return PVMFErrNoMemory;
                    }
                    rui32->min = MIN_CACHE_SIZE;
                    rui32->max = MAX_CACHE_SIZE;
                    aParameters[0].value.key_specific_value = (void*)rui32;
                }
                break;
            case ASYNC_READ_BUFFER_SIZE:
                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    // Return current value
                    aParameters[0].value.uint32_value = iAsyncReadBuffSize;;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    // Return default
                    aParameters[0].value.uint32_value = DEFAULT_ASYNC_READ_BUFFER_SIZE;
                }
                else
                {
                    // Return capability
                    range_uint32* rui32 = (range_uint32*)oscl_malloc(sizeof(range_uint32));
                    if (rui32 == NULL)
                    {
                        oscl_free(aParameters[0].key);
                        oscl_free(aParameters);
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() "
                                                      "Memory allocation for range uint32 failed"));
                        return PVMFErrNoMemory;
                    }
                    rui32->min = MIN_ASYNC_READ_BUFFER_SIZE;
                    rui32->max = MAX_ASYNC_READ_BUFFER_SIZE;
                    aParameters[0].value.key_specific_value = (void*)rui32;
                }
                break;
            case BASEKEY_PVLOGGER_ENABLE:

                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    aParameters[0].value.bool_value = iPVLoggerEnableFlag;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    aParameters[0].value.bool_value = false;
                }
                else
                {
                    // Return capability - no concept of capability for keep alive interval
                    // do nothing
                }
                break;

            case PVLOGGER_STATS_ENABLE:
                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    aParameters[0].value.bool_value = iPVLoggerStateEnableFlag;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    aParameters[0].value.bool_value = false;
                }
                else
                {
                    // Return capability - no concept of capability for keep alive interval
                    // do nothing
                }
                break;
            case NATIVE_ACCESS_MODE:
                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    // Return current value
                    aParameters[0].value.uint32_value = iNativeAccessMode;;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    // Return default
                    aParameters[0].value.uint32_value = DEFAULT_NATIVE_ACCESS_MODE;
                }
                else
                {
                    // Return capability
                }
                break;



            default:
                // Invalid index
                oscl_free(aParameters[0].key);
                oscl_free(aParameters);
                PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoGetPlayerParameter() Invalid index to player parameter"));
                return PVMFErrArgument;
        }
    }
    else if (iBaseKey == NET)
    {
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR("x-pvmf/net/"), 11);
        oscl_strncat(aParameters[0].key, MP4ParserNodeConfig_Net_Keys[aIndex].iString,
                     oscl_strlen(MP4ParserNodeConfig_Net_Keys[aIndex].iString));
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR(";type=value;valtype="), 20);
        switch (MP4ParserNodeConfig_Net_Keys[aIndex].iValueType)
        {
            case PVMI_KVPVALTYPE_RANGE_INT32:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_INT32_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_RANGE_INT32_STRING));
                break;

            case PVMI_KVPVALTYPE_KSV:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_KSV_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_KSV_STRING));
                break;

            case PVMI_KVPVALTYPE_CHARPTR:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_CHARPTR_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING));
                break;

            case PVMI_KVPVALTYPE_WCHARPTR:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_WCHARPTR_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_WCHARPTR_STRING));
                break;

            case PVMI_KVPVALTYPE_BOOL:
                oscl_strncat(aParameters[0].key,
                             _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING),
                             oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));
                break;

            case PVMI_KVPVALTYPE_UINT32:
            default:
                if (reqattr == PVMI_KVPATTR_CAP)
                {
                    oscl_strncat(aParameters[0].key,
                                 _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_UINT32_STRING),
                                 oscl_strlen(PVMI_KVPVALTYPE_RANGE_UINT32_STRING));
                }
                else
                {
                    oscl_strncat(aParameters[0].key,
                                 _STRLIT_CHAR(PVMI_KVPVALTYPE_UINT32_STRING),
                                 oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING));
                }
                break;
        }
        aParameters[0].key[MP4CONFIG_KEYSTRING_SIZE-1] = 0;

        // Copy the requested info
        switch (aIndex)
        {
            case DELAY:
                if (reqattr == PVMI_KVPATTR_CUR)
                {
                    aParameters[0].value.uint32_value = iJitterBufferDurationInMs;
                }
                else if (reqattr == PVMI_KVPATTR_DEF)
                {
                    // Return default
                    aParameters[0].value.uint32_value = PVMF_MP4FFPARSER_NODE_PSEUDO_STREAMING_BUFFER_DURATION_IN_MS;
                }
                else
                {
                    // Return capability
                    range_uint32* rui32 = (range_uint32*)oscl_malloc(sizeof(range_uint32));
                    if (rui32 == NULL)
                    {
                        oscl_free(aParameters[0].key);
                        oscl_free(aParameters);
                        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::GetConfigParameter() "
                                                      "Memory allocation for range uint32 failed"));
                        return PVMFErrNoMemory;
                    }
                    rui32->min = MIN_JITTER_BUFFER_DURATION_IN_MS;
                    rui32->max = MAX_JITTER_BUFFER_DURATION_IN_MS;
                    aParameters[0].value.key_specific_value = (void*)rui32;
                }
                break;

            default:
                // Invalid index
                oscl_free(aParameters[0].key);
                oscl_free(aParameters);
                PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoGetPlayerParameter() Invalid index to player parameter"));
                return PVMFErrArgument;
        }
    }
    else if (iBaseKey == PARSER)
    {
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR("x-pvmf/parser/"), 14);
        oscl_strncat(aParameters[0].key, MP4ParserNodeConfig_Parser_Keys[aIndex].iString,
                     oscl_strlen(MP4ParserNodeConfig_Parser_Keys[aIndex].iString));
        oscl_strncat(aParameters[0].key, _STRLIT_CHAR(";type=value;valtype="), 20);
        if (MP4ParserNodeConfig_Parser_Keys[aIndex].iValueType == PVMI_KVPVALTYPE_BOOL)
        {
            oscl_strncat(aParameters[0].key,
                         _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING),
                         oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));

            aParameters[0].value.bool_value = iIFrameOnlyFwdPlayback ;

        }
        aParameters[0].key[MP4CONFIG_KEYSTRING_SIZE-1] = 0;
    }

    aNumParamElements = 1;
    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVPlayerEngine::DoGetPlayerParameter() Out"));
    return PVMFSuccess;

}


PVMFStatus PVMFMP4FFParserNode::VerifyAndSetConfigParameter(int index, PvmiKvp& aParameter, bool set)
{
    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::VerifyAndSetConfigParameter() In"));

    // Determine the valtype
    PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameter.key);
    if (keyvaltype == PVMI_KVPVALTYPE_UNKNOWN)
    {
        PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::VerifyAndSetConfigParameter() "
                                      "Valtype in key string unknown"));
        return PVMFErrArgument;
    }

    if (iBaseKey == FILE_IO)
    {   // Verify the valtype
        if (keyvaltype != MP4ParserNodeConfig_FileIO_Keys[index].iValueType)
        {
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::VerifyAndSetConfigParameter() "
                                          "Valtype does not match for key"));
            return PVMFErrArgument;
        }

        switch (index)
        {
            case PV_CACHE_SIZE:
            {
                // Validate
                if (set)
                {
                    // save value locally
                    iCacheSize = aParameter.value.uint32_value;
                }
            }
            break;
            case ASYNC_READ_BUFFER_SIZE:
            {
                if (set)
                {
                    // retrieve and update
                    iAsyncReadBuffSize = aParameter.value.uint32_value;
                }
            }
            break;
            case BASEKEY_PVLOGGER_ENABLE:
            {
                if (set)
                {
                    // retrieve and update
                    iPVLoggerEnableFlag = aParameter.value.bool_value;
                }
            }
            break;
            case PVLOGGER_STATS_ENABLE:
            {
                if (set)
                {
                    // user agent update
                    iPVLoggerStateEnableFlag = aParameter.value.bool_value;
                }
            }
            break;

            case NATIVE_ACCESS_MODE:
            {
                if (set)
                {
                    iNativeAccessMode = aParameter.value.uint32_value;
                }
            }
            break;

            case FILE_HANDLE:
            {
                if (set)
                {
                }
            }
            break;

            default:
                OSCL_ASSERT(0);
        }
    }
    else if (iBaseKey == NET)
    {
        // Verify the valtype
        if (keyvaltype != MP4ParserNodeConfig_FileIO_Keys[index].iValueType)
        {
            PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::VerifyAndSetConfigParameter() "
                                          "Valtype does not match for key"));
            return PVMFErrArgument;
        }

        switch (index)
        {
            case DELAY:
            {
                // Validate
                if (set)
                {
                    // save value locally
                    iJitterBufferDurationInMs = aParameter.value.uint32_value;
                }
            }
            break;

            default:
                return PVMFErrNotSupported;
        }
    }

    PVMF_MP4FFPARSERNODE_LOGINFO((0, "PVMFMP4FFParserNode::VerifyAndSetPlayerParameter() Out"));
    return PVMFSuccess;
}
