/**
 * Converts a byte array into a MessagePartsDescriptor
 * @param blockData byte array to convert
 * @return a MessagePartsDescriptor
 */
SmartPtrCMessagePartDescriptor CMessagePartDescriptor::fromArray(
	SmartPtrCDynamicByteArray& buffer) {
	CAF_CM_STATIC_FUNC("CMessagePartDescriptor", "fromArray");
	CAF_CM_VALIDATE_SMARTPTR(buffer);

	if (buffer->getByteCount() < BLOCK_SIZE) {
		CAF_CM_EXCEPTION_VA1(E_INVALIDARG, "Input data block is too small - %d",
			buffer->getByteCount());
	}

	if (CMessagePartsParser::getByte(buffer) != CAF_MSG_VERSION) {
		CAF_CM_EXCEPTION_VA0(E_INVALIDARG, "Input data block version is incorrect");
	}

	const byte resvd = CMessagePartsParser::getByte(buffer);
	if (resvd != RESERVED) {
		CAF_CM_EXCEPTION_VA0(E_INVALIDARG, "Input data block reserved bits are incorrect");
	}

	const uint16 attachmentNumber = CMessagePartsParser::getUint16(buffer);
	const uint32 partNumber = CMessagePartsParser::getUint32(buffer);
	const uint32 dataSize = CMessagePartsParser::getUint32(buffer);
	const uint32 dataOffset = CMessagePartsParser::getUint32(buffer);
	buffer->verify();

	SmartPtrCMessagePartDescriptor messagePartsDescriptor;
	messagePartsDescriptor.CreateInstance();
	messagePartsDescriptor->initialize(
		attachmentNumber, partNumber, dataSize, dataOffset);

	return messagePartsDescriptor;
}
SmartPtrCDynamicByteArray CMessagePartDescriptor::toArray(
		const uint16 attachmentNumber,
		const uint32 partNumber,
		const uint32 dataSize,
		const uint32 dataOffset) {
	SmartPtrCDynamicByteArray buffer;
	buffer.CreateInstance();
	buffer->allocateBytes(BLOCK_SIZE);

	CMessagePartsBuilder::put(CAF_MSG_VERSION, buffer);
	CMessagePartsBuilder::put(RESERVED, buffer);
	CMessagePartsBuilder::put(attachmentNumber, buffer);
	CMessagePartsBuilder::put(partNumber, buffer);
	CMessagePartsBuilder::put(dataSize, buffer);
	CMessagePartsBuilder::put(dataOffset, buffer);
	buffer->verify();

	return buffer;
}
SmartPtrIIntMessage COutgoingMessageHandler::rehydrateMultiPartMessage(
	const SmartPtrCMessageDeliveryRecord& deliveryRecord,
	const IIntMessage::SmartPtrCHeaders& addlHeaders) {
	CAF_CM_STATIC_FUNC_LOG("COutgoingMessageHandler", "rehydrateMultiPartMessage");
	CAF_CM_VALIDATE_SMARTPTR(deliveryRecord);
	// addlHeaders are optional

	uint32 payloadSize = CMessagePartsHeader::BLOCK_SIZE;
	const std::deque<SmartPtrCMessagePartDescriptorSourceRecord> sourceRecords = deliveryRecord->getMessagePartSources();
	for (TConstIterator<std::deque<SmartPtrCMessagePartDescriptorSourceRecord> > sourceRecordIter(sourceRecords);
		sourceRecordIter; sourceRecordIter++) {
		const SmartPtrCMessagePartDescriptorSourceRecord sourceRecord = *sourceRecordIter;
		payloadSize += CMessagePartDescriptor::BLOCK_SIZE + sourceRecord->getDataLength();
	}

	SmartPtrCDynamicByteArray payload;
	payload.CreateInstance();
	payload->allocateBytes(payloadSize);

	const SmartPtrCDynamicByteArray partsHeader = CMessagePartsHeader::toArray(
		deliveryRecord->getCorrelationId(), deliveryRecord->getNumberOfParts());
	payload->memAppend(partsHeader->getPtr(), partsHeader->getByteCount());

	uint32 partNumber = deliveryRecord->getStartingPartNumber();
	if (CAF_CM_IS_LOG_DEBUG_ENABLED) {
		CAF_CM_LOG_DEBUG_VA3("[# sourceRecords=%d][payloadSize=%d][startingPartNumber=%d]",
			sourceRecords.size(), payloadSize, partNumber);
	}

	for (TConstIterator<std::deque<SmartPtrCMessagePartDescriptorSourceRecord> > sourceRecordIter(sourceRecords);
		sourceRecordIter; sourceRecordIter++) {
		const SmartPtrCMessagePartDescriptorSourceRecord sourceRecord = *sourceRecordIter;

		const SmartPtrCDynamicByteArray partDescriptor = CMessagePartDescriptor::toArray(
			sourceRecord->getAttachmentNumber(), partNumber++, sourceRecord->getDataLength(),
			sourceRecord->getDataOffset());
		payload->memAppend(partDescriptor->getPtr(), partDescriptor->getByteCount());

		CAF_CM_LOG_DEBUG_VA3("Reading from file - file: %s, len: %d, offset: %d",
			sourceRecord->getFilePath().c_str(), sourceRecord->getDataLength(),
			sourceRecord->getDataOffset());

		std::ifstream file(sourceRecord->getFilePath().c_str(), std::ios::binary);
		try {
			if (!file.is_open()) {
				CAF_CM_EXCEPTION_VA1(ERROR_FILE_NOT_FOUND,
					"Could not open binary file - %s", sourceRecord->getFilePath().c_str());
			}

			file.seekg(sourceRecord->getDataOffset(), std::ios::beg);
			file.read(reinterpret_cast<char*>(payload->getNonConstPtrAtCurrentPos()),
				sourceRecord->getDataLength());
			payload->verify();
			if (! file) {
				CAF_CM_EXCEPTION_VA3(ERROR_BUFFER_OVERFLOW,
					"Did not read full contents - file: %s, requested: %d, read: %d",
					sourceRecord->getFilePath().c_str(), sourceRecord->getDataLength(),
					file.gcount());
			}

			payload->incrementCurrentPos(sourceRecord->getDataLength());
		}
		CAF_CM_CATCH_ALL;
		file.close();
		CAF_CM_LOG_CRIT_CAFEXCEPTION;
		CAF_CM_THROWEXCEPTION;
	}

	SmartPtrCIntMessage rc;
	rc.CreateInstance();
	rc->initialize(payload, deliveryRecord->getMessageHeaders(), addlHeaders);

	return rc;
}