#include "wine/winreg.h"
#include "wine/vfw.h"
#include "wine/driver.h"

#include "VideoCodec.h"

#include <stdio.h>
using namespace std;

VideoCodec* VideoCodecControl::Create(int compressor, const CodecInfo& info, Module::Mode mode)
{
    //    cerr<<"VideoCodecControl::Create()"<<endl;
    //    cerr<<"_modules size: "<<_modules.size()<<endl;
    list<Module*>::iterator it;
    for (it = _modules.begin(); it!=_modules.end(); it++)
    {
	if ((*it)->Name() == info.dll)
	    return new VideoCodec(*it, compressor, mode);
    }
    Module* module = new Module(info.dll, *this);
    _modules.push_back(module);
    return new VideoCodec(module, compressor, mode);
}

VideoCodecControl::~VideoCodecControl()
{
    list<Module*>::iterator it;
    for (it = _modules.begin(); it != _modules.end(); it++)
    {
	(*it)->ForgetParent();
	// at this time player using this codec has to be stopped
	// currently this is partial responsibility of user task
        // FIXME !!! - destroy codec thread if necessary
	delete *it;
    }
}

void VideoCodecControl::Erase(Module* mod)
{
    //cerr<<"Erasing module "<<(int)mod<<endl;
    list<Module*>::iterator it;
    for (it = _modules.begin(); it != _modules.end(); it++)
	if (*it == mod)
	{
	    _modules.erase(it);
	    //cerr<<"Success: new _modules size "<<_modules.size()<<endl;
	    return;
	}
}

VideoCodec::VideoCodec(Module* module, int compressor, Module::Mode mode)
    :_module(module)
{
    _handle=_module->CreateHandle(compressor, mode);
}

VideoCodec::~VideoCodec()
{
    //    cerr<<"Deleting codec"<<endl;
    _module->CloseHandle(_handle);
}

//
//
//  Here goes VFW API
//
//

HRESULT VideoCodec::GetFormat(BITMAPINFOHEADER* v1,BITMAPINFOHEADER* v2)
{
    return _module->Message(_handle, ICM_COMPRESS_GET_FORMAT, (int)v1, (int)v2);
}

HRESULT VideoCodec::GetDefaultKeyFrameRate(int* lpint)
{
    return _module->Message(_handle, ICM_GETDEFAULTKEYFRAMERATE,
			    (long)(void*)(lpint), 0);
}
HRESULT VideoCodec::GetDefaultQuality(int* lpint)
{
    return _module->Message(_handle, ICM_GETDEFAULTQUALITY,
			    (long)(void*)(lpint), 0);
}

HRESULT VideoCodec::CompressBegin( BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER* lpbiOutput)
{
    return _module->Message(_handle, ICM_COMPRESS_BEGIN,
			    (long)(void*)(lpbiInput), (long)(void*)(lpbiOutput));
}

HRESULT VideoCodec::CompressGetSize( BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER* lpbiOutput)
{
    return _module->Message(_handle,
			    ICM_COMPRESS_GET_SIZE, (long)(void*)(lpbiInput),
			    (long)(void*)(lpbiOutput));
}

HRESULT VideoCodec::CompressQuery( BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER* lpbiOutput)
{
    return _module->Message(_handle,
			    ICM_COMPRESS_QUERY, (long)(void*)(lpbiInput),
			    (long)(void*)(lpbiOutput));
}

HRESULT VideoCodec::CompressEnd()
{
    return _module->Message(_handle, ICM_COMPRESS_END, 0, 0);
}

HRESULT VideoCodec::Compress(long dwFlags,LPBITMAPINFOHEADER lpbiOutput,void* lpData,
			     LPBITMAPINFOHEADER lpbiInput,void* lpBits,long* lpckid,
			     long* lpdwFlags,long lFrameNum,long dwFrameSize,long dwQuality,
			     LPBITMAPINFOHEADER lpbiPrev,void* lpPrev)
{
    ICCOMPRESS	iccmp;
    iccmp.dwFlags	= dwFlags;
    iccmp.lpbiOutput	= lpbiOutput;
    iccmp.lpOutput	= lpData;
    iccmp.lpbiInput	= lpbiInput;
    iccmp.lpInput	= lpBits;

    iccmp.lpckid	= lpckid;
    iccmp.lpdwFlags	= lpdwFlags;
    iccmp.lFrameNum	= lFrameNum;
    iccmp.dwFrameSize	= dwFrameSize;
    iccmp.dwQuality	= dwQuality;
    iccmp.lpbiPrev	= lpbiPrev;
    iccmp.lpPrev	= lpPrev;
    return _module->Message(_handle,ICM_COMPRESS,(long)&iccmp,sizeof(iccmp));
}

HRESULT VideoCodec::DecompressBegin(BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER*  lpbiOutput)
{
    return _module->Message(_handle, ICM_DECOMPRESS_BEGIN, (long)(void*)(lpbiInput),
			    (long)(lpbiOutput));
}

HRESULT VideoCodec::DecompressQuery(BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER* lpbiOutput)
{
    return _module->Message(_handle,ICM_DECOMPRESS_QUERY, (long)(void*)(lpbiInput),
			    (long)(lpbiOutput));
}

HRESULT VideoCodec::DecompressGetFormat(BITMAPINFOHEADER* lpbiInput, BITMAPINFOHEADER* lpbiOutput)
{
    return _module->Message(_handle,ICM_DECOMPRESS_GET_FORMAT, (long)(void*)(lpbiInput),
			    (long)(lpbiOutput));
}

HRESULT VideoCodec::DecompressEnd()
{
    return _module->Message(_handle, ICM_DECOMPRESS_END, 0, 0);
}

HRESULT VideoCodec::Decompress(long dwFlags,LPBITMAPINFOHEADER lpbiFormat,void* lpData,LPBITMAPINFOHEADER  lpbi,void* lpBits)
{
    ICDECOMPRESS	icd;
    int result;
    icd.dwFlags		= dwFlags;
    icd.lpbiInput	= lpbiFormat;
    icd.lpInput		= lpData;

    icd.lpbiOutput	= lpbi;
    icd.lpOutput	= lpBits;
    icd.ckid		= 0;
    STORE_ALL;
    result=_module->Message(_handle,ICM_DECOMPRESS,(long)&icd,sizeof(icd));
    REST_ALL;
    return result;
}

HRESULT VideoCodec::CompressFramesInfo(ICCOMPRESSFRAMES* picf)
{
    HRESULT result=_module->Message(_handle, ICM_COMPRESS_FRAMES_INFO, (long)picf, sizeof(*picf));
    return result;
}

HRESULT VideoCodec::GetInfo(ICINFO *pici)
{
    HRESULT result=_module->Message(_handle, ICM_GETINFO, (long)pici, sizeof(*pici));
    return result;
}
