#ifndef _xbCOMPRESSITF_
#define _xbCOMPRESSITF_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbCompressItf
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _xbSTREAMITF_
#	include "xbStreamItf.h"
#endif

#ifndef _xbEXCEPTION_
#	include "xbException.h"
#endif

#ifndef _xbHOTPLUG_
#	include "xbHotPlug.h"
#endif

enum xbCompressLevel
{
	xbCompressDefault = -1,
	xbCompressHigh = -2,
	xbCompressMid = -3,
	xbCompressLow = -4
};

#define xbCOMPRESSCAPS_FILELIST				0x80000000 //support multiple file in one stream
#define xbCOMPRESSCAPS_FILELIST_ATSTART		0x40000000 //you must write the file list at compression startup (no sense if not used with xbCOMPRESSCAPS_FILELIST)
#define xbCOMPRESSCAPS_HEADERPARAM			0x20000000 //support param list for header
#define xbCOMPRESSCAPS_HEADERPARAM_ATSTART	0x10000000 //you must write the param list for header at start (no sense if not used with xbCOMPRESSCAPS_HEADERPARAM)
#define xbCOMPRESSCAPS_FILEPARAM			0x08000000 //support param list for each file
#define xbCOMPRESSCAPS_FILEPARAM_ATSTART	0x04000000 //you must write the param list for a file when writing file list (no sense if not used with xbCOMPRESSCAPS_FILELIST)

interface xbEXPORT IxbCompressPush;
interface xbEXPORT IxbCompressPull;
interface xbEXPORT IxbDecompressPush;
interface xbEXPORT IxbDecompressPull;
interface __declspec(uuid("{19DA7A35-EC6B-43f8-99E2-9B5722A8F47C}")) 
	xbEXPORT IxbCompressProgress:public IxbObject
{
	virtual void onCompressProgress(IxbCompressPush *pCompPush,IxbCompressPull *pCompPull,LPCSTR pStepLabel,ulong cByteReal,ulong cByteComp,ulong cByteFile) = 0;
};

interface __declspec(uuid("{44E8F821-E7A6-4cfd-A570-3F2B85A70B1A}")) 
	xbEXPORT IxbDecompressProgress:public IxbObject
{
	virtual void onDecompressProgress(IxbDecompressPush *pUncompPush,IxbDecompressPull *pUncompPull,LPCSTR pStepLabel,ulong cByteReal,ulong cByteComp,ulong cByteFile) = 0;
};

interface __declspec(uuid("{21355534-C76D-4a63-A366-72BDC669523A}")) 
	xbEXPORT IxbCompressNotif:public IxbObject
{
	virtual void onCompressFlush(IxbCompressPush *pComp,bool bEnd,bool bClose) = 0;
	virtual void onCompressClose(IxbCompressPush *pComp) = 0;
	virtual void onCompressNewFile(IxbCompressPush *pComp,ulong cp,const xbString &path,ulong length) = 0;
};

interface __declspec(uuid("{42391610-1E85-463e-AA5F-B40C2F8EE128}")) 
	xbEXPORT IxbDecompressNotif:public IxbObject
{
	virtual void onDecompressFlush(IxbDecompressPush *pComp,bool bEnd,bool bClose) = 0;
	virtual void onDecompressClose(IxbDecompressPush *pComp) = 0;
	virtual void onDecompressStart(IxbDecompressPush *pComp) = 0;
	virtual void onDecompressEnd(IxbDecompressPush *pComp,bool bClose) = 0;
	virtual void onDecompressNewFile(IxbDecompressPush *pComp,ulong cp,const xbString &path,ulong length) = 0;
};

