#ifndef __OBJECT_AUDIO_H__
#define __OBJECT_AUDIO_H__

#include "Object.h"

namespace AScript {

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

//-----------------------------------------------------------------------------
// Object_Audio
//-----------------------------------------------------------------------------
class DLLDECLARE Object_Audio : public Object {
public:
	enum Format {
		FORMAT_None,
		FORMAT_U8, FORMAT_S8,
		FORMAT_U16LE, FORMAT_S16LE, FORMAT_U16BE, FORMAT_S16BE,
	};
public:
	AScript_DeclareObjectAccessor(Audio)
private:
	Format _format;
	size_t _nChannels;
	size_t _len;
	Object *_pObjRef;
	unsigned char *_buff;
	OAL::Memory _memory;
public:
	inline Object_Audio(Environment &env, Format format, size_t nChannels) :
				Object(env.LookupClass(VTYPE_Audio)), _format(format), _nChannels(nChannels),
				_len(0), _pObjRef(NULL), _buff(NULL) {}
	inline Object_Audio(Class *pClass, Format format, size_t nChannels) :
				Object(pClass), _format(format), _nChannels(nChannels),
				_len(0), _pObjRef(NULL), _buff(NULL) {}
	virtual ~Object_Audio();
	virtual Object *Clone() const;
	inline bool IsValid() const { return _buff != NULL; }
	inline Format GetFormat() const { return _format; }
	inline size_t GetChannels() const { return _nChannels; }
	inline size_t GetLength() const { return _len; }
	inline unsigned char *GetBuffer() { return _buff; }
	inline size_t GetBytesPerData() const {
		return (_format == FORMAT_U8 || _format == FORMAT_S8)? 1 : 2;
	}
	inline void StoreData(unsigned char *buffp, int data) {
		if (_format == FORMAT_U8) {
			*buffp = static_cast<unsigned char>((data + 0x80) & 0xff);
		} else if (_format == FORMAT_S8) {
			*buffp = static_cast<unsigned char>(static_cast<char>(data & 0xff));
		} else if (_format == FORMAT_U16LE) {
			unsigned short num = static_cast<unsigned short>((data + 0x8000) & 0xffff);
			*(buffp + 0) = static_cast<unsigned char>(num);
			*(buffp + 1) = static_cast<unsigned char>(num >> 8);
		} else if (_format == FORMAT_S16LE) {
			unsigned short num = static_cast<unsigned short>(static_cast<short>(data & 0xffff));
			*(buffp + 0) = static_cast<unsigned char>(num);
			*(buffp + 1) = static_cast<unsigned char>(num >> 8);
		} else if (_format == FORMAT_U16BE) {
			unsigned short num = static_cast<unsigned short>((data + 0x8000) & 0xffff);
			*(buffp + 0) = static_cast<unsigned char>(num >> 8);
			*(buffp + 1) = static_cast<unsigned char>(num);
		} else if (_format == FORMAT_S16BE) {
			unsigned short num = static_cast<unsigned short>(static_cast<short>(data & 0xffff));
			*(buffp + 0) = static_cast<unsigned char>(num >> 8);
			*(buffp + 1) = static_cast<unsigned char>(num);
		}
	}
	void ReferenceBuffer(Object *pObjRef, unsigned char *buff, size_t len);
	bool AllocBuffer(Signal sig, size_t len);
	void FreeBuffer();
	bool SetSineWave(Signal sig, size_t iChannel,
			size_t pitch, int phase, int amplitude, size_t offset, size_t len);
	static Format SymbolToFormat(Signal sig, const Symbol *pSymbol);
	static const Symbol *FormatToSymbol(Format format);
	virtual Value DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag);
	virtual Value DoPropSet(Signal sig, const Symbol *pSymbol,
									const Value &value, bool &evaluatedFlag);
	virtual String ToString(Signal sig, bool exprFlag);
};

//-----------------------------------------------------------------------------
// AudioStreamer
//-----------------------------------------------------------------------------
class DLLDECLARE AudioStreamer {
public:
	typedef std::vector<AudioStreamer *> List;
private:
	const char *_audioType;
	static List *_pList;
public:
	inline AudioStreamer(const char *audioType) : _audioType(audioType) {}
	inline const char *GetAudioType() const { return _audioType; }
	virtual bool IsResponsible(Signal sig, Stream &stream) = 0;
	virtual bool Read(Environment &env, Signal sig, Object_Audio *pObjAudio, Stream &stream) = 0;
	virtual bool Write(Environment &env, Signal sig, Object_Audio *pObjAudio, Stream &stream) = 0;
public:
	static void Register(AudioStreamer *pAudioStreamer);
	static AudioStreamer *FindResponsible(Signal sig, Stream &stream, const char *audioType);
	static AudioStreamer *FindByAudioType(const char *audioType);
};

}

#endif
