/* ------------------------------------------------------------------
 * 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 pvmf_media_input_node_outport.h
 * @brief Output port for media io interface wrapper node
 *
 */

#ifndef PV_COMMS_IO_NODE_PORT_H_INCLUDED
#define PV_COMMS_IO_NODE_PORT_H_INCLUDED

#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif
#ifndef OSCL_VECTOR_H_INCLUDED
#include "oscl_vector.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 PVMF_MEDIA_DATA_H_INCLUDED
#include "pvmf_media_data.h"
#endif
#ifndef PVMF_PORT_BASE_IMPL_H_INCLUDED
#include "pvmf_port_base_impl.h"
#endif
#ifndef PVMI_MEDIA_TRANSFER_H_INCLUDED
#include "pvmi_media_transfer.h"
#endif
#ifndef OSCL_MEM_MEMPOOL_H_INCLUDED
#include "oscl_mem_mempool.h"
#endif
#ifndef PVMF_NODE_INTERFACE_H_INCLUDED
#include "pvmf_node_interface.h"
#endif
#ifndef PVMI_CONFIG_AND_CAPABILITY_UTILS_H_INCLUDED
#include "pvmi_config_and_capability_utils.h"
#endif
#ifndef PVMI_MIO_COMM_DATA_BUFFER_H_INCLUDED
#include "pvmi_mio_comm_data_buffer.h"
#endif

// TEMP -RH TSC deletes the allocators while comm node holds buffers
// so copy them for now to avoid holding onto TSC fragments.
#define USE_COPY_BUFFER
#ifdef USE_COPY_BUFFER
#define NUM_COPY_BUFFERS 2
#define COPY_BUFFER_SIZE 1024
#endif

// Forward declaration
class PVCommsIONode;

