//
// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
//
#ifndef CHARLS_STREAMS
#define CHARLS_STREAMS

#include "dcmtk/ofstd/ofvector.h"
#include "dcmtk/ofstd/ofbmanip.h"
#include "util.h"



// This file defines JPEG-LS streams: The header and the actual pixel data. Header markers have fixed length, the pixeldata not.



class JpegSegment;

enum JPEGLS_ColorXForm
{
	// default (RGB)
	COLORXFORM_NONE = 0,

	// Color transforms as defined by HP
	COLORXFORM_HP1,
	COLORXFORM_HP2,
	COLORXFORM_HP3,

	// Defined by HP but not supported by CharLS
	COLORXFORM_RGB_AS_YUV_LOSSY,
	COLORXFORM_MATRIX
};

//
// JLSOutputStream: minimal implementation to write JPEG header streams
//
class JLSOutputStream
{
	friend class JpegMarkerSegment;
	friend class JpegImageDataSegment;

public:
	JLSOutputStream();
	virtual ~JLSOutputStream();

	void Init(Size size, LONG bitsPerSample, LONG ccomp);
	void AddScan(const void* compareData, const JlsParameters* pparams);
	void AddLSE(const JlsCustomParameters* pcustom);
	void AddColorTransform(int i);
	size_t GetBytesWritten()
		{ return _cbyteOffset; }

	size_t GetLength()
		{ return _cbyteLength - _cbyteOffset; }

	size_t Write(BYTE* pdata, size_t cbyteLength);

	void EnableCompare(bool bCompare)
	{ _bCompare = bCompare; }
private:
	BYTE* GetPos() const
		{ return _pdata + _cbyteOffset; }

	void WriteByte(BYTE val)
	{
		ASSERT(!_bCompare || _pdata[_cbyteOffset] == val);

		_pdata[_cbyteOffset++] = val;
	}

	void WriteBytes(const OFVector<BYTE>& rgbyte)
	{
		for (size_t i = 0; i < rgbyte.size(); ++i)
		{
			WriteByte(rgbyte[i]);
		}
	}

	void WriteWord(USHORT val)
	{
		WriteByte(BYTE(val / 0x100));
		WriteByte(BYTE(val % 0x100));
	}


    void Seek(size_t byteCount)
		{ _cbyteOffset += byteCount; }

	bool _bCompare;

private:
	BYTE* _pdata;
	size_t _cbyteOffset;
	size_t _cbyteLength;
	LONG _icompLast;
	OFVector<JpegSegment*> _segments;
};



struct Presets : public JlsCustomParameters
{
public:
	Presets()
	{
		MAXVAL = 0;
		T1 = 0;
		T2 = 0;
		T3 = 0;
		RESET = 0;
	}
};


//
// JLSInputStream: minimal implementation to read JPEG header streams
//
class JLSInputStream
{
public:
	JLSInputStream(const BYTE* pdata, LONG cbyteLength);

	size_t GetBytesRead()
		{ return _cbyteOffset; }

	const JlsParameters& GetMetadata() const
		{ return _info; }

	const JlsCustomParameters& GetCustomPreset() const
	{ return _info.custom; }

	void Read(void* pvoid, LONG cbyteAvailable);
	void ReadHeader();

	void EnableCompare(bool bCompare)
		{ _bCompare = bCompare;	}

	void SetInfo(JlsParameters* info) { _info = *info; }

	void SetRect(JlsRect rect) { _rect = rect; }

private:
	void ReadPixels(void* pvoid, LONG cbyteAvailable);
	void ReadScan(void*);
	void ReadStartOfScan();
	void ReadPresetParameters();
	void ReadComment();
	void ReadStartOfFrame();
	BYTE ReadByte();
	int ReadWord();
	void ReadNBytes(OFVector<char>& dst, int byteCount);

	// JFIF
	void ReadJfif();
	// Color Transform Application Markers & Code Stream (HP extension)
	void ReadColorSpace();
	void ReadColorXForm();

private:
	const BYTE* _pdata;
	size_t _cbyteOffset;
	size_t _cbyteLength;
	bool _bCompare;
	JlsParameters _info;
	JlsRect _rect;
};




#endif
