/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "mt_test_common.h"

#include <cmath>

#include "modules/video_coding/main/source/tick_time_base.h"
#include "rtp_dump.h"

namespace webrtc {

TransportCallback::TransportCallback(webrtc::RtpRtcp* rtp,
                                     TickTimeBase* clock,
                                     const char* filename):
RTPSendCompleteCallback(rtp, clock, filename)
{
    //
}

TransportCallback::~TransportCallback()
{
    //
}

int
TransportCallback::SendPacket(int channel, const void *data, int len)
{
    _sendCount++;
    _totalSentLength += len;

    if (_rtpDump != NULL)
    {
        if (_rtpDump->DumpPacket((const WebRtc_UWord8*)data, len) != 0)
        {
            return -1;
        }
    }

    bool transmitPacket = true;
    // Off-line tests, don't drop first Key frame (approx.)
    if (_sendCount > 20)
    {
        transmitPacket = PacketLoss();
    }

    TickTimeBase clock;
    int64_t now = clock.MillisecondTimestamp();
    // Insert outgoing packet into list
    if (transmitPacket)
    {
        RtpPacket* newPacket = new RtpPacket();
        memcpy(newPacket->data, data, len);
        newPacket->length = len;
        // Simulate receive time = network delay + packet jitter
        // simulated as a Normal distribution random variable with
        // mean = networkDelay and variance = jitterVar
        WebRtc_Word32
        simulatedDelay = (WebRtc_Word32)NormalDist(_networkDelayMs,
                                                   sqrt(_jitterVar));
        newPacket->receiveTime = now + simulatedDelay;
        _rtpPackets.push_back(newPacket);
    }
    return 0;
}

int
TransportCallback::TransportPackets()
{
    // Are we ready to send packets to the receiver?
    RtpPacket* packet = NULL;
    TickTimeBase clock;
    int64_t now = clock.MillisecondTimestamp();

    while (!_rtpPackets.empty())
    {
        // Take first packet in list
        packet = _rtpPackets.front();
        WebRtc_Word64 timeToReceive = packet->receiveTime - now;
        if (timeToReceive > 0)
        {
            // No available packets to send
            break;
        }

        _rtpPackets.pop_front();
        // Send to receive side
        if (_rtp->IncomingPacket((const WebRtc_UWord8*)packet->data,
                                     packet->length) < 0)
        {
            delete packet;
            packet = NULL;
            // Will return an error after the first packet that goes wrong
            return -1;
        }
        delete packet;
        packet = NULL;
    }
    return 0; // OK
}



bool VCMProcessingThread(void* obj)
{
    SharedRTPState* state = static_cast<SharedRTPState*>(obj);
    if (state->_vcm.TimeUntilNextProcess() <= 0)
    {
        if (state->_vcm.Process() < 0)
        {
            return false;
        }
    }
    return true;
}


bool VCMDecodeThread(void* obj)
{
    SharedRTPState* state = static_cast<SharedRTPState*>(obj);
    state->_vcm.Decode();
    return true;
}

bool TransportThread(void *obj)
{
    SharedTransportState* state = static_cast<SharedTransportState*>(obj);
    state->_transport.TransportPackets();
    return true;
}

}  // namespace webrtc
