#ifndef _xdcPicJPEG_PLUG_
#define _xdcPicJPEG_PLUG_
/*<<<***************************************************************************
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.

!! IMPORTANT !!
This plugin/software uses and integrates the following sources which are 
obviously not covered/excluded from this license: 
- Independent JPEG Group's software library 6b used for jpeg support 
	(folder jpeg-6b, see README.txt for license)
- Glenn Randers- Pehrson's libpng-1.2.8
	(folder libpng-128, see LICENSE.txt)
- Jean-loup Gailly/Mark Adler's zlib-1.2.3 for png support and gzip compression
	(folder zlib-123, see README.txt for license)

For this source, please refer to their own license.
////////////////////////////////////////////////////////////////////////////////
#Title: xdcPicJpegPlug
#Project: xdcPicStd
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<14/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#include "jpeg-6b/jpeglib.h"

#define jpg_DEFAULT_COMPRESSION  (25)

class jpegPlug:public xbHotPlugObject<xbObject>,public IgdiCompressPlug
{
public:
	jpegPlug();

	xbImplObject();
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IgdiCompressPlug);

		return xbHotPlugObject<xbObject>::GetInterface(riid,ppInterf);
	}

	xbHotPlugCreateDcl(jpegPlug,IgdiCompressPlug);


	// IgdiCompressPlug methods

	//Auto detection functions
	virtual bool CanWorkWithType(LPCSTR pszType, IxbInputStream *pStm, xbRefPtr<IgdiDecompressor> *pprDecomp = NULL, IgdiImage *pImg = NULL) const;
	virtual bool CanWorkWithType(LPCSTR pszType, const uchar *pStmData, int lgData, int *pLgDataMin, xbRefPtr<IgdiDecompressor> *pprDecomp = NULL, IgdiImage *pImg = NULL) const;

	virtual bool Decompress(ulong caps, xbRefPtr<IgdiDecompressor> *pprUncomp,xbOpMode reqMode = xbOp_Required);
	virtual bool Compress(ulong caps, xbRefPtr<IgdiCompressor> *pprComp,xbOpMode reqMode = xbOp_Required);

	virtual void askClose(LPCSTR pReason);
	virtual xbString getCloseReason() const;

	virtual bool EnumDecompressSetting(int &no, gdiSettingInfo *pInfo) const;

	virtual xbString GetCompressLabel(bool bShort = true,LCID lcid = xbLCID_NEUTRAL) const;
	virtual xbString GetCompressVersion(bool bShort = true,LCID lcid = xbLCID_NEUTRAL) const;
	virtual xbString GetDefaultExtension() const;
	virtual bool GetCompressLevelInfo(gdiSettingInfo *pInfo) const;
	virtual bool EnumCompressSetting(int &no, gdiSettingInfo *pInfo) const;

	virtual gdiCompressCaps GetCaps() const;

protected:
	virtual void onDestruction(bool /*bInDestroy*/);
	void throwEnd(const xbString &strEnd,const xbString &strCtx) const;

	xbString m_closeReason;
};


class jpegCompressor:public xbHotPlugObject<xbObject>,public IgdiCompressor
{
public:
	jpegCompressor();

	xbImplObject();
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IgdiCompressor);
		xbImplInterface(IxbInputStream);

		return xbHotPlugObject<xbObject>::GetInterface(riid,ppInterf);
	}

	static void CreateObject(xbHotPlugFactory *pFactory,xbRefPtr<IgdiCompressor> *ppObj);

	// IgdiCompressor methods
	virtual void NewInput(IgdiImage *pImg);
	virtual void NewInput(IgdiBitmap *pBmp);
	virtual bool GetInput(xbRefPtr<IgdiImage> *pprImg,xbOpMode reqMode = xbOp_Required);
	virtual bool GetInput(xbRefPtr<IgdiBitmap> *pprBmp,xbOpMode reqMode = xbOp_Required);

	virtual void SetCompressLevel(int compressLevel);
	virtual int GetCompressLevel() const;

	virtual bool EnumCompressSetting(int &no, gdiSettingInfo *pInfo) const;

	virtual bool SetCompressSetting(LPCSTR pszName,int intVal,LPCSTR strVal,xbOpMode reqMode = xbOp_Required);
	virtual bool GetCompressSetting(LPCSTR pszName,int *pIntVal,xbString *pStrVal) const;
	virtual void ResetCompressSettings(int compressLevel = gdiCompressDefault);

	virtual void askClose(LPCSTR pReason);
	virtual xbString getCloseReason() const;

	//IxbInputStream methods
	virtual bool			CanRead() const;
	virtual ulong			Read(void *pData,ulong DataLg,bool DataLg_Required = true);

	virtual ulong			ReadString(xbString *pStr,xbString *pStopStr,IxbStreamMode *pMode = NULL);
	virtual ulong			ReadStringW(xbBSTR *pStr,xbBSTR *pStopStr,IxbStreamMode *pMode = NULL);

