/* ------------------------------------------------------------------
 * 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 PVAUTHORENGINE_H_INCLUDED
#define PVAUTHORENGINE_H_INCLUDED

#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif
#ifndef OSCL_MEM_H_INCLUDED
#include "oscl_mem.h"
#endif
#ifndef OSCL_SCHEDULER_AO_H_INCLUDED
#include "oscl_scheduler_ao.h"
#endif
#ifndef PVLOGGER_H_INCLUDED
#include "pvlogger.h"
#endif
#ifndef PV_UUID_H_INCLUDED
#include "pv_uuid.h"
#endif
#ifndef PVMF_NODE_INTERFACE_H_INCLUDED
#include "pvmf_node_interface.h"
#endif
#ifndef PV_ENGINE_TYPES_H_INCLUDED
#include "pv_engine_types.h"
#endif
#ifndef PV_ENGINE_OBSERVER_H_INCLUDED
#include "pv_engine_observer.h"
#endif
#ifndef PVAUTHORENGINEINTERFACE_H_INCLUDED
#include "pvauthorengineinterface.h"
#endif
#ifndef PVAE_NODE_UTILITY_H_INCLUDED
#include "pvaenodeutility.h"
#endif
#ifndef PVMI_CONFIG_AND_CAPABILITY_BASE_H_INCLUDED
#include "pvmi_config_and_capability_base.h"
#endif
#ifndef PVMF_MEDIA_CLOCK_H_INCLUDED
#include "pvmf_media_clock.h"
#endif

#define K3gpComposerMimeType "/x-pvmf/ff-mux/3gp"
#define KMP4ComposerMimeType "/x-pvmf/ff-mux/mp4"
#define KAmrNbEncMimeType "/x-pvmf/audio/encode/amr-nb"
#define KAMRWbEncMimeType "/x-pvmf/audio/encode/amr-wb"
#define KH263EncMimeType "/x-pvmf/video/encode/h263"
#define KH264EncMimeType "/x-pvmf/video/encode/h264"
#define KMp4EncMimeType "/x-pvmf/video/encode/mp4"
#define KTextEncMimeType "/x-pvmf/text/encode/txt"

//MIME strings for .amr and .aac composer
#define KAMRNbComposerMimeType      "/x-pvmf/ff-mux/amr-nb"
#define KAMRWbComposerMimeType      "/x-pvmf/ff-mux/amr-wb"
#define KAACADIFComposerMimeType    "/x-pvmf/ff-mux/adif"
#define KAACADTSComposerMimeType    "/x-pvmf/ff-mux/adts"
#define KAACADIFEncMimeType         "/x-pvmf/audio/encode/aac/adif"
#define KAACADTSEncMimeType         "/x-pvmf/audio/encode/aac/adts"
#define KAACMP4EncMimeType          "/x-pvmf/audio/encode/X-MPEG4-AUDIO"
//end of changes

/**
 * Enumeration of types of asychronous commands that can be issued to PV Author Engine
 */
typedef enum
{
    PVAE_CMD_SET_LOG_APPENDER,
    PVAE_CMD_REMOVE_LOG_APPENDER,
    PVAE_CMD_SET_LOG_LEVEL,
    PVAE_CMD_GET_LOG_LEVEL,
    PVAE_CMD_OPEN,
    PVAE_CMD_CLOSE,
    PVAE_CMD_ADD_DATA_SOURCE,
    PVAE_CMD_REMOVE_DATA_SOURCE,
    PVAE_CMD_SELECT_COMPOSER,
    PVAE_CMD_ADD_MEDIA_TRACK,
    PVAE_CMD_ADD_DATA_SINK,
    PVAE_CMD_REMOVE_DATA_SINK,
    PVAE_CMD_INIT,
    PVAE_CMD_RESET,
    PVAE_CMD_START,
    PVAE_CMD_PAUSE,
    PVAE_CMD_RESUME,
    PVAE_CMD_STOP,
    PVAE_CMD_QUERY_INTERFACE,
    PVAE_CMD_GET_SDK_INFO,
    PVAE_CMD_GET_SDK_MODULE_INFO,
    PVAE_CMD_CANCEL_ALL_COMMANDS,
    PVAE_CMD_STOP_MAX_SIZE,
    PVAE_CMD_STOP_MAX_DURATION,
    PVAE_CMD_STOP_EOS_REACHED,
    PVAE_CMD_CAPCONFIG_SET_PARAMETERS
} PVAECmdType;

