#ifndef AVIFILE_ASFFMT_H
#define AVIFILE_ASFFMT_H

#include <default.h> // int64_t
#include <vector>
#include <com.h>

#define Debug if(0)
/*
  Data is stored in ASF packets in a relatively complicated manner
  ( see details in http://divx.euro.ru/asf-1.0.htm ).
  The following objects represent that data in convenient form.

  Procedure of accessing data is as follows:

  int packet_size; //from ASF header
  packet p(packet_size);
  read(fd, &p[0], packet_size);
  p.init(); //processes data and fills packet members
  for(int i=0; i<p.fragments.size(); i++)
    ...
*/

struct packet_header
{
    uint8_t length;		// of header itself
    uint8_t type;		// 1st byte
    uint8_t flags;		// see spec
    uint8_t segtype;
    uint8_t segsizetype;
    uint16_t packet_length;	// of data following header
    uint32_t send_time;		// timestamp in milliseconds
    uint16_t duration;		// in milliseconds
    uint8_t segments;		// number of segments

    packet_header(){}
    packet_header(const unsigned char* memory, int size);
};

struct fragment
{
    unsigned char keyframe :1;
    unsigned char stream_id :7;
    unsigned char seq_num;
    unsigned int object_start_time;
    unsigned int fragment_offset; // offset of fragment within object
				// ( needed for reconstruction of fragmented packets )
    unsigned int object_length;	// length of object that this fragment beints to
    unsigned int data_length;	// length of this fragment
    unsigned int pointer;	// offset of fragment within packet
				// first byte of fragment N in packet p
				//   is p[p.fragments[N].pointer]
};

struct segment_header
{
    int length;
    unsigned char keyframe :1;
    unsigned char stream_id :7;
    unsigned char seq_num;
    int fragment_offset;
    unsigned char flags;
    int object_start_time;

    segment_header() {}
    segment_header(const unsigned char* memory, int offset,
		   const packet_header& header,
		   std::vector<fragment>& fragments);
};

struct packet: std::vector<unsigned char>
{
    packet_header hdr;
    std::vector<segment_header> segments;
    std::vector<fragment> fragments;

    packet(size_t psize = 0);
    void init();
};

struct __attribute__((packed)) MainASFHeader
{
//0x0
    GUID guid; //generated by client computer
//0x10 TOTAL_SIZE_8
    uint64_t file_size; //in bytes
//0x18
    uint64_t file_time; //time of creation, in 100-nanosecond units since 1.1.1601
//0x20 NUM_PACKETS
    uint64_t num_packets; //how many packets are there in the file
//0x28 FINE_TOTALTIME
    uint64_t total_time; //end timestamp, in 100-nanosecond units
//0x30 FINE_PLAYTIME
    uint64_t play_time; //file duration, in 100-nanosecond units
//0x38 PLAYTIME_OFFSET
    uint32_t play_start_time; //timestamp of first packet, in milliseconds
//0x3C
    uint32_t unk3; //unknown, maybe reserved ( usually contain 0 )
//0x40 FLAGS
    uint32_t flags; //unknown flags, usually contain 0x02 ( seekable? )
//0x44 CHUNKLENGTH
    uint32_t pktsize; //size of a data packet
//0x48 CHUNKLENGTH_CONFIRM
    uint32_t pktsize_confirm; // the same
    uint32_t frame_size; //uncompressed frame size
};

#ifndef _WAVEFORMATEX_
#define _WAVEFORMATEX_
typedef struct _WAVEFORMATEX {
    short wFormatTag;
    short nChannels;
    int   nSamplesPerSec;
    int   nAvgBytesPerSec;
    short nBlockAlign;
    short wBitsPerSample;
    short cbSize;
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
#endif

union ASFStreamHeader
{
    char buf[1024];
    struct __attribute__((__packed__))
    {
	GUID uid_type;    //audio or video stream
	GUID uid_conceal; //is audio data error concealment used
	int64_t unk1;	//usually 0
	int data_len;   //size of fixed data
	int edata_len;  //data that follows
	unsigned short stream;   //number ( 1, 2 ... )
	int unk2; //usually the same in both streams
		// Eyes on me.asf: 0x62dffd4
		// Alsou - Solo.asf: 0x10
		// Baby one more time.asf: 0x10
		// Cure_LastDayOfSummer.wma: 0x818f900c
		// Windows Movie Maker Sample File.wmv: 0x3f
		// KellssyV_500VBR.wmv: 0x0
        union __attribute__((__packed__))
	{
         struct __attribute__((__packed__))
	 {
	     int32_t width;
	     int32_t height;
	     int8_t  c;
	     int16_t biSize;

	     int32_t biSize2;
	     int32_t biWidth;
	     int32_t biHeight;
	     int16_t biPlanes;
	     int16_t biBitCount;
	     int32_t biCompression;
	     int32_t biSizeImage;
	     int32_t biXPelsPerMeter;
	     int32_t biYPelsPerMeter;
	     int32_t biClrUsed;
	     int32_t biClrImportant;
         } vid;
         struct __attribute__((__packed__))
         {
           WAVEFORMATEX wfex;
          // audio scramble data follows
         } aud;
       };
    } hdr;
};

struct __attribute__((__packed__)) ASFAudioScrambleDef
{
    uint8_t  block_size;	// total number of audio blocks in each scramble group
    uint16_t chunk_size;	// byte size of each scrambling chunk
    uint16_t block_align_1;	// usually = nBlockAlign
    uint16_t block_align_2;	// usually = nBlockAlign
    uint8_t  unk;
};

#endif // AVIFILE_ASFFMT_H
