#ifndef OGG_H
#define OGG_H

/*
 * @(#)Ogg.h
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2003 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 */

#include "File.h"
#include "FileInputStream.h"

/**
 * A class to handle ogg files.
 *
 * @version 20030220
 * @author Jörg P. M. Haeger
 */
class Ogg {
private:
	int audio_channels;
	int audio_sample_rate;
	long dataLength;
	long headerStart;
	int64 sampleNum;
	int vorbis_version;

public:
	Ogg(File &file) {
		dataLength = File(file).length();
		FileInputStream inStream = new FileInputStream(file);

		int pos = 0;
		while (true) {
			int packet_type = 0;
			char capture_pattern1[] = { 'v', 'o', 'r', 'b', 'i', 's' };
			for (int i = 0; capture_pattern1[i] != 0; i++) {
				int b = inStream.read();
				if (b == -1)
					throw new Exception(
						"no Vorbis identification header");
				pos++;
				if (b != capture_pattern1[i]) {
					packet_type = b;
					i = -1;
				}
			}

			if (packet_type == 1)
				break;
		}

		vorbis_version = read32Bits(inStream);
		if (vorbis_version > 0)
			throw new Exception(S.e + "unknown vorbis_version "
				+ vorbis_version);
		audio_channels = inStream.read();
		audio_sample_rate = read32Bits(inStream);
		pos += 4 + 1 + 4;

		headerStart = dataLength - 16 * 1024;
		inStream.skip(headerStart - pos);
		int count = 0;
		while (true) {
			char capture_pattern[] = { 'O', 'g', 'g', 'S', 0 };
			int capture_pattern_length = strlen(capture_pattern) + 1;
			int i;
			for (i = 0; i < capture_pattern_length; i++) {
				int b = inStream.read();
				if (b == -1)
					break;
				if (b != capture_pattern[i]) {
					headerStart += i + 1;
					i = -1;
				}
			}
			if (i < capture_pattern_length)
				break;

			count++;

			int header_type_flag = inStream.read();
			if (header_type_flag == -1)
				break;

			int64 absolute_granule_position = 0;
			for (i = 0; i < 8; i++) {
				int64 b = inStream.read();
				if (b == -1)
					break;

				absolute_granule_position |= b << (8 * i);
			}
			if (i < 8)
				break;

			if ((header_type_flag & 0x06) != 0)
				sampleNum = absolute_granule_position;
		}
	}

	long getSeconds() {
		if (audio_sample_rate > 0)
			return sampleNum / audio_sample_rate;
		else
			return 0;
	}

	int read32Bits(FileInputStream &inStream) {
		int n = 0;
		for (int i = 0; i < 4; i++) {
			int b = inStream.read();
			if (b == -1)
				throw new Exception("Unexpected end of input stream");
			n |= b << (8 * i);
		}
		return n;
	}
};

#endif