// Structure to hold the key string info for
// player engine's capability-and-config
struct PVAuthorKeyStringData
{
    char iString[64];
    PvmiKvpType iType;
    PvmiKvpValueType iValueType;
};

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

// Key string info at the base level ("x-pvmf/author/")
#define PVAUTHORCONFIG_BASE_NUMKEYS 3
const PVAuthorKeyStringData PVAuthorConfigBaseKeys[PVAUTHORCONFIG_BASE_NUMKEYS] =
{
    //These are dummy keys, to be changed in future
    {"dummy1", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_INT32},
    {"dummy2", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_INT32},
    //It is necessary to have this key for the PVAuthorConfigProdInfoKeys to work
    //Do not change the position of this key in the array
    {"productinfo", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_INT32}
    //add more keys here
};

// Key string info at the productinfo level ("x-pvmf/author/productinfo/")
#define PVAUTHORCONFIG_PRODINFO_NUMKEYS 2
const PVAuthorKeyStringData PVAuthorConfigProdInfoKeys[PVAUTHORCONFIG_PRODINFO_NUMKEYS] =
{
    {"dummyprod1", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_INT32},
    {"dummyprod2", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_INT32}
};


/**
 * PVAuthorEngine Class
 */
class PVAuthorEngine
        : public PVAuthorEngineInterface
        , public OsclTimerObject
        , public PVMFNodeErrorEventObserver
        , public PVMFNodeInfoEventObserver
        , public PVAENodeUtilObserver
        , public PvmiCapabilityAndConfigBase
{
    public:
        static PVAuthorEngineInterface* Create(PVCommandStatusObserver* aCmdStatusObserver,
                                               PVErrorEventObserver *aErrorEventObserver, PVInformationalEventObserver *aInfoEventObserver);
        ~PVAuthorEngine();

        /////////////////////////////////////////////////////////
        // Pure virtuals from PVAuthorEngineInterface
        /////////////////////////////////////////////////////////
        OSCL_IMPORT_REF PVCommandId SetLogAppender(const char* aTag, PVLoggerAppender& aAppender,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId RemoveLogAppender(const char* aTag, PVLoggerAppender& aAppender,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId SetLogLevel(const char* aTag, int32 aLevel, bool aSetSubtree = false,
                                                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId GetLogLevel(const char* aTag, PVLogLevelInfo& aLogInfo, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Open(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Close(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId AddDataSource(const PVMFNodeInterface& aDataSource, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId RemoveDataSource(const PVMFNodeInterface& aDataSource, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId SelectComposer(const PvmfMimeString& aComposerType, PVInterface*& aConfigInterface,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId SelectComposer(const PVUuid& aComposerUuid, PVInterface*& aConfigInterface,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId AddMediaTrack(const PVMFNodeInterface& aDataSource, const PvmfMimeString& aEncoderType,
                const OsclAny* aComposer, PVInterface*& aConfigInterface,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId AddMediaTrack(const PVMFNodeInterface& aDataSource, const PVUuid& aEncoderUuid,
                const OsclAny* aComposer, PVInterface*& aConfigInterface,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId AddDataSink(const PVMFNodeInterface& aDataSink, const OsclAny* aComposer,
                                                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId RemoveDataSink(const PVMFNodeInterface& aDataSink, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Init(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Reset(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Start(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Pause(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Resume(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId Stop(const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId QueryInterface(const PVUuid& aUuid,
                PVInterface*& aInterfacePtr,
                const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVAEState GetPVAuthorState();
        OSCL_IMPORT_REF PVCommandId GetSDKInfo(PVSDKInfo& aSDKInfo, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId GetSDKModuleInfo(PVSDKModuleInfo& aSDKModuleInfo, const OsclAny* aContextData = NULL);
        OSCL_IMPORT_REF PVCommandId CancelAllCommands(const OsclAny* aContextData = NULL);

        // Implement pure virtual from PVMFNodeErrorEventObserver
        void HandleNodeErrorEvent(const PVMFAsyncEvent& aEvent);

        // Implement pure virtual from PVMFNodeInfoEventObserver
        void HandleNodeInformationalEvent(const PVMFAsyncEvent& aEvent);

        // Implement pure virtuals from PVAENodeUtilObserver
        void NodeUtilCommandCompleted(const PVMFCmdResp& aResponse);
        void NodeUtilErrorEvent(const PVMFAsyncEvent& aEvent);
        // capability and configuration class implemented here
        // virtual functions of PvmiCapabilityAndConfig class implemented here

        void setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver);
        PVMFStatus getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext);
        PVMFStatus releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements);
        void createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext);
        void setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP);
        PVMFCommandId setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP, OsclAny* aContext = NULL);
        PVMFStatus verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements);
        // functions used by cap-config class virtual functions
        bool queryInterface(const PVUuid& uuid, PVInterface*& iface);
        PVMFStatus DoQueryNodeCapConfig(char* aKeySubString, Oscl_Vector<PVInterface*, OsclMemAllocator>& aNodeCapConfigIF);
        void addRef();
        void removeRef();
    private:
        PVAuthorEngine();
        void Construct(PVCommandStatusObserver *aCmdObserver, PVErrorEventObserver *aErrorObserver,
                       PVInformationalEventObserver *aInfoObserver);

        // From OsclTimerObject
        void Run();

        // Command handling functions
        void Dispatch(PVEngineCommand& aCmd);
        void Dispatch(PVEngineAsyncEvent& aEvent);
        void PushCmdInFront(PVEngineCommand& aCmd);
        void CompleteEngineCommand(PVEngineCommand& aCmd, PVMFStatus aStatus,
                                   OsclAny* aResponseData = NULL, int32 aResponseDataSize = 0);
        PVMFStatus DoOpen(PVEngineCommand& aCmd);
        PVMFStatus DoClose(PVEngineCommand& aCmd);
        PVMFStatus DoAddDataSource(PVEngineCommand& aCmd);
        PVMFStatus DoRemoveDataSource(PVEngineCommand& aCmd);
        PVMFStatus DoSelectComposer(PVEngineCommand& aCmd);
        PVMFStatus DoAddMediaTrack(PVEngineCommand& aCmd);
        PVMFStatus DoAddDataSink(PVEngineCommand& aCmd);
        PVMFStatus DoRemoveDataSink(PVEngineCommand& aCmd);
        PVMFStatus DoInit(PVEngineCommand& aCmd);
        PVMFStatus DoReset(PVEngineCommand& aCmd);
        PVMFStatus DoStart(PVEngineCommand& aCmd);
        PVMFStatus DoPause(PVEngineCommand& aCmd);
        PVMFStatus DoResume(PVEngineCommand& aCmd);
        PVMFStatus DoStop(PVEngineCommand& aCmd);
        PVMFStatus DoQueryInterface(PVEngineCommand& aCmd);
        PVMFStatus DoStopMaxSizeDuration();

        // Registry function
        PVMFStatus QueryRegistry(const PvmfMimeString& aMimeType, PVUuid& aUuid);

        // Author engine state functions
        void SetPVAEState(PVAEState aState);
        PVAEState GetPVAEState()
        {
            return iState;
        }

        // Find the container that holds the specified node
        PVAENodeContainer* GetNodeContainer(PVAENodeContainerVector& aNodeContainerVector, PVMFNodeInterface* aNode);

        /**
         * Check if the specified format is supported
         */
        PVMFStatus IsCompressedFormatDataSource(PVAENodeContainer* aDataSrc, const PvmfMimeString& aMimeString, bool& aIsCompressedFormat);

        /**
         * Resets the graph.  All nodes will be disconnected.
         */
        void ResetGraph();

        /**
         * All nodes(except source nodes) will be destroyed.
         * All nodes are removed from node vectors.
         * Source node pools are destroyed when RemoveDataSource API is executed.
         */
        void ResetNodeContainers();
        /**
         * Query configuration interface for the specified encoder or composer node
         *
         * When implementing support for a new composer or encoder node, this method will
         * need to be modified to query for configuration interface(s) of the new node.
         *
         * @param aNodeContainer Node container of composer node to perform query on
         * @return Completion status
         */
        PVMFStatus QueryNodeConfig(PVAENodeContainer* aNodeContainer, PVInterface*& aInterface);

        /**
         * Configure file format composer
         *
         * When implementing support for a new file format composer node, this method will
         * need to be updated to configure the new composer node.
         *
         * @param aComposerMimeType Composer Mime type
         * @return Completion status
         */
        PVMFStatus ConfigureComposer(const PvmfMimeString& aComposerMimeType);

        /**
         * Configure encoder
         *
         * If the encoder node supports multiple output formats, the engine will need to
         * configure the encoder to encode output to the format type specified by the
         * client in AddMediaTrack.
         *
         * When implementing support for a new encoder node, this method might need to
         * be updated to configure the new node.
         *
         * @param aMimeType Encoder Mime type specified by client
         * @return Completion status
         */
        PVMFStatus ConfigureEncoder(const PvmfMimeString& aMimeType);

        /**
         * Get the PVMFFormatType corresponding to the specified encoder mime type
         *
         * When implementing support for a new encoding type, this method will need
         * to be updated to return the format type mapped to this new encoding type.
         *
         * @param aFormatType Output parameter to store the PVMFFormatType
         * @param aMimeType Mime type to be converted to PVMFFormatType
         * @return PVMFSuccess if a mapping for the Mime type is found, else return PVMFFailure.
         */
        PVMFStatus GetPvmfFormatString(PvmfMimeString& aMimeType, const PvmfMimeString& aNodeMimeType);

        PVAENodeContainer* AllocateNodeContainer(PVMFNodeInterface* aNode);
        PVMFStatus DeallocateNodeContainer(PVAENodeContainerVector& aVector, PVMFNodeInterface* aNode);

        // private functions used internally in cap-config class functions
        //f(n) used in SetParametersSync function of cap-config class
        PVMFStatus DoCapConfigSetParameters(PVEngineCommand& aCmd, bool aSyncCmd = false);  // f(n) used in SetParametersSync function of cap-config class
        //f(n) used in GetParametersSync function of cap-config class
        PVMFStatus DoCapConfigGetParametersSync(PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext);
        //f(n) used in ReleaseParametersSync function of cap-config class
        PVMFStatus DoCapConfigReleaseParameters(PvmiKvp* aParameters, int aNumElements);
        //f(n) used in VerifyParametersSync function of cap-config class
        PVMFStatus DoCapConfigVerifyParameters(PvmiKvp* aParameters, int aNumElements);
        PVMFStatus DoVerifyAndSetAuthorParameter(PvmiKvp& aParameter, bool aSetParam);
        PVMFStatus DoVerifyAndSetAuthorProductInfoParameter(PvmiKvp& aParameter, bool aSetParam);
        PVMFStatus DoGetAuthorProductInfoParameter(PvmiKvp*& aParameters, int& aNumParamElements, int32 aIndex, PvmiKvpAttr reqattr);
        PVMFStatus DoGetAuthorParameter(PvmiKvp*& aParameters, int& aNumParamElements, int32 aIndex, PvmiKvpAttr reqattr);
    private:

        // Engine commands
        Oscl_Vector<PVEngineCommand, OsclMemAllocator> iPendingCmds;
        Oscl_Vector<PVEngineAsyncEvent, OsclMemAllocator> iPendingEvents;
        PVCommandId iCommandId;

        // Engine observers
        PVCommandStatusObserver* iCmdStatusObserver;
        PVInformationalEventObserver* iInfoEventObserver;
        PVErrorEventObserver* iErrorEventObserver;

        // Node utility and storage
        PVAuthorEngineNodeUtility iNodeUtil;
        PVAENodeContainerVector iDataSourcePool;
        PVAENodeContainerVector iDataSinkPool;
        PVAENodeContainerVector iDataSourceNodes;
        PVAENodeContainerVector iEncoderNodes;
        PVAENodeContainerVector iComposerNodes;
        PVAENodeContainerVector iAllNodes;

        PVMFFormatType iEncodedVideoFormat;
        PVAEState iState;
        PVLogger* iLogger;
        int32 iCapConfigContext;
        PvmiConfigAndCapabilityCmdObserver *iCfgCapCmdObserver;
        int iAsyncNumElements;
        bool iDoResetNodeContainers;

        //authoring clock related
        PVMFTimebase_Tickcount iAuthorClockTimebase;
        PVMFMediaClock iAuthorClock;
        PVMFStatus SendAuthoringClockToDataSources(bool aReset = false);

        PVMFStatus lastNodeCommandError;
};



#endif // PVAUTHORENGINE_H_INCLUDED


