#define _LARGEFILE64_SOURCE


/// THIS COMPLETE NIGHTMARE AND HAS TO BE COMPLETELY REWRITTEN
/// I'VE CONSIDERED THAT THIS CODE IS UNMANAGABLE!!!
/// FIXME FIXME FIXME


#include "asffmt.h"
#include "AsfReadHandler.h"
#include "AsfReadStream.h"
#include "AsfInputStream.h"
#include "asf_guids.h"

#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <iostream>
#include <cstdio>

using namespace std;
#define __MODULE__ "AsfReaderHandler"
#pragma pack(1)
int ASF_DEBUG=0;
#undef Debug
#define Debug if(ASF_DEBUG)

ASFReadHandler::ASFReadHandler(const char* pszFile) throw(FatalError)
    :m_pInput(ASFInputStream::create(pszFile))
{
    if (!m_pInput)
	throw FATAL("Could not open file");
    m_Header=m_pInput->getHeader();
    const vector<ASFStreamHeader>& str=m_pInput->getStreams();
    for (unsigned i = 0; i < str.size(); i++)
    {
	// FIXME - do this in thread so we could play instantly
	ASFReadStream tmp(this);
	m_Streams.push_back(tmp);
	ASFReadStream& stream=m_Streams.back();
	stream.m_Header=str[i];
	stream.m_iId=stream.m_Header.hdr.stream; //warning! stream number in packets are 1-based
	stream.m_bIsAudio = (stream.m_Header.hdr.uid_type == guid_audio_stream);
	stream.m_pIterator = m_pInput->getIterator(i);
	stream.m_pSeekInfo = stream.m_pIterator->getSeekInfo();
	stream.m_bIsScrambled = false;
	stream.m_iScrOffset = 0;
	if (stream.m_bIsAudio
	    && (stream.m_Header.hdr.uid_conceal==guid_audio_conceal_interleave))
	{
	    char* tmp=(char*)(&stream.m_Header.hdr.aud.wfex);
	    tmp+=18+stream.m_Header.hdr.aud.wfex.cbSize;
	    stream.m_pScrambleDef=(const ASFAudioScrambleDef*)tmp;
	    //
	    cout<<"Dumping interleave info:\n"
		<< (int)stream.m_pScrambleDef->block_size<<" "
		<< stream.m_pScrambleDef->chunk_size<<" "
		<< stream.m_pScrambleDef->block_align_1<<endl;
	    if ((stream.m_pScrambleDef->block_size!=1)
		&& (stream.m_pScrambleDef->chunk_size/stream.m_pScrambleDef->block_align_1!=1))
	    {
		stream.m_bIsScrambled=true;
		int msize=stream.m_pScrambleDef->chunk_size*stream.m_pScrambleDef->block_size;
		cout<<msize<<endl;
		stream.m_pcScrambleBuf.resize(msize);
		// stream.m_pcScrambleBuf=new char[msize];
		// stream.m_pcScrambleBuf=(char*)malloc(msize);
	    }
	}
    }
}

ASFReadHandler::~ASFReadHandler()
{
    for (unsigned i = 0; i < m_SeekInfo.size(); i++)
	delete m_SeekInfo[i];
    delete m_pInput;
}

IMediaReadStream* ASFReadHandler::GetStream(fourcc_t fccType, streamid_t lParam)
{
    GUID stream_id;

    if (fccType == mmioFOURCC('a', 'u', 'd', 's'))
	stream_id = guid_audio_stream;
    else if (fccType == mmioFOURCC('v', 'i', 'd', 's'))
	stream_id = guid_video_stream;
    else
	return 0;

    streamid_t match = 0;
    for(int i = m_Streams.size()-1; i>=0; i--)
    {
	if (m_Streams[i].m_Header.hdr.uid_type == stream_id)
	{
	    if (match == lParam)
		return &m_Streams[i];
	    match++;
	}
    }
    return 0;
}

HRESULT ASFReadHandler::GetHeader(void* pheader, size_t n) const
{
    return -1;
}

void ASFReadHandler::Interrupt()
{
    return m_pInput->interrupt();
}

double ASFReadStream::CacheSize() const
{
    return m_pParent->m_pInput->cacheSize();
}

bool ASFReadHandler::IsOpened() const
{
    return m_pInput->isOpened();
}

bool ASFReadHandler::IsValid() const
{
    return m_pInput->isValid();
}

bool ASFReadHandler::IsRedirector() const
{
    return m_pInput->isRedirector();
}

bool ASFReadHandler::GetURLs(vector<string>& urls) const
{
    return m_pInput->getURLs(urls);
}

IMediaReadHandler *CreateASFReadHandler(const char *pszFile) throw(FatalError)
{
    return new ASFReadHandler(pszFile);
}
