#ifndef __OBJECT_BINARY_H__
#define __OBJECT_BINARY_H__

#include "Object.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Class_Binary / Object_Binary
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Binary : public Class {
public:
	Class_Binary(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
	virtual Object *CreateDescendant(Environment &env, Signal sig, Class *pClass);
};

class DLLDECLARE Object_Binary : public Object {
public:
	class IteratorByte : public Iterator {
	private:
		Object_Binary *_pObj;
		int _cnt, _cntMax;
		Binary::const_iterator _pCur;
	public:
		IteratorByte(Object_Binary *pObj, int cntMax);
		virtual ~IteratorByte();
		virtual bool DoNext(Environment &env, Signal sig, Value &value);
		virtual String ToString(Signal sig) const;
	};
	class IteratorUnpack : public Iterator {
	private:
		Object_Binary *_pObj;
		String _format;
		size_t _offset, _offsetInit;
		int _cntMax, _cnt;
	public:
		IteratorUnpack(Object_Binary *pObj, const char *format, size_t offset, int cntMax);
		virtual ~IteratorUnpack();
		virtual bool DoNext(Environment &env, Signal sig, Value &value);
		virtual String ToString(Signal sig) const;
	};
public:
	AScript_DeclareObjectAccessor(Binary)
private:
	Binary _binary;
public:
	inline Object_Binary(Class *pClass) : Object(pClass) {}
	inline Object_Binary(Environment &env) : Object(env.LookupClass(VTYPE_Binary)) {}
	inline Object_Binary(Environment &env, const Binary &binary) :
						Object(env.LookupClass(VTYPE_Binary)), _binary(binary) {}
	inline Object_Binary(Environment &env, const char *buff, size_t size) :
						Object(env.LookupClass(VTYPE_Binary)), _binary(buff, size) {}
	Object_Binary(const Object_Binary &obj);
	virtual ~Object_Binary();
	virtual Object *Clone() const;
	virtual Value IndexGet(Signal sig, const Value &valueIdx);
	virtual void IndexSet(Signal sig, const Value &valueIdx, const Value &value);
	virtual Iterator *CreateIterator(Signal sig);
	virtual String ToString(Signal sig, bool exprFlag);
	inline Binary &GetBinary() { return _binary; }
	inline const Binary &GetBinary() const { return _binary; }
	bool Pack(Signal sig, size_t &offset,
							const char *format, const ValueList &valList);
	Value Unpack(Signal sig, size_t &offset,
							const char *format, bool exeedErrorFlag);
	bool PackForward(Signal sig, size_t offset, size_t size);
	static void PackUShort(Binary::iterator pByte,
									bool bigEndianFlag, unsigned short num);
	static void PackULong(Binary::iterator pByte,
									bool bigEndianFlag, unsigned long num);
	static void PackUInt64(Binary::iterator pByte,
									bool bigEndianFlag, uint64 num);
	bool UnpackForward(Signal sig, size_t &offset, int distance, bool exceedErrorFlag);
	static unsigned short UnpackUShort(Binary::iterator pByte, bool bigEndianFlag);
	static unsigned long UnpackULong(Binary::iterator pByte, bool bigEndianFlag);
	static uint64 UnpackUInt64(Binary::iterator pByte, bool bigEndianFlag);
	static bool CheckString(Signal sig,
				const ValueList &valList, ValueList::const_iterator pValue);
	static bool CheckNumber(Signal sig,
				const ValueList &valList, ValueList::const_iterator pValue);
	static bool CheckNumber(Signal sig, const ValueList &valList,
				ValueList::const_iterator pValue, Number numMin, Number numMax);
};

//-----------------------------------------------------------------------------
// Class_BinaryPtr / Object_BinaryPtr
//-----------------------------------------------------------------------------
class DLLDECLARE Class_BinaryPtr : public Class {
public:
	Class_BinaryPtr(Environment *pEnvOuter);
	virtual Object *CreateDescendant(Environment &env, Signal sig, Class *pClass);
};

class DLLDECLARE Object_BinaryPtr : public Object {
public:
	AScript_DeclareObjectAccessor(BinaryPtr)
private:
	Object_Binary *_pObjBinary;
	size_t _offset;
public:
	inline Object_BinaryPtr(Class *pClass, Object_Binary *pObjBinary, size_t offset) :
		Object(pClass), _pObjBinary(pObjBinary), _offset(offset) {}
	inline Object_BinaryPtr(Environment &env, Object_Binary *pObjBinary, size_t offset) :
		Object(env.LookupClass(VTYPE_BinaryPtr)), _pObjBinary(pObjBinary), _offset(offset) {}
	inline Object_BinaryPtr(const Object_BinaryPtr &obj) :
		Object(obj), _pObjBinary(dynamic_cast<Object_Binary *>(Object::Reference(obj._pObjBinary))),
		_offset(obj._offset) {}
	virtual ~Object_BinaryPtr();
	virtual Object *Clone() const;
	virtual String ToString(Signal sig, bool exprFlag);
	inline Object_Binary *GetBinaryObj() { return _pObjBinary; }
	inline Binary &GetBinary() { return _pObjBinary->GetBinary(); }
	inline const Binary &GetBinary() const { return _pObjBinary->GetBinary(); }
	inline size_t GetOffset() const { return _offset; }
	inline void Reset() { _offset = 0; }
	bool Pack(Signal sig, bool forwardFlag,
							const char *format, const ValueList &valList);
	Value Unpack(Signal sig, bool forwardFlag,
							const char *format, bool exeedErrorFlag);
	bool UnpackForward(Signal sig, int distance, bool exceedErrorFlag);
};

//-----------------------------------------------------------------------------
// BinaryStream
//-----------------------------------------------------------------------------
class DLLDECLARE BinaryStream : public Stream {
private:
	Object_Binary *_pObjBinary;
	size_t _offset;
public:
	BinaryStream(Signal sig, Object_Binary *pObjBinary);
	virtual ~BinaryStream();
	virtual const char *GetName() const;
	virtual size_t DoRead(Signal sig, void *buff, size_t len);
	virtual size_t DoWrite(Signal sig, const void *buff, size_t len);
	virtual bool DoSeek(Signal sig, long offset, size_t offsetPrev, SeekMode seekMode);
	virtual bool DoFlush(Signal sig);
	virtual bool DoClose(Signal sig);
	virtual size_t DoGetSize();
	inline Binary &GetBinary() { return _pObjBinary->GetBinary(); }
	inline const Binary &GetBinary() const { return _pObjBinary->GetBinary(); }
};

}

#endif
