/*
 * @(#)AudioToWAV.cpp
 *
 * This file is part of webCDwriter - Network CD/DVD Writing.
 *
 * Copyright (C) 2000-2004 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 *
 * Jörg Haeger, 14.05.2000
 */

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "Config.h"
#include "AudioToWAV.h"
#include "Process.h"
#include "Support.h"
#include "Wave.h"

AudioToWAV::AudioToWAV(InputStream *inStream) {
	this->inStream = inStream;
	leftInStream = 0;
	writeBuf0 = writeBuf1 = 0;
	readBufN = 44;
	waveLength = 0;
	mode = NORMAL;
}

AudioToWAV::~AudioToWAV() {
	converter->terminate();
	delete converter;
}

void AudioToWAV::end() {
	mode = CLOSEOUT;
}

void AudioToWAV::fillReadBuf() {
	int free = sizeof readBuf - readBufN;
	if (free <= 0)
		return;

	int n = converter->read(&readBuf[readBufN], free);
	if (n == 0)
		mode = INCLOSED;
	else
	if (n > 0) {
		readBufN += n;
		waveLength += n;
	}
}

void AudioToWAV::fillWriteBuf() {
	int n = inStream->read(writeBuf, 0,
		min(leftInStream, sizeof writeBuf));
	if (n > 0) {
		leftInStream -= n;
		writeBuf0 = 0;
		writeBuf1 = n;
	}
	else
		if (leftInStream > 0)
			throw new Exception("unexpected end of inStream");
}

int AudioToWAV::get(const char **buf) {
	while (1) {
		converter->select();
		fillReadBuf();
		if (mode == INCLOSED) {
			if (leftInStream > 0
					|| writeBuf0 < writeBuf1) {
				// unexpected end of converter
				inStream->skip(leftInStream);
				leftInStream = 0;
				throw new Exception("unexpected end of converter");
			}

			int n = readBufN;
			readBufN = 0;
			*buf = readBuf;
			return n;
		}

		if (readBufN == sizeof readBuf) {
			readBufN = 0;
			*buf = readBuf;
			return sizeof readBuf;
		}

		if (leftInStream == 0)
			if (mode == NORMAL)
				return 0;
			else
			if (mode == CLOSEOUT && writeBuf0 >= writeBuf1) {
				converter->closePipeToChild();
				mode = OUTCLOSED;
			}

		if (writeBuf0 >= writeBuf1)
			fillWriteBuf();

		int n = converter->write(&writeBuf[writeBuf0],
			writeBuf1 - writeBuf0);
		if (n > 0)
			writeBuf0 += n;
	}
}

void AudioToWAV::put(int n) {
	leftInStream += n;
}

void AudioToWAV::setInStream(InputStream *inStream) {
	this->inStream = inStream;
}

void AudioToWAV::updateHeader(FILE *outStream) {
	fseek(outStream, 0, SEEK_SET);
	WaveHeader header;
	header.setLength(waveLength);
	fwrite(&header, 1, sizeof header, outStream);
	fflush(outStream);
}
