/* Web Polygraph       http://www.web-polygraph.org/
 * (C) 2003-2006 The Measurement Factory
 * Licensed under the Apache License, Version 2.0 */

#include "base/polygraph.h"

#include "xstd/ZLib.h"

#include "base/RndPermut.h"
#include "runtime/LogComment.h"
#include "runtime/IOBuf.h"
#include "csm/ContentDbase.h"

#include "csm/ContentCfg.h"
#include "csm/InjectIter.h"
#include "csm/cdbEntries.h"
#include "csm/GzipEncoder.h"

#include "xstd/gadgets.h"


GzipEncoder::GzipEncoder(int aLevel, BodyIter *aProducer): 
	theLevel(aLevel), theProducer(aProducer), theEncoder(0) {
	theOid = theProducer->oid();
	theContentCfg = theProducer->contentCfg();
	theContentHash = theProducer->contentHash();
	theContentSize = Size(); // unknown
}

GzipEncoder::~GzipEncoder() {
	delete theEncoder;
}

void GzipEncoder::reset() {
	Assert(!theProducer);
	BodyIter::reset();
	theLevel = -1;
	theProducerBuf.reset();
	if (theEncoder)
		theEncoder->reset();
}

void GzipEncoder::start(WrBuf *aBuf) {
	BodyIter::start(aBuf);
	Assert(theLevel >= 0);
	Assert(theProducer);
	theProducer->start(&theProducerBuf);

	if (theEncoder)
		theEncoder->init(theLevel);
	else
		theEncoder = new Deflator(theLevel);
}

void GzipEncoder::stop() {
	if (theProducer) {
		theContentCfg->putBodyIter(theProducer); // assumes same theContentCfg
		theProducer = 0;
	}
}

void GzipEncoder::abandonProducer() {
	theProducer = 0;
}

bool GzipEncoder::pourBody() {
	while ((theProducer->canPour() || !theProducerBuf.empty()) && this->canPour()) {
		if (theProducer->canPour())
			theProducer->pour();
		
		if (Should(!theProducerBuf.empty())) {
			theEncoder->data(theProducerBuf.content(), theProducerBuf.contSize());
			theEncoder->space(theBuf->space(), theBuf->spaceSize());

			// compress
			Size dataDelta, spaceDelta;
			const bool finish = theProducer->pouredAll();
			if (theEncoder->deflate(spaceDelta, dataDelta, finish)) {
				theProducerBuf.consumed(dataDelta);
				theBuf->appended(spaceDelta);
				theBuiltSize += spaceDelta;
				if (!theContentSize.known() && finish && theProducerBuf.empty())
					theContentSize = theBuiltSize;
			} else {
				Comment << "error: a called to zlib::deflate failed: " <<
					theEncoder->error() << endc;
				return false;
			}
		}
	}
	return true;
}


syntax highlighted by Code2HTML, v. 0.9.1