#include <config.h>
#include <default.h>
#include "AviSegWrite.h"

#undef __MODULE__
#define __MODULE__ "AviSegWriteFile"

#include <iostream>
using namespace std;


AviSegWriteFile::AviSegWriteFile(const char* name, size_t flimit, int flags, int mask)
    :_name(name), _flags(flags), _mask(mask), m_lFlimit(flimit), _size(0LL)
{
    rf=new AviWriteFile(name, flags, mask);
}

AviSegWriteFile::~AviSegWriteFile()
{
    if (rf)
	delete rf;
    vector<streaminfo>::iterator it;
    for(it=m_streams.begin(); it!=m_streams.end(); it++)
	if(it->state==streaminfo::Common)
	    delete it->format;
}

void AviSegWriteFile::Segment()
{
    _size+=rf->FileSize();
    delete rf;
    if(_name.length()<6)
	_name="_____"+_name;
    string::size_type st=_name.find_last_of(".avi");
    if(st==string::npos)
	_name+=".0.avi";
    else
    {
	if(_name[st-5]=='.')
	{
	    char& newval=_name[st-4];
	    if(newval=='9')
		newval='a';
	    else
		newval++;
	}
	else
	    _name.insert(st-3, ".0");
    }
    cerr<<"New file: "<<_name<<endl;
    rf = new AviWriteFile(_name.c_str(), _flags, _mask);
    vector<streaminfo>::iterator it;
    for (it = m_streams.begin(); it != m_streams.end(); it++)
    {
	if (it->state==streaminfo::Video)
	{
	    IAviVideoWriteStream* realstream =
		rf->AddVideoStream(it->fourcc, &it->hdr, it->frame_rate, it->flags);
	    it->vstream->SetRealStream(realstream);
	}
	else if (it->state==streaminfo::Audio)
	{
	    IAviAudioWriteStream* realstream =
		rf->AddAudioStream(it->fourcc, (WAVEFORMATEX*)it->format,
				   it->frame_rate, it->flags);
	    it->astream->SetRealStream(realstream);
	}
	else
	{
	    IAviWriteStream* realstream =
		rf->AddStream(it->type,	it->format, it->format_size,
			      it->fourcc, it->frame_rate, it->samplesize,
			      it->quality, it->flags);
	    it->stream->SetRealStream(realstream);
	}
    }
}

IAviVideoWriteStream* AviSegWriteFile::AddVideoStream(fourcc_t fourcc,
						      BITMAPINFOHEADER* srchdr,
						      int frame_rate, int flags)
{
    if (!srchdr)
	return 0;

    streaminfo str;
    str.state=streaminfo::Video;
    str.fourcc=fourcc;
    str.hdr=*srchdr;
    str.frame_rate=frame_rate;
    str.flags=flags;
    IAviVideoWriteStream* vs=rf->AddVideoStream(fourcc, srchdr, frame_rate, flags);
    str.vstream=new AviVideoSegWriteStream(this, vs);
    m_streams.push_back(str);

    return str.vstream;
}

IAviAudioWriteStream* AviSegWriteFile::AddAudioStream(fourcc_t fourcc,
						      WAVEFORMATEX* fmt,
						      int bitrate, int flags)
{
    if (!fmt)
	return 0;

    streaminfo str;
    str.state = streaminfo::Audio;
    str.fourcc = fourcc;
    str.format_size = 18+fmt->cbSize;
    str.format = new uint8_t[18+fmt->cbSize];
    memcpy(str.format, fmt, str.format_size);
    str.frame_rate = bitrate;
    str.flags = flags;
    IAviAudioWriteStream* vs = rf->AddAudioStream(fourcc, fmt, bitrate, flags);
    str.astream = new AviAudioSegWriteStream(this, vs);
    m_streams.push_back(str);

    return str.astream;
}

IAviWriteStream* AviSegWriteFile::AddStream(enum AviStream::StreamType type,
					    const void* format, size_t format_size,
					    fourcc_t handler, int frame_rate,
					    size_t samplesize,
					    int quality, int flags)
//IAviWriteStream* AviSegWriteFile::AddStream(enum AviStream::StreamType type)
{
    streaminfo str;
    str.state=streaminfo::Common;
    str.type=type;
    str.format = new uint8_t[format_size];
    memcpy(str.format, format, format_size);
    str.format_size=format_size;
    str.fourcc=handler;
    str.frame_rate=frame_rate;
    str.samplesize=samplesize;
    str.quality=quality;
    str.flags=flags;
    IAviWriteStream* vs=rf->AddStream(type, format, format_size, handler,
				      frame_rate, samplesize, quality, flags);
    str.stream=new AviSegWriteStream(this, vs);
    m_streams.push_back(str);
    return str.stream;
}




IAviSegWriteFile* CreateSegmentedFile(const char* name, size_t flimit,
				      int flags, int mask)
{
    return new AviSegWriteFile(name, flimit, flags, mask);
}


AviSegWriteStream::AviSegWriteStream(AviSegWriteFile* file, IAviWriteStream* stream)
    :m_pStream(stream), m_pFile(file), _format(0)
{
    //
}

AviSegWriteStream::~AviSegWriteStream()
{
    if (_format)
	delete _format;
}


void AviSegWriteStream::SetRealStream(IAviWriteStream* pStream)
{
//    pStream->SetHeader(_handler, _frame_rate, _samplesize, _quality, _flags);
//    pStream->SetFormat(_format, _format_size);
    m_pStream=pStream;
}


HRESULT AviSegWriteStream::AddChunk(const void* chunk, size_t size, int flags)
{
    HRESULT result=m_pStream->AddChunk(chunk, size, flags);
    if(m_pFile->rf->FileSize()>m_pFile->m_lFlimit)
        m_pFile->Segment();
    return result;
}

HRESULT AviAudioSegWriteStream::AddData(void* chunk, size_t size)
{
    HRESULT result=m_pStream->AddData(chunk,size);
    if (m_pFile->rf->FileSize() > m_pFile->m_lFlimit)
        m_pFile->Segment();
    return result;
}

HRESULT AviVideoSegWriteStream::AddFrame(CImage* chunk, size_t* pSize = 0, int* pKeyframe=0)
{
    HRESULT result=m_pStream->AddFrame(chunk, pSize, pKeyframe);
    if (m_pFile->rf->FileSize() > m_pFile->m_lFlimit)
        m_pFile->Segment();
    return result;
}