interface __declspec(uuid("{7828F262-E188-4d79-9F98-0813775217AB}")) 
	xbEXPORT IxbCompressPush:public IxbOutputStream
{
	virtual xbString GetCompressLabel(bool bShort = true) const = 0;
	virtual bool GetCompressLevelRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool GetCompressBlockRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool EnumCompressSetting(int no, xbString *pName, xbString *pLabel, int *pMin, int *pMax, int *pDflt) const = 0;
	virtual ulong GetCaps() const = 0; //cf xbCOMPRESSCAPS_

	virtual void SetCompressLevel(int compressLevel) = 0;
	virtual int GetCompressLevel() const = 0;
	virtual void SetCompressBlock(int compressBlock) = 0;
	virtual int GetCompressBlock() const = 0;
	virtual bool SetCompressSetting(LPCSTR pszName,int val,xbOpMode opm =xbOp_Required) = 0;
	virtual int GetCompressSetting(LPCSTR pszName,bool *pbExist = NULL) const = 0;
	virtual void ResetCompressSettings(int compressLevel = xbCompressDefault) = 0;

	virtual ulong GetMemoryUsage() const = 0;
	virtual bool GetIOstat(ulong *pcByteReal,ulong *pcByteComp) const = 0;
	virtual void ResetIOstat() = 0;

	virtual void SetCodePage(ulong cp) = 0;
	virtual ulong GetCodePage() const = 0;

	virtual void New(IxbOutputStream *pStm) = 0;
	virtual void SetProgressCb(IxbCompressProgress *pProgressCb) = 0;
	virtual void SetNotifCb(IxbCompressNotif *pNotifCb) = 0;
	virtual bool GetOutputStream(xbRefPtr<IxbOutputStream> *pprStm,xbOpMode opm =xbOp_Required) = 0;
	virtual void CompressFlush() = 0;
	virtual void Close(bool bFreeMem = true) = 0;
	virtual bool IsCompressStarted() const = 0;

	virtual bool NewFile(const xbString &path,ulong length = -1,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0; //return false if file is already in list, in this case seek only 
	virtual bool EnumFile(int no, xbString *pPath, ulong *pLength,ulong cp = CP_ACP) const = 0;
	virtual int GetFileCount() const = 0;
	virtual bool GetFileParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumFileParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
	virtual bool AddFileParam(const xbString &name, const xbString &val,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0;

	virtual bool GetHeaderParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumHeaderParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
	virtual bool AddHeaderParam(const xbString &name, const xbString &val,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0;

	virtual void SetOutputStream(IxbOutputStream *pStm) = 0;
};

interface __declspec(uuid("{7EEF3E5B-5B3E-4d50-9FCF-9DE050EF688D}")) 
	xbEXPORT IxbCompressPull:public IxbInputStream
{
	virtual xbString GetCompressLabel(bool bShort = true) const = 0;
	virtual bool GetCompressLevelRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool GetCompressBlockRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool EnumCompressSetting(int no, xbString *pName, xbString *pLabel, int *pMin, int *pMax, int *pDflt) const = 0;
	virtual ulong GetCaps() const = 0; //cf xbCOMPRESSCAPS_

	virtual void SetCompressLevel(int compressLevel) = 0;
	virtual int GetCompressLevel() const = 0;
	virtual void SetCompressBlock(int compressBlock) = 0;
	virtual int GetCompressBlock() const = 0;
	virtual bool SetCompressSetting(LPCSTR pszName,int val,xbOpMode opm =xbOp_Required) = 0;
	virtual int GetCompressSetting(LPCSTR pszName,bool *pbExist = NULL) const = 0;
	virtual void ResetCompressSettings(int compressLevel = xbCompressDefault) = 0;

	virtual ulong GetMemoryUsage() const = 0;
	virtual bool GetIOstat(ulong *pcByteReal,ulong *pcByteComp) const = 0;
	virtual void ResetIOstat() = 0;

	virtual void SetCodePage(ulong cp) = 0;
	virtual ulong GetCodePage() const = 0;

	virtual void New() = 0;
	virtual void SetInputStream(IxbInputStream *pFileStm) = 0;
	virtual void SetProgressCb(IxbCompressProgress *pProgressCb) = 0;
	virtual bool GetInputStream(xbRefPtr<IxbInputStream> *pprStm,xbOpMode opm =xbOp_Required) = 0;
	virtual void CompressFlush() = 0;
	virtual void Close(bool bFreeMem = true) = 0;
	virtual bool IsCompressStarted() const = 0;

	virtual bool NewFile(const xbString &path,ulong length = -1,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0; //return false if file is already in list, in this case seek only 
	virtual bool EnumFile(int no, xbString *pPath, ulong *pLength,ulong cp = CP_ACP) const = 0;
	virtual int GetFileCount() const = 0;
	virtual bool GetFileParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumFileParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
	virtual bool AddFileParam(const xbString &name, const xbString &val,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0;

	virtual bool GetHeaderParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumHeaderParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
	virtual bool AddHeaderParam(const xbString &name, const xbString &val,ulong cp = CP_ACP,xbOpMode addopm =xbOp_Required) = 0;
};

interface __declspec(uuid("{84A2CC4D-6420-4994-AEF2-44C4ECDCEA1C}")) 
	xbEXPORT IxbDecompressPull:public IxbInputStream
{
	virtual xbString GetCompressLabel(bool bShort = true) const = 0;
	virtual ulong GetCaps() const = 0; //cf xbCOMPRESSCAPS_

	virtual ulong GetMemoryUsage() const = 0;
	virtual bool GetIOstat(ulong *pcByteReal,ulong *pcByteComp) const = 0;
	virtual void ResetIOstat() = 0;

	virtual ulong GetCodePage() const = 0;

	virtual void New(IxbInputStream *pStm) = 0;
	virtual void SetProgressCb(IxbDecompressProgress *pProgressCb) = 0;
	virtual bool GetInputStream(xbRefPtr<IxbInputStream> *pprStm,xbOpMode opm =xbOp_Required) = 0;
	virtual void Close(bool bFreeMem = true) = 0;
	virtual bool IsDecompressStarted() const = 0;

	virtual bool SeekFile(const xbString &path,ulong *pLength = NULL,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) = 0;
	virtual bool EnumFile(int no, xbString *pPath, ulong *pLength,ulong cp = CP_ACP) const = 0;
	virtual int GetFileCount() const = 0;
	virtual bool GetFileParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumFileParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;

	virtual bool GetHeaderParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumHeaderParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
};

interface __declspec(uuid("{703390AA-1CA5-4b57-BC06-9D88E45B1A42}")) 
	xbEXPORT IxbDecompressPush:public IxbOutputStream
{
	virtual xbString GetCompressLabel(bool bShort = true) const = 0;
	virtual ulong GetCaps() const = 0; //cf xbCOMPRESSCAPS_

	virtual ulong GetMemoryUsage() const = 0;
	virtual bool GetIOstat(ulong *pcByteReal,ulong *pcByteComp) const = 0;
	virtual void ResetIOstat() = 0;

	virtual ulong GetCodePage() const = 0;

	virtual void New() = 0;
	virtual void SetOutputStream(IxbOutputStream *pFileStm) = 0;
	virtual void SetProgressCb(IxbDecompressProgress *pProgressCb) = 0;
	virtual void SetNotifCb(IxbDecompressNotif *pNotifCb) = 0;
	virtual bool GetOutputStream(xbRefPtr<IxbOutputStream> *pprStm,xbOpMode opm =xbOp_Required) = 0;
	virtual void DecompressFlush() = 0;
	virtual void Close(bool bFreeMem = true) = 0;
	virtual bool IsDecompressStarted() const = 0;

	virtual bool EnumFile(int no, xbString *pPath, ulong *pLength,ulong cp = CP_ACP) const = 0;
	virtual int GetFileCount() const = 0;
	virtual bool GetFileParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumFileParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;

	virtual bool GetHeaderParam(const xbString &name, xbString *pVal,ulong cp = CP_ACP,xbOpMode opm =xbOp_Required) const = 0;
	virtual bool EnumHeaderParam(int no, xbString *pName, xbString *pVal,ulong cp = CP_ACP) const = 0;
};

interface __declspec(uuid("{F786CCBB-59DE-46a9-BA9C-AAB00C225E67}")) 
	xbEXPORT IxbCompressPlug:public IxbObject
{
	virtual bool CanWorkWithType(LPCSTR pszType, IxbInputStream *pStm) const = 0;

	virtual bool Decompress(IxbInputStream *pStm, ulong caps, xbRefPtr<IxbDecompressPull> *pprUncompStm,xbOpMode opm =xbOp_Required) = 0;
	virtual bool Decompress(IxbOutputStream *pStm, ulong caps, xbRefPtr<IxbDecompressPush> *pprUncompStm,xbOpMode opm =xbOp_Required) = 0;
	virtual bool Compress(IxbOutputStream *pStm, ulong caps, xbRefPtr<IxbCompressPush> *pprCompStm,xbOpMode opm =xbOp_Required) = 0;
	virtual bool Compress(IxbInputStream *pStm, ulong caps, xbRefPtr<IxbCompressPull> *pprCompStm,xbOpMode opm =xbOp_Required) = 0;

	virtual void askClose(LPCSTR pReason) = 0;

	virtual xbString GetCompressLabel(bool bShort = true) const = 0;
	virtual bool GetCompressLevelRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool GetCompressBlockRange(int *pMin, int *pMax, int *pDflt) const = 0;
	virtual bool EnumCompressSetting(int no, xbString *pName, xbString *pLabel, int *pMin, int *pMax, int *pDflt) const = 0;
	virtual ulong GetCaps() const = 0;

	virtual xbString	getCloseReason() const = 0;
	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getCloseReason());
		if (ret.IsEmpty())
			return ret;
		return "(reason: "+ret+(bLfAfter?")\n":")");
	}
};

//Exception xbEcompress: to use by compression system
xbEdclStart(xbEcompress,xbEadv,{12719A9F-7E5C-4a1e-87B6-1A61CE575D81},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Compression system error";} 
xbEdclEnd(xbEcompress);

//Exception xbEcompressUser: to use by compression system to signal user error
xbEdclStart(xbEcompressUser,xbEcompress,{A560717D-576E-4de0-AAD4-FAF81E21BB35},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Compression error";} 
xbEdclEnd(xbEcompressUser);

//Exception xbEcompressCorrupt: to use by compression system to signal corrupted data/stream
xbEdclStart(xbEcompressCorrupt,xbEcompress,{D2326695-CB2D-4837-B615-C23F8ADE8CC5},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Compressed stream corrupted";} 
xbEdclEnd(xbEcompressCorrupt);

class xbEXPORT  __declspec(uuid("{212D3C18-35FF-492a-979E-54A3B2A494EF}"))
	xbCompressPlugType:public xbHotPlugType
{
public:
	xbCompressPlugType(const char *pPlugTypeName,const char *pPlugTypeVer,const char *pLabel,const xbEngines &engUsed = xbEngines())
		:xbHotPlugType(pPlugTypeName,pPlugTypeVer,pLabel,engUsed)
	{
	}
	virtual ~xbCompressPlugType()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbCompressPlugType);
		return xbHotPlugType::GetInterface(riid,ppInterf);
	}
//	bool	CreatePluggedObject(const xbString &name,xbRefPtr<IxbCompressPlug> *pprObj,xbRefPtr<IxbHotPlugin> *pprPlugin = NULL);
	int		GetSupportedEncoding(xbArray<xbString> *pArrEncode);

//	bool	CanWorkWith(IxbHotPlugin *pObj,const xbString &name);
protected:
	static int PrioritySort(const Object &obj1,const Object &obj2);
/*	bool	CreatePluggedObject(sIxbPlugPtr *pPtr,const xbString &name)
	{
		return xbHotPlugType::CreatePluggedObject(pPtr,name);
	}
	bool	CreatePluggedObject(const xbString &name,xbRefPtr<IxbObject> *pprObj,xbRefPtr<IxbHotPlugin> *pprPlugin)
	{
		return xbHotPlugType::CreatePluggedObject(name,pprObj,pprPlugin);
	}*/
};

xbEXPORT extern xbExtraMsg			g_xbCompressPlugMsg;
xbEXPORT extern xbCompressPlugType	g_xbCompressPlugType;


template<class base> class
	xbLZSSnotif:public base,public IxbCompressProgress,public IxbDecompressProgress,
				public IxbCompressNotif,public IxbDecompressNotif
{
public:
	xbLZSSnotif(bool bCreate = true)
	{
		m_cByteRealTotal = m_cByteCompTotal = 0;
		if (bCreate)
			Create();
	}
	virtual ~xbLZSSnotif()
	{
		eProtectTrace(Destroy());
	}
	void SetRealLength(ulong cByteReal)
	{
		m_cByteRealTotal = cByteReal;
		m_cByteCompTotal = 0;
	}
	void SetCompLength(ulong cByteComp)
	{
		m_cByteRealTotal = 0;
		m_cByteCompTotal = cByteComp;
	}

	xbImplObject();

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IxbCompressProgress);
		xbImplInterface(IxbDecompressProgress);
		xbImplInterface(IxbCompressNotif);
		xbImplInterface(IxbDecompressNotif);
		return base::GetInterface(riid,ppInterf);
	}

	// IxbCompressProgress methods
	virtual void onCompressProgress(IxbCompressPush *pCompPush,IxbCompressPull *pCompPull,LPCSTR pStepLabel,ulong cByteReal,ulong cByteComp,ulong cByteFile)
	{
		ulong cByteTotal,cByteDone;
		if (m_cByteRealTotal > 0) 
		{
			cByteTotal = m_cByteRealTotal;
			cByteDone = cByteReal;
		}
		else
		{
			cByteTotal = m_cByteCompTotal;
			cByteDone = cByteComp;
		}
		double percentDone;
		if (cByteTotal == 0)
			percentDone = 0.0;
		else
		{
			percentDone = double(cByteDone) * 100.0/ double(cByteTotal);
			if (percentDone > 100.0)
				percentDone = 100.0;
		}
		onProgress(pCompPush?(IxbObject*)pCompPush:(IxbObject*)pCompPull,percentDone,pStepLabel,cByteReal,cByteComp,cByteTotal,true);
	}

	// IxbDecompressProgress methods
	virtual void onDecompressProgress(IxbDecompressPush *pUncompPush,IxbDecompressPull *pUncompPull,LPCSTR pStepLabel,ulong cByteReal,ulong cByteComp,ulong cByteFile)
	{
		ulong cByteTotal,cByteDone;
		if (m_cByteRealTotal > 0) 
		{
			cByteTotal = m_cByteRealTotal;
			cByteDone = cByteReal;
		}
		else
		{
			cByteTotal = m_cByteCompTotal;
			cByteDone = cByteComp;
		}
		double percentDone;
		if (cByteTotal == 0)
			percentDone = 0.0;
		else
		{
			percentDone = double(cByteDone) * 100.0/ double(cByteTotal);
			if (percentDone > 100.0)
				percentDone = 100.0;
		}
		onProgress(pUncompPush?(IxbObject*)pUncompPush:(IxbObject*)pUncompPull,percentDone,pStepLabel,cByteReal,cByteComp,cByteTotal,false);
	}

	// IxbCompressNotif
	virtual void onCompressFlush(IxbCompressPush *pComp,bool bEnd,bool bClose)
	{
	}
	virtual void onCompressClose(IxbCompressPush *pComp)
	{
	}
	virtual void onCompressNewFile(IxbCompressPush *pComp,ulong cp,const xbString &path,ulong length)
	{
	}

	// IxbDecompressNotif
	virtual void onDecompressFlush(IxbDecompressPush *pComp,bool bEnd,bool bClose)
	{
	}
	virtual void onDecompressClose(IxbDecompressPush *pComp)
	{
	}
	virtual void onDecompressStart(IxbDecompressPush *pComp)
	{
	}
	virtual void onDecompressEnd(IxbDecompressPush *pComp,bool bClose)
	{
	}
	virtual void onDecompressNewFile(IxbDecompressPush *pComp,ulong cp,const xbString &path,ulong length)
	{
	}

protected:
	virtual void onProgress(IxbObject *pCompressor,double percentDone,LPCSTR pStepLabel,ulong cByteReal,ulong cByteComp,ulong cByteFile,bool bCompress)
	{
	}
	ulong	m_cByteRealTotal,m_cByteCompTotal;
};

#endif
