#include "asffmt.h"
#include <utils.h>
#include <iostream>

#define Debug if(0)
using namespace std;

packet_header::packet_header(const unsigned char* memory, int size)
{
    if(memory[0]!=0x82)
    {
	cout<<"WARNING: unexpected packet header"<<endl;
	avi_usleep(50000);
	length=0xFF;
	return;
    }
    length=11;
    type=memory[0];
    flags=memory[3];
    segtype=memory[4];
    memory+=5;
    int padding=0;
    if(flags&0x40){size=*(const unsigned short*)memory;memory+=2;length+=2;}
    if(flags&0x10){padding+=*(const short*)memory;memory+=2;length+=2;}
    if(flags&0x8){padding+=*memory++;length++;}
    send_time=*(const int*)memory; memory+=4;
    duration=*(const unsigned short*)memory; memory+=2;
    if(flags&0x1)
    {
	segments=*memory;
	segsizetype=segments & 0xC0;
	segments&=0x3F;
	length++;
    }
    else
    {
	segments=1;
	segsizetype=0x80;
    }
    packet_length=size-length-padding;
    Debug cout<<"Created packet header for send_time "<<send_time/1000.
	<<", length "<<packet_length<<", "<<(int)segments<<" segments"<<endl;
}

segment_header::segment_header(const unsigned char* memory, int offset,
			       const packet_header& header,
			       vector<fragment>& fragments)
{
    if(header.type!=0x82)
    {
	cout<<"WARNING: unexpected packet header"<<endl;
	length=-1;
	return;
    }
    const unsigned char* memory2=memory+offset;
    keyframe=(memory2[0] & 0x80)?1:0;
    stream_id=memory2[0] & 0x7f;
    seq_num=memory2[1];
    int third_field=0;
    int off=2;
    switch(header.segtype)
    {
    case 0x55:
	third_field=memory2[2];
	off=3;
	break;
    case 0x59:
	third_field=*(const short*)&memory2[2];
	off=4;
	break;
    case 0x5d:
	third_field=*(const int*)&memory2[2];
	off=6;
	break;
    };
    flags=memory2[off++];
    fragment f;
    f.keyframe=keyframe;
    f.stream_id=stream_id;
    f.seq_num=seq_num;
    if(flags == 0x08) // no grouping
    {
	f.fragment_offset=fragment_offset=third_field;
	f.object_length=*(const int*)(&memory2[off]);
	off+=4;
	f.object_start_time=object_start_time=*(const int*)(&memory2[off]);
	off+=4;
	if(header.flags & 0x01)
	{
	    if(header.segsizetype==0x80)
	    {
		f.data_length=*(const unsigned short*)(&memory2[off]);
		if(
		   (header.packet_length-offset<f.data_length) ||
		   (f.data_length<0) )
		{
		    length=-1;
		    cout<<"WARNING: Invalid fragment data length "<<f.data_length<<endl;
		    return;
		}
		f.pointer=offset+off+2;
	    }
	    else
	    {
		f.data_length=*(const unsigned char*)(&memory2[off]);
		if(
		   (header.packet_length-offset<f.data_length) ||
		   (f.data_length<0) )
		{
		    length=-1;
		    cout<<"WARNING: Invalid fragment data length "<<f.data_length<<endl;
		    return;
		}
		f.pointer=offset+off+1;
	    }
	}
	else
	{
	    f.data_length=header.packet_length-off;
	    f.pointer=offset+off;
	}
	//	    f.pointer=offset+15;
	//	    data.push_back(o);
	fragments.push_back(f);
	length=f.pointer+f.data_length-offset;
    }
    else if(flags == 0x01) // can this happen with segtype!=0x5d?
	// not sure how to handle this
    {
	fragment_offset=0;
	f.fragment_offset=0;
	f.object_start_time=object_start_time=third_field;
	off++;
	int length2;
	if(header.flags & 0x01)
	{
	    length2=*(const short*)(&memory2[off]);
	    off+=2;
	    if(length2>header.packet_length)
	    {
		cout<<"WARNING: segment length overflow"<<endl;
		offset+=length2;//signals above about occurred problem
		return;
	    }
	    length=length2+off;
	    offset+=off;
	}
	else
	{
	    length2=header.packet_length-off;
	    length=length2+off;
	    offset+=off;
	}
	while(length2>0)
	{
	    f.object_length=f.data_length=memory[offset];
	    f.pointer=offset+1;
	    offset+=f.data_length+1;
	    length2-=f.data_length+1;
	    fragments.push_back(f);
	}
    }
    else
    {
	cout<<"WARNING: unexpected segment flags "<<(int)flags<<endl;
	length=-1;
	return;
    }
    Debug cout<<"Created segment header for stream "<<(int)stream_id<<", "
	<<fragments.size()<<" fragments"<<endl;
}

packet::packet(size_t psize)
    :std::vector<unsigned char>(psize)
{
}

void packet::init()
{
    segments.clear();
    const unsigned char* data_start=&((*this)[0]);
    hdr=packet_header(data_start, size());
    unsigned int offset=hdr.length;
    if (offset==0xFF)
	return; //packet creation failed
    for(int i=0; i<hdr.segments; i++)
    {
	segments.push_back(segment_header(data_start, offset, hdr, fragments));
	if(segments.back().length<0)
	{
	    hdr.segments=i;
	    segments.pop_back();
	    break;
	}
	offset+=segments.back().length;
	if(offset>size())
	{
	    cout<<"WARNING: packet size overflow"<<endl;
	    hdr.segments=i;
	    segments.pop_back();
	    break;
	}
    }
}
