/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef LASTEXPRESS_SOUND_ENTRY_H
#define LASTEXPRESS_SOUND_ENTRY_H

/*
	Sound entry: 68 bytes (this is what appears in savegames)
	    uint32 {4}      - status
	    uint32 {4}      - tag
	    uint32 {4}      - time left (_blockCount - _time)
	    uint32 {4}      - time in sound ticks (30Hz timer)
	    uint32 {4}      - LastExpress_ADPCMStream::_volumeHoldBlocks
	                      (useless since the target volume is not saved)
	    uint32 {4}      - ?? [no references except for save/load]
	    uint32 {4}      - entity
	    uint32 {4}      - activate delay in sound ticks (30Hz timer)
	    uint32 {4}      - priority
	    char {16}       - name of linked-after sound
	                      (always empty because only NIS entries
	                       have linked-after sounds, and NIS entries are not saved)
	    char {16}       - name

	Sound queue entry: 120 bytes
	    uint32 {4}      - status (combination of flags from SoundFlag)
	    uint32 {4}      - tag (enum SoundTag for special sounds,
	                           unique value for normal ones)
	    uint32 {4}      - pointer to the beginning of the buffer for compressed sound data
	    uint32 {4}      - pointer to the end of the buffer for compressed sound data
	    uint32 {4}      - decoder pointer inside the buffer
	    uint32 {4}      - pointer to the sound buffer [always same as the third field]
	    uint32 {4}      - reader pointer inside the buffer
	    uint32 {4}      - time left (_blockCount - time)
	    uint32 {4}      - time in sound ticks (30Hz timer)
	    uint32 {4}      - buffer size
	    uint32 {4}      - union:
	                       if data stream is open: position in the stream
	                       if data stream is closed: close reason, purely informational
	    uint32 {4}      - archive structure pointer
	    uint32 {4}      - _linkAfter, pointer to the entry for linked-after sound
	                      (xxx.LNK for sound entry corresponding to xxx.NIS)
	    uint32 {4}      - LastExpress_ADPCMStream::_volumeHoldBlocks
	                      (used for smooth change of volume)
	    uint32 {4}      - ?? [no references except for save/load]
	    uint32 {4}      - target value for smooth change of volume
	    uint32 {4}      - base volume if NIS is playing
	                      (the actual volume is reduced in half for non-NIS sounds;
	                       this is used to restore the volume after NIS ends)
	    uint32 {4}      - entity
	    uint32 {4}      - activate time in sound ticks (30Hz timer)
	    uint32 {4}      - priority
	    char {16}       - name of linked-after sound, used to save/load _linkAfter
	    char {16}       - name
	    uint32 {4}      - pointer to next entry in the queue
	    uint32 {4}      - subtitle data pointer
*/

#include "lastexpress/data/snd.h"
#include "lastexpress/data/subtitle.h"

#include "lastexpress/shared.h"

#include "common/serializer.h"

namespace LastExpress {

class LastExpressEngine;
class SubtitleEntry;

//////////////////////////////////////////////////////////////////////////
// SoundEntry
//////////////////////////////////////////////////////////////////////////
class SoundEntry : Common::Serializable {
public:
	SoundEntry(LastExpressEngine *engine);
	~SoundEntry();

	void open(Common::String name, SoundFlag flag, int priority);
	void close();
	// startTime is measured in sound ticks, 30Hz timer
	// [used for restoring the entry from savefile]
	void play(uint32 startTime = 0);
	void kill() {
		_entity = kEntityPlayer; // no kActionEndSound notifications
		close();
	}
	void setVolumeSmoothly(SoundFlag newVolume);
	// setVolumeSmoothly() treats kVolumeNone in a special way;
	// fade() terminates the stream after the transition
	void fade() { setVolumeSmoothly(kVolumeNone); }
	bool update();
	void adjustVolumeIfNISPlaying();
	void setVolume(SoundFlag newVolume);
	// activateDelay is measured in main ticks, 15Hz timer
	void initDelayedActivate(unsigned activateDelay);

	// Subtitles
	void setSubtitles(Common::String filename);

	// Serializable
	void saveLoadWithSerializer(Common::Serializer &ser);

	// Accessors
	void setEntity(EntityIndex entity) { _entity = entity; }
	bool needSaving() const {
		return (_name != "NISSND?" && (_status & kSoundTypeMask) != kSoundTypeMenu);
	}

	uint32           getStatus()   { return _status; }
	int32            getTag()      { return _tag; }
	uint32           getTime()     { return _soundStream ? (_soundStream->getTimeMS() * 30 / 1000) + _startTime : 0; }
	EntityIndex      getEntity()   { return _entity; }
	uint32           getPriority() { return _priority; }
	const Common::String& getName(){ return _name; }

	// Streams
	SimpleSound *getSoundStream() { return _soundStream; }

private:
	LastExpressEngine *_engine;

	// _status field is a combination of bits from SoundFlag; writing
	// _status = (SoundFlag)(_status | kSoundFlagXxx) instead of _status |= kSoundFlagXxx
	// is irksome, so let's keep the type as uint32
	uint32 _status;
	int32 _tag; // member of SoundTag for special sounds, unique value for normal sounds
	//byte *_bufferStart, *_bufferEnd, *_decodePointer, *_buffer, *_readPointer;
	// the original game uses uint32 _blocksLeft, _time instead of _blockCount
	// we ask the backend for sound time
	uint32 _blockCount;
	uint32 _startTime;
	//uint32 _bufferSize;
	//union { uint32 _streamPos; enum StreamCloseReason _streamCloseReason; };
	Common::SeekableReadStream *_stream;    // The file stream
	//SoundEntry* _linkAfter;
	//uint32 _volumeHoldBlocks; // the related logic is in LastExpress_ADPCMStream
	//uint32 _unused;
	//uint32 _smoothChangeTarget; // the related logic is in LastExpress_ADPCMStream
	uint32 _volumeWithoutNIS;
	EntityIndex _entity;
	// The original game uses one variable _activateTime = _initTime + _activateDelay
	// and measures everything in sound ticks (30Hz timer).
	// We use milliseconds and two variables to deal with possible overflow
	// (probably paranoid, but nothing really complicated).
	uint32 _initTimeMS, _activateDelayMS;
	uint32 _priority;
	// char _linkAfterName[16];
	Common::String _name;    //char[16];
	// original has pointer to the next structure in the list (not used)
	SubtitleEntry *_subtitle;

	// Sound buffer & stream
	StreamedSound *_soundStream;    // the filtered sound stream

	void setupTag(SoundFlag flag);
	void setupStatus(SoundFlag flag);
	void loadStream(Common::String name);
};

//////////////////////////////////////////////////////////////////////////
// SubtitleEntry
//////////////////////////////////////////////////////////////////////////
class SubtitleEntry {
public:
	SubtitleEntry(LastExpressEngine *engine);
	~SubtitleEntry();

	void load(Common::String filename, SoundEntry *soundEntry);
	void loadData();
	void close();
	void setupAndDraw();
	void drawOnScreen();

	// Accessors
	uint32 getStatus() { return _status; }
	SoundEntry *getSoundEntry()  { return _sound; }

private:
	LastExpressEngine *_engine;

	Common::String    _filename;
	uint32            _status;
	SoundEntry       *_sound;
	SubtitleManager  *_data;
};

} // End of namespace LastExpress

#endif // LASTEXPRESS_SOUND_ENTRY_H