/* ------------------------------------------------------------------
 * 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.
 * -------------------------------------------------------------------
 */
/*********************************************************************************/
/*     -------------------------------------------------------------------       */
/*                            MPEG-4 TrackAtom Class                             */
/*     -------------------------------------------------------------------       */
/*********************************************************************************/
/*
    This TrackAtom Class is the container for a single track in the MPEG-4
    presentation.
*/

#define IMPLEMENT_TrackAtom

#include "movieatom.h"
#include "trackatom.h"
#include "atomdefs.h"
#include "atomutils.h"

OSCL_EXPORT_REF  uint8 TrackAtom::getObjectTypeIndication()
{
    if (_pmediaAtom != NULL)
    {
        return _pmediaAtom->getObjectTypeIndication();
    }
    else
    {
        return 0xFF;
    }
} // Based on OTI value

// Constructor
TrackAtom::TrackAtom(MP4_FF_FILE *fp,
                     OSCL_wString& filename,
                     uint32 size,
                     uint32 type,
                     bool oPVContent,
                     bool oPVContentDownloadable,
                     uint32 parsingMode,
                     bool aOpenFileOncePerTrack)
        : Atom(fp, size, type)
        , _puserdataatom(0)
        , _pEditAtom(0)
        , _ptrackHeader(0)
        , _ptrackReference(0)
        , _pmediaAtom(0)
        , _pMediaType(0xFFFFFFFF)
{


    if (_success)
    {
        // Generalized so can read in atoms in ANY ORDER!
        _pparent = NULL;
        _ptrackReference = NULL;

        uint32 atomType = UNKNOWN_ATOM;
        uint32 atomSize = 0;

        int32 count = _size - DEFAULT_ATOM_SIZE;

        while (((atomType == TRACK_REFERENCE_ATOM) ||
                (atomType == TRACK_HEADER_ATOM) ||
                (atomType == MEDIA_ATOM) ||
                (atomType == USER_DATA_ATOM) ||
                (atomType == EDIT_ATOM) ||
                (atomType == FREE_SPACE_ATOM) ||

                (atomType == UUID_ATOM) ||
                (atomType == UNKNOWN_ATOM) ||
                (atomType == META_DATA_ATOM))
                && (count > 0))
        {
            AtomUtils::getNextAtomType(fp, atomSize, atomType);

            if (atomType == EDIT_ATOM)
            {
                PV_MP4_FF_NEW(fp->auditCB, EditAtom, (fp, atomSize, atomType), _pEditAtom);

                if (!_pEditAtom->MP4Success())
                {
                    _success = false;
                    _mp4ErrorCode = _pEditAtom->GetMP4Error();
                    break;
                }

                count -= _pEditAtom->getSize();
            }
            else if ((atomType == FREE_SPACE_ATOM)
                     || (atomType == UUID_ATOM)
                     || (atomType == UNKNOWN_ATOM)
                     || (atomType == META_DATA_ATOM))
            {
                if (atomSize < DEFAULT_ATOM_SIZE)
                {
                    _success = false;
                    _mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE;
                    break;
                }
                if (count < (int32)atomSize)
                {
                    _success = false;
                    _mp4ErrorCode = READ_FAILED;
                    break;
                }
                count -= atomSize;
                atomSize -= DEFAULT_ATOM_SIZE;
                AtomUtils::seekFromCurrPos(fp, atomSize);
            }
            else if (atomType == USER_DATA_ATOM)
            {
                if (oPVContent)
                {
                    if (_puserdataatom == NULL)
                    {
                        PV_MP4_FF_NEW(fp->auditCB, UserDataAtom, (fp, atomSize, atomType), _puserdataatom);
                        if (!_puserdataatom->MP4Success())
                        {
                            _success = false;
                            _mp4ErrorCode = _puserdataatom->GetMP4Error();
                            break;
                        }
                        count -= _puserdataatom->getSize();
                    }
                    else
                    {
                        _success = false;
                        _mp4ErrorCode = READ_USER_DATA_ATOM_FAILED;
                        break;
                    }
                }
                else
                {
                    //Skip third party user data atom
                    if (atomSize < DEFAULT_ATOM_SIZE)
                    {
                        _success = false;
                        _mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE;
                        break;
                    }
                    if (count < (int32)atomSize)
                    {
                        _success = false;
                        _mp4ErrorCode = READ_FAILED;
                        break;
                    }
                    count -= atomSize;
                    atomSize -= DEFAULT_ATOM_SIZE;
                    AtomUtils::seekFromCurrPos(fp, atomSize);
                }
            }
            else if (atomType == TRACK_REFERENCE_ATOM)
            {
                // tref
                if (_ptrackReference != NULL)
                {
                    _success = false;
                    _mp4ErrorCode = DUPLICATE_TRACK_REFERENCE_ATOMS;
                    break;
                }
                PV_MP4_FF_NEW(fp->auditCB, TrackReferenceAtom, (fp, atomSize, atomType), _ptrackReference);
                if (!_ptrackReference->MP4Success())
                {
                    _success = false;
                    _mp4ErrorCode = _ptrackReference->GetMP4Error();
                    break;
                }
                _ptrackReference->setParent(this);
                count -= _ptrackReference->getSize();
            }
            else if (atomType == TRACK_HEADER_ATOM)
            {
                // tkhd
                if (_ptrackHeader != NULL)
                {
                    _success = false;
                    _mp4ErrorCode = DUPLICATE_TRACK_HEADER_ATOMS;
                    break;
                }
                PV_MP4_FF_NEW(fp->auditCB, TrackHeaderAtom, (fp, atomSize, atomType), _ptrackHeader);

                if (!_ptrackHeader->MP4Success())
                {
                    _success = false;
                    _mp4ErrorCode = _ptrackHeader->GetMP4Error();
                    break;
                }
                _ptrackHeader->setParent(this);
                count -= _ptrackHeader->getSize();
            }
            else if (atomType == MEDIA_ATOM)
            {   // mdia
                if (_pmediaAtom != NULL)
                {
                    _success = false;
                    _mp4ErrorCode = DUPLICATE_MEDIA_ATOMS;
                    break;
                }
                PV_MP4_FF_NEW(fp->auditCB, MediaAtom, (fp, filename, atomSize, atomType,
                                                       oPVContentDownloadable, parsingMode, aOpenFileOncePerTrack), _pmediaAtom);

                if (!_pmediaAtom->MP4Success())
                {
                    _success = false;
                    _mp4ErrorCode = _pmediaAtom->GetMP4Error();
                    break;
                }
                _pmediaAtom->setParent(this);
                count -= _pmediaAtom->getSize();
            }
        }

        if (_success)
        {
            if (NULL == _ptrackHeader)
            {
                _success = false;
                _mp4ErrorCode = NO_TRACK_HEADER_ATOM_PRESENT;
                return;
            }

            if (NULL == _pmediaAtom)
            {
                _success = false;
                _mp4ErrorCode = NO_MEDIA_ATOM_PRESENT;
                return;
            }
            _pMediaType =
                AtomUtils::getMediaTypeFromHandlerType(_pmediaAtom->getMediaHandlerType());
        }
    }
    else
    {
        _mp4ErrorCode = READ_TRACK_ATOM_FAILED;
    }
}

