//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / OVOPS++
//
//File: frame.h
//
//Version: $Revision: 1.9 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/06/23 05:47:57 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Authors:
//      Pasi Nummisalo
//      Juhana Räsänen
//      Sami Raatikainen
//      
//
//Description:
//      Rewritten by SR. The most important difference is "write-bit"
//      which is kind of a token for proxies to have access to write
//      to a shared container. Could have less code, but to maintain
//      interoperability with earlier solutions using previous pfFrame,
//      used interface methods are not removed but changed to apply new
//      implementation.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//      
//Licence:
//     
//
//History:
//
// 

#ifndef __PF_FRAME_H__
#define __PF_FRAME_H__

#include <typeinfo>
#include "pf/types.h"
#include "pf/exception.h"

//
//Class: pfFrame
// 
//Description:
//      See file description.
//

class pfFrame
{
    private:        
        class FrameContainer
        {
            public:
                FrameContainer(pfUlong dataSize_);
                FrameContainer(const FrameContainer &other_);
                virtual ~FrameContainer(void);
                
                pfUlong length(void) const;                
                pfByte read(pfUlong offset_) const;
                void write(pfByte value_, pfUlong offset_);
                void copyData(pfUlong offset_,
                              pfUlong length_,
                              pfByte *destination_) const;
                void copyContainer(pfUlong offset_,
                                   const FrameContainer &other_);
                void incRefCount(void);
                void decRefCount(void);
                int getRefCount(void) const;
                
            private:
                static pfByte *allocateFrameData(pfUlong dataSize_);
                
                pfByte *_data;
                pfUlong _dataSize;
                int _referenceCount;
        };
       
    public:
        static const pfUlong DEFAULT_FRAMESIZE = 4096;

        pfFrame(pfUlong dataSize_ = DEFAULT_FRAMESIZE);
        pfFrame(pfByte *data_, pfUlong length_, pfUlong dataSize_ = 0);
        pfFrame(pfFrame &other_);
        virtual ~pfFrame(void);
        
        const pfFrame& operator=(pfFrame &other_);
        pfUlong length(void) const;

        pfByte read(pfUlong offset_ = 0) const
            throw (pfOutOfRangeException);
        pfUlong read16bit(pfUlong offset_ = 0) const
            throw (pfOutOfRangeException);
        pfUlong read24bit(pfUlong offset_ = 0) const
            throw (pfOutOfRangeException);
        pfUlong read32bit(pfUlong offset_ = 0) const
            throw (pfOutOfRangeException);

        void putFirst(pfByte byte_);
        void putFirst16bit(pfUlong value_);
        void putFirst24bit(pfUlong value_);
        void putFirst32bit(pfUlong value_);
        void putFirst(const pfByte *byte_, pfUlong length_);

        pfByte getFirst(void)
            throw (pfOutOfRangeException);
        pfUlong getFirst16bit(void)
            throw (pfOutOfRangeException);
        pfUlong getFirst24bit(void)
            throw (pfOutOfRangeException);
        pfUlong getFirst32bit(void)
            throw (pfOutOfRangeException);
        
        void putLast(pfByte byte_);
        void putLast16bit(pfUlong value_);
        void putLast24bit(pfUlong value_);
        void putLast32bit(pfUlong value_);
        void putLast(const pfByte *byte_, pfUlong length_);

        pfByte getLast(void)
            throw (pfOutOfRangeException);
        pfUlong getLast16bit(void)
            throw (pfOutOfRangeException);
        pfUlong getLast24bit(void)
            throw (pfOutOfRangeException);
        pfUlong getLast32bit(void)
            throw (pfOutOfRangeException);
        
        pfFrame getSubFrame(pfUlong start_, pfUlong length_) const    
            throw (pfOutOfRangeException);

        void setStart(pfUlong offset_)
            throw (pfOutOfRangeException);

        void copyData(pfByte *destination_) const;
        
    private:        
        FrameContainer *_container;
        pfBoolean _write;        // indicates write access to the container
        pfUlong _beginPointer;   // first data byte in the buffer (0=data[0])
        pfUlong _endPointer;     // next byte (null) after data

        pfBoolean giveWriteBit(void);        

        void write(pfUlong value_, pfUlong length_, pfUlong offset_);

        void giveUpFrameContainer(void);
        void checkBegin(pfUlong length_ = 1);
        void checkEnd(pfUlong length_ = 1);
        void copyIfNecessary(void);        
        void expandBuffer(pfUlong growth_ = 2048);

        static const pfUlong LENGTH_16BIT = 2;
        static const pfUlong LENGTH_24BIT = 3;
        static const pfUlong LENGTH_32BIT = 4;
};

#endif // __PF_FRAME_H__