class PVCommsIONodePort
        : public OsclTimerObject
        , public PvmfPortBaseImpl
        , public PvmiMediaTransfer
        , public PVMFPortActivityHandler
        , public PvmiCapabilityAndConfigBase
{
    public:
        PVCommsIONodePort(int32 aPortTag, PVCommsIONode* aNode);
        ~PVCommsIONodePort();

        OSCL_IMPORT_REF void Start();
        OSCL_IMPORT_REF void MediaIOStarted();
        OSCL_IMPORT_REF void Pause();
        OSCL_IMPORT_REF void Stop();

        OSCL_IMPORT_REF PVMFStatus Configure(PVMFFormatType aPortProperty);

        // these override the PvmfPortBaseImpl routines
        OSCL_IMPORT_REF PVMFStatus Connect(PVMFPortInterface* aPort);
        OSCL_IMPORT_REF PVMFStatus Disconnect();
        OSCL_IMPORT_REF PVMFStatus PeerConnect(PVMFPortInterface* aPort);
        OSCL_IMPORT_REF PVMFStatus PeerDisconnect();
        void QueryInterface(const PVUuid &aUuid, OsclAny*&aPtr)
        {
            if (aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID)
            {
                aPtr = (PvmiCapabilityAndConfig*)this;
            }
            else
            {
                aPtr = NULL;
            }
        }

        //from PVMFPortActivityHandler
        void HandlePortActivity(const PVMFPortActivity& aActivity);

        // Pure virtuals from PvmiMediaTransfer
        void setPeer(PvmiMediaTransfer *aPeer);
        void useMemoryAllocators(OsclMemAllocator* write_alloc = NULL);
        PVMFCommandId writeAsync(uint8 format_type, int32 format_index, uint8* data, uint32 data_len,
                                 const PvmiMediaXferHeader& data_header_info, OsclAny* aContext = NULL);
        void writeComplete(PVMFStatus aStatus, PVMFCommandId  write_cmd_id, OsclAny* aContext);
        PVMFCommandId readAsync(uint8* data, uint32 max_data_len, OsclAny* aContext = NULL,
                                int32* formats = NULL, uint16 num_formats = 0);
//  void readComplete(PVMFStatus aStatus, PVMFCommandId  read_cmd_id, int32 format_index,
        //uint32 seq_num, uint32 flags, const PVMFTimestamp& timestamp, OsclAny* aContext);
        void readComplete(PVMFStatus aStatus, PVMFCommandId  read_cmd_id, int32 format_index,
                          const PvmiMediaXferHeader& data_header_info, OsclAny* aContext);

        void statusUpdate(uint32 status_flags);
        void cancelCommand(PVMFCommandId  command_id);
        void cancelAllCommands();

        // Implement pure virtuals from PvmiCapabilityAndConfig interface
        OSCL_IMPORT_REF void setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver);
        OSCL_IMPORT_REF PVMFStatus getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier,
                PvmiKvp*& aParameters, int& num_parameter_elements,
                PvmiCapabilityContext aContext);
        OSCL_IMPORT_REF PVMFStatus releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements);
        OSCL_IMPORT_REF void setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
                                               int num_elements, PvmiKvp * & aRet_kvp);
        OSCL_IMPORT_REF PVMFStatus verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements);

        OSCL_IMPORT_REF bool isActiveCommsRead()
        {
            return iActiveCommsRead;
        }
        OSCL_IMPORT_REF bool isActiveCommsWrite()
        {
            return iActiveCommsWrite;
        }

        OSCL_EXPORT_REF bool isIncomingFull();

    private:
        int32 WriteAsync(int32& cmdId,
                         OsclRefCounterMemFrag frag,
                         PvmiMediaXferHeader data_hdr);

        void Run();

        void QueueData(PVMFSharedMediaDataPtr aData, bool requeue = false, uint32 fragindex = 0);
        PVMFStatus DequeueData(PVMFSharedMediaDataPtr &aData, bool &aResend, uint32 &aFragment);

        void SetDataTransferModels();

        // Container node
        PVCommsIONode* iNode;

        // Rx/Tx bitstream loggers;
        PVLogger *iRxLogger;
        PVLogger *iTxLogger;

        class AsyncIOCmd
        {
            public:
                AsyncIOCmd(PVMFCommandId id, OsclAny* context = NULL): iID(id), iContext(context) {}
                PVMFCommandId iID;
                OsclAny *iContext;
        };
        Oscl_Vector<AsyncIOCmd, OsclMemAllocator> iReadAsyncCmds;

        //Format
        PVMFFormatType iFormatType;

        PvmiMediaTransfer* iMediaOutputTransfer;
        PvmiMediaTransfer* iMediaInputTransfer;
        uint32 iRemoteStatus;

        uint32 cmdId;

        //media data re-send queue
        bool iResend;
        uint32 iResendSeqNum;
        uint32 iResendFragment;
        uint32 iWriteAsyncContext;

        PvmiMIOCommDataBufferAlloc iMediaDataAlloc;
        OsclMemPoolFixedChunkAllocator iMediaDataMemPool;

        enum PortState
        {
            PORT_STATE_BUFFERING = 0,
            PORT_STATE_STARTED,
        };
        PortState iState;
        PVMFFormatType iFormat;

        enum WriteState {EWriteBusy, EWriteWait, EWriteOK};
        WriteState iWriteState;

        //media data cleanup queue
        class CleanupQueueElement
        {
            public:
                CleanupQueueElement(PVMFSharedMediaDataPtr d, PVMFCommandId id): iData(d), iCmdId(id) {}
                PVMFSharedMediaDataPtr iData;
                PVMFCommandId iCmdId;
        };
        Oscl_Vector<CleanupQueueElement, OsclMemAllocator> iCleanupQueue;

        // Receive and Send models for the MediaDataTransfer
        // interface.  Threading model will likely dictate
        // how these are set.
        bool iActiveCommsWrite;
        bool iActiveCommsRead;

        uint32 iQueueLimit;

        bool iEndOfInputPortDataReached;
        bool iEndOfOutputPortDataReached;

        //for flow control
        bool iWriteFailed;
        PvmiMediaTransfer* iPeer;

        void ClearCleanupQueue();
        void CleanupMediaTransfer();

        bool CanSendCommsData();
        void SendCommsData();

        bool EndOfData(int32 aTag);

        //for datapath logging
        void LogMediaDataInfo(const char*msg, PVMFSharedMediaDataPtr mediaData, int32 p1, int32 p2);
        void LogMediaDataInfo(const char*msg, PVMFSharedMediaDataPtr mediaData);
        void LogDatapath(const char*msg);

#ifdef USE_COPY_BUFFER
        uint8 iCopyBuffer[NUM_COPY_BUFFERS][COPY_BUFFER_SIZE];
        uint32 iCopyBufferSize[NUM_COPY_BUFFERS];
        uint32 iCopyBufferIndex;
        bool iCopyBufferSent;

        void CopyBuffer();
        void SendCopyBuffer();
#endif
};

#endif // PV_COMMS_IO_NODE_PORT_H_INCLUDED
