/*
#  $Id$
# -----------------------------------------------------------------------------
#  The part of 'VideoNEXT MediaClient SDK'
# -----------------------------------------------------------------------------
#  Author: Petrov Maxim, 03/04/2009
#  Edited by:
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
*/
#ifndef C_PTR
#define C_PTR

#include "ace/Refcounted_Auto_Ptr.h"

#include <sys/time.h>
#include <stdlib.h>
#include <stdint.h>
#include "Mutex.h"
#include <string>

namespace videonext { namespace media {

/**
 * This class implements simple reference counting.
 * It's threads safe. 
 * When internal counter is zerro - object will be delete[]d.
 * 
 * Use it as wrapper  to MediaFrame 
 * 
 */
template <typename Type>
class c_ptr 
{
public:
    c_ptr(Type *p) : pointee(p), refs(new uint32_t(0)), mutex(new Mutex) 
    {
        Grab();
    }
    
    c_ptr(const c_ptr<Type>& cp) : pointee(cp.pointee), refs(cp.refs), mutex(cp.mutex)
    {
        Grab();
    }

    ~c_ptr()
    {
        Release();
    }
    
    Type* get() { return pointee; }

    Type* operator->() { return pointee; }

    Type* operator->() const { return pointee; }

   
private:
    
    c_ptr<Type>& operator=(const c_ptr<Type>& cp)
    {
        Release();
        
        pointee     = cp.pointee;
        refs        = cp.refs;
        mutex       = cp.mutex;
        
        Grab();
        
        return *this;
        
    }
    
    Type* pointee;
    uint32_t *refs;	
    Mutex *mutex;

    void Grab()
    {
        mutex->lock();
        ++(*refs);
        mutex->unlock();
    }

    void Release()
    {
        mutex->lock();
        --(*refs);
        if (*refs == 0)
        {
            delete pointee;
            delete refs;
            mutex->unlock();
            delete mutex;
        }
        else mutex->unlock();
    }
};

class MemCounter
{
public:
    MemCounter() : counter_(0) {}

    void inc(int32_t count) 
    {
        MutexGuard mutexGuard(mutex_);
        counter_+=count;
    }
    
    void dec(int32_t count) 
    {
        MutexGuard mutexGuard(mutex_);
        counter_-=count; 
        if (counter_ < 0) counter_ = 0;
    }
    
    int32_t size() 
    {
        MutexGuard mutexGuard(mutex_);
        return counter_;
    }
    
private:
    int32_t counter_;
    Mutex mutex_;
};

class MediaFrame 
{
public:

    enum MEDIA_TYPE {AUDIO, VIDEO};

    MediaFrame(unsigned char* pData, unsigned long size_of_data, MemCounter *mc = NULL) 
        : data(pData), size(size_of_data), type(0), markJump(false), num(0), mc_(mc)
    {}

    ~MediaFrame()
    {
        if (mc_)
            mc_->dec(size);
        
        if (data)
            free(data);
    }
    
    /**
     * Pointer to stored frame
    */
    unsigned char *data;
    
    /**
     * Size of stored frame
    */
    unsigned long size; 

    /**
     * Type of frame (AUDIO/VIDEO)
    */
    MEDIA_TYPE mediaType;
    
    /**
     * Size of allocated memory for frame (helper variable for core needs)
    */
    unsigned allocSize; 
    
    /**
     * Time of received frame
    */
    struct timeval tv; /* received time*/
    
    /**
     * Frame type (0-I, 1-P, 2-B)
    */
    unsigned short type;
    
    /**
     * 
    */
    bool markJump;
    
    /**
     * objects tracking data in binary format
     */
    std::string objectsData;

    unsigned long num;

private:
    MemCounter *mc_;
    
};

typedef ACE_Refcounted_Auto_Ptr<MediaFrame, ACE_Thread_Mutex> CPMediaFrame;

//typedef c_ptr<MediaFrame> CPMediaFrame; 

}}

#endif /* C_PTR */

