#ifndef ADX2WAV_ADXHEADER_H
#define ADX2WAV_ADXHEADER_H

#include <istream>

// ADX info from http://ku-www.ss.titech.ac.jp/~yatsushi/adx.html
// and http://www.smallnews.net/azuco/column/cri.htm
// (but mostly the latter, holy crap)

class AdxHeader {
public:
	AdxHeader(): loopedFile(false), channelCount(1), criOffset(0),
				 criVersion(0), loopStartSample(0), loopEndSample(0) { }
	~AdxHeader() { }
	
	bool readFromFile(std::istream &fin);
	
	int version() const {
		return this->criVersion;
	}

	bool stereo() const {
		return this->isStereo;
	}
	
	int channels() const {
		return this->channelCount;
	}

	int frequency() const {
		return this->sampleFrequency;
	}
	
	int samples() const {
		return this->sampleCount;
	}
	
	int loopStart() const {
		return this->loopStartSample;
	}
	
	int loopEnd() const {
		return this->loopEndSample;
	}
	
	int signatureOffset() const {
		return this->criOffset;
	}
	
	bool loops() const {
		return loopedFile;
	}
	
private:
	bool loopedFile;
	bool isStereo;
	int channelCount;
	int sampleFrequency;
	int sampleCount;
	int criOffset;
	int criVersion;
	int loopStartSample;
	int loopEndSample;
};

// To tell if you've got an ADX file, look for "(C)CRI" at 1W+32h
// and 0x8001 at the last 1W of data
// e.g. - BGMME13.ADX - End of 1000 Years (千年城)
// ~1:09
//        BGMME24.ADX - Severe person
// ~0:56
bool AdxHeader::readFromFile(std::istream &fin) {
	unsigned char buf[16];
	
	this->criVersion = -1;
	fin.read((char *) buf, 16);
	this->criOffset = (buf[2] * 0x100 + buf[3]) - 2;

	this->channelCount = buf[7];
	this->isStereo = (this->channelCount == 2);

	this->sampleFrequency = buf[8] * 0x1000000 + buf[9] * 0x10000
						  + buf[10] * 0x100 + buf[11];
	this->sampleCount = buf[12] * 0x1000000 + buf[13] * 0x10000
				      + buf[14] * 0x100 + buf[15];

	if (this->criOffset > 0x14) {
		// 16 bytes at 0x10
		fin.read((char *) buf, 4);
		this->criVersion = buf[2];

		if (this->criOffset > 0x24) {
			fin.read((char *) buf, 8);
			fin.read((char *) buf, 4);
			if (this->criVersion == 3) {
				this->loopStartSample = buf[0] * 0x1000000 + buf[1] * 0x10000
				                      + buf[2] * 0x100 + buf[3];
			}
			// 16 bytes at 0x20
			fin.read((char *) buf, 8);
			if (this->criVersion == 3) {
				this->loopEndSample = buf[4] * 0x1000000 + buf[1] * 0x10000
				                    + buf[1] *0x100 + buf[3];
			}
			if (this->criOffset > 0x28) {
				fin.read((char *) buf, 8);
				if (this->criVersion == 4) {
					this->loopStartSample = buf[0] * 0x1000000 + buf[1] * 0x10000
									  	+ buf[2] * 0x100 + buf[3];
				}

				// 4 bytes at 0x30
				fin.read((char *) buf, 4);
				if (this->criVersion == 4) {
					this->loopEndSample = buf[0] * 0x1000000 + buf[1] * 0x10000
										+ buf[2] * 0x100 + buf[3];
				}			
			}
		}
		if (this->loopStartSample > 0 && this->loopEndSample > 0
			&& this->loopEndSample > this->loopStartSample)
		{
			this->loopedFile = true;
		}
	}
	
	fin.seekg(this->criOffset - fin.tellg(), std::ios::cur);
	fin.read((char *) buf, 6);
	if (0 != memcmp(buf, "(c)CRI", 6)) {
		return false;
	}
	
	return true;
}

#endif /*ADXHEADER_H_*/