int32 TrackAtom::NEWsetTrackTSOffset(uint32 ts)
{
    if (_pmediaAtom != NULL)
    {
        if (_pEditAtom != NULL)
        {
            uint32 initTimeOffset = (uint32)(_pEditAtom->getInitialTimeOffset());

            float fTS = (float)_pmediaAtom->getMediaTimescale();
            fTS *= (float)initTimeOffset;
            fTS /= (float)ts;
            _pmediaAtom->setTrackTSOffset((uint32)(fTS));
        }
    }
    return EVERYTHING_FINE;
}

int32 TrackAtom::getTrackTSOffset(uint32& aTSOffset, uint32 aMovieTimeScale)
{
    aTSOffset = 0;
    if (_pmediaAtom != NULL)
    {
        if (_pEditAtom != NULL)
        {
            uint32 initTimeOffset = (uint32)(_pEditAtom->getInitialTimeOffset());

            float fTS = (float)_pmediaAtom->getMediaTimescale();
            fTS *= (float)initTimeOffset;
            fTS /= (float)aMovieTimeScale;
            aTSOffset = (uint32)(fTS);
        }
    }
    return EVERYTHING_FINE;
}

// Destructor
TrackAtom::~TrackAtom()
{
    if (_ptrackHeader != NULL)
        PV_MP4_FF_DELETE(NULL, TrackHeaderAtom, _ptrackHeader);

    if (_pmediaAtom != NULL)
        PV_MP4_FF_DELETE(NULL, MediaAtom, _pmediaAtom);

    if (_puserdataatom != NULL)
        PV_MP4_FF_DELETE(NULL, UserDataAtom, _puserdataatom);

    if (_ptrackReference != NULL)
        PV_MP4_FF_DELETE(NULL, TrackReferenceAtom, _ptrackReference);

    if (_pEditAtom != NULL)
        PV_MP4_FF_DELETE(NULL, EditAtom, _pEditAtom);
}