protected:
	virtual void onDestruction(bool /*bInDestroy*/);
	void throwEnd(const xbString &strEnd,const xbString &strCtx) const;


	bool						m_bJpegInit;
	xbRefPtr<IgdiImage>			m_prImg;
	xbRefPtr<IgdiBitmap>		m_prBmp;
	int							m_compressLevel;

	/* This struct contains the JPEG compression parameters and pointers to
	* working space (which is allocated as needed by the JPEG library).
	* It is possible to have several such structures, representing multiple
	* compression/decompression processes, in existence at once.  We refer
	* to any one struct (and its associated working data) as a "JPEG object".
	*/
	struct jpeg_compress_struct	m_cinfo;
	/* This struct represents a JPEG error handler.  It is declared separately
	* because applications often want to supply a specialized error handler
	* (see the second half of this file for an example).  But here we just
	* take the easy way out and use the standard error handler, which will
	* print a message on stderr and call exit() if compression fails.
	* Note that this struct must live as long as the main JPEG parameter
	* struct, to avoid dangling-pointer problems.
	*/
	struct jpeg_error_mgr		m_jerr;
	xbData						m_resDta;

	void jpegOpen();
	void jpegInit();
	void jpegClose();
	bool jpegRead(int dataLg);

	xbString m_closeReason;
};

class jpegDecompressor:public xbHotPlugObject<xbObject>,public IgdiDecompressor
{
public:
	jpegDecompressor();

	xbImplObject();
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IgdiDecompressor);
		xbImplInterface(IxbOutputStream);

		return xbHotPlugObject<xbObject>::GetInterface(riid,ppInterf);
	}

	static void CreateObject(xbHotPlugFactory *pFactory,xbRefPtr<IgdiDecompressor> *ppObj);


	// IgdiCompressor methods
	virtual void NewOutput(IgdiImage *pImg = NULL,IgdiDecompressorCallBack *pCb = NULL);
	virtual bool GetOutput(xbRefPtr<IgdiImage> *pprImg,xbOpMode reqMode = xbOp_Required);

	virtual bool EnumDecompressSetting(int &no, gdiSettingInfo *pInfo) const;

	virtual bool SetDecompressSetting(LPCSTR pszName,int intVal,LPCSTR strVal,xbOpMode reqMode = xbOp_Required);
	virtual bool GetDecompressSetting(LPCSTR pszName,int *pIntVal,xbString *pStrVal) const;
	virtual void ResetDecompressSettings();

	virtual void askClose(LPCSTR pReason);
	virtual xbString getCloseReason() const;

	//IxbOutputStream methods
	virtual bool			CanWrite() const;
	virtual ulong			Write(const void *pData,ulong DataLg,bool DataLg_Required = true);
	virtual ulong			WriteStream(IxbInputStream *pstm);
	virtual ulong			WriteStream(IxbInputStream *pstm,ulong DataLg,bool DataLg_Required = true);
	virtual ulong			WriteString(const char *pStr,ulong lgStr,bool bAddLf = false,IxbStreamMode *pMode = NULL);
	virtual ulong			WriteStringW(const wchar *pStr,ulong lgStr,bool bAddLf = false,IxbStreamMode *pMode = NULL);
protected:
	virtual void onDestruction(bool /*bInDestroy*/);
	void throwEnd(const xbString &strEnd,const xbString &strCtx) const;

	bool							m_bJpegInit;
	xbRefPtr<IgdiImage>				m_prImg;
	xbRefPtr<IgdiBitmap>			m_prBmp;

	/* This struct contains the JPEG decompression parameters and pointers to
	* working space (which is allocated as needed by the JPEG library).
	*/
	struct jpeg_decompress_struct	m_cinfo;
	/* We use our private extension JPEG error handler.
	* Note that this struct must live as long as the main JPEG parameter
	* struct, to avoid dangling-pointer problems.
	*/
	struct jpeg_error_mgr			m_jerr;
	xbData							m_waitingDta,m_tmpBuf;

	enum jpegStep
	{
		jpegStep_Unknown,
			jpegStep_ReadHeader,
			jpegStep_StartDecompress,
			jpegStep_ReadRows,
			jpegStep_EndOfImage,
			jpegStep_EndOfFormat
	};
	jpegStep						m_jpegStep;

	void jpegOpen();
	void jpegClose();
	bool jpegProcessWaitingData();
	int jpegEndStayingData(int dataLg);

	xbString m_closeReason;
};
#endif
