/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if defined(_MSC_VER)
	#pragma warning ( disable: 4231 4251 4275 4786 )
#endif

#include <log4cxx/logstring.h>
#include <log4cxx/helpers/objectoutputstream.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/helpers/outputstream.h>
#include <log4cxx/helpers/charsetencoder.h>
#include "apr_pools.h"

using namespace log4cxx;
using namespace log4cxx::helpers;

IMPLEMENT_LOG4CXX_OBJECT(ObjectOutputStream)

ObjectOutputStream::ObjectOutputStream(OutputStreamPtr outputStream, Pool& p)
	:   os(outputStream),
		utf8Encoder(CharsetEncoder::getUTF8Encoder()),
		objectHandleDefault(0x7E0000),
		objectHandle(objectHandleDefault),
		classDescriptions(new ClassDescriptionMap())
{
	unsigned char start[] = { 0xAC, 0xED, 0x00, 0x05 };
	ByteBuffer buf((char*) start, sizeof(start));
	os->write(buf, p);
}

ObjectOutputStream::~ObjectOutputStream()
{
	delete classDescriptions;
}

void ObjectOutputStream::close(Pool& p)
{
	os->close(p);
}

void ObjectOutputStream::flush(Pool& p)
{
	os->flush(p);
}

void ObjectOutputStream::reset(Pool& p)
{
	os->flush(p);
	writeByte(TC_RESET, p);
	os->flush(p);

	objectHandle = objectHandleDefault;
	classDescriptions->clear();
}

void ObjectOutputStream::writeObject(const LogString& val, Pool& p)
{
	objectHandle++;
	writeByte(TC_STRING, p);
	char bytes[2];
#if LOG4CXX_LOGCHAR_IS_UTF8
	size_t len = val.size();
	ByteBuffer dataBuf(const_cast<char*>(val.data()), val.size());
#else
	size_t maxSize = 6 * val.size();
	char* data = p.pstralloc(maxSize);
	ByteBuffer dataBuf(data, maxSize);
	LogString::const_iterator iter(val.begin());
	utf8Encoder->encode(val, iter, dataBuf);
	dataBuf.flip();
	size_t len = dataBuf.limit();
#endif
	bytes[1] = (char) (len & 0xFF);
	bytes[0] = (char) ((len >> 8) & 0xFF);
	ByteBuffer lenBuf(bytes, sizeof(bytes));

	os->write(lenBuf,   p);
	os->write(dataBuf,  p);
}

void ObjectOutputStream::writeObject(const MDC::Map& val, Pool& p)
{
	//
	// TC_OBJECT and the classDesc for java.util.Hashtable
	//
	unsigned char prolog[] =
	{
		0x72, 0x00, 0x13, 0x6A, 0x61, 0x76, 0x61,
		0x2E, 0x75, 0x74, 0x69, 0x6C, 0x2E, 0x48, 0x61,
		0x73, 0x68, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x13,
		0xBB, 0x0F, 0x25, 0x21, 0x4A, 0xE4, 0xB8, 0x03,
		0x00, 0x02, 0x46, 0x00, 0x0A, 0x6C, 0x6F, 0x61,
		0x64, 0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x49,
		0x00, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68,
		0x6F, 0x6C, 0x64, 0x78, 0x70
	};
	writeProlog("java.util.Hashtable", 1, (char*) prolog, sizeof(prolog), p);

	// loadFactor = 0.75, threshold = 5, blockdata start, buckets.size = 7
	char data[] = { 0x3F, 0x40,   0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
			TC_BLOCKDATA, 0x08, 0x00, 0x00, 0x00, 0x07
		};
	ByteBuffer dataBuf(data, sizeof(data));
	os->write(dataBuf, p);

	char size[4];
	size_t sz = val.size();

	size[3] = (char) (sz            & 0xFF);
	size[2] = (char) ((sz >> 8)     & 0xFF);
	size[1] = (char) ((sz >> 16)    & 0xFF);
	size[0] = (char) ((sz >> 24)    & 0xFF);

	ByteBuffer sizeBuf(size, sizeof(size));
	os->write(sizeBuf, p);

	for (MDC::Map::const_iterator   iter  = val.begin();
		iter != val.end();
		iter++)
	{
		writeObject(iter->first, p);
		writeObject(iter->second, p);
	}

	writeByte(TC_ENDBLOCKDATA, p);
}

void ObjectOutputStream::writeUTFString(const std::string& val, Pool& p)
{
	char bytes[3];
	size_t len = val.size();
	ByteBuffer dataBuf(const_cast<char*>(val.data()), val.size());
	objectHandle++;

	bytes[0] = 0x74;
	bytes[1] = (char) ((len >> 8) & 0xFF);
	bytes[2] = (char) (len & 0xFF);

	ByteBuffer lenBuf(bytes, sizeof(bytes));
	os->write(lenBuf, p);
	os->write(dataBuf, p);
}

void ObjectOutputStream::writeByte(char val, Pool& p)
{
	ByteBuffer buf(&val, 1);
	os->write(buf, p);
}

void ObjectOutputStream::writeInt(int val, Pool& p)
{
	char bytes[4];

	bytes[3] = (char) (val & 0xFF);
	bytes[2] = (char) ((val >> 8) & 0xFF);
	bytes[1] = (char) ((val >> 16) & 0xFF);
	bytes[0] = (char) ((val >> 24) & 0xFF);

	ByteBuffer buf(bytes, sizeof(bytes));
	os->write(buf, p);
}

void ObjectOutputStream::writeLong(log4cxx_time_t val, Pool& p)
{
	char bytes[8];

	bytes[7] = (char) (val & 0xFF);
	bytes[6] = (char) ((val >> 8) & 0xFF);
	bytes[5] = (char) ((val >> 16) & 0xFF);
	bytes[4] = (char) ((val >> 24) & 0xFF);
	bytes[3] = (char) ((val >> 32) & 0xFF);
	bytes[2] = (char) ((val >> 40) & 0xFF);
	bytes[1] = (char) ((val >> 48) & 0xFF);
	bytes[0] = (char) ((val >> 56) & 0xFF);

	ByteBuffer buf(bytes, sizeof(bytes));
	os->write(buf, p);
}

void ObjectOutputStream::writeBytes(const char* bytes, size_t len, Pool& p)
{
	ByteBuffer buf(const_cast<char*>(bytes), len);
	os->write(buf, p);
}

void ObjectOutputStream::writeNull(Pool& p)
{
	writeByte(TC_NULL, p);
}

void ObjectOutputStream::writeProlog(const  char*   className,
	int        classDescIncrement,
	char*  classDesc,
	size_t len,
	Pool&  p)
{
	ClassDescriptionMap::const_iterator match = classDescriptions->find(className);

	if (match != classDescriptions->end())
	{
		char bytes[6];

		bytes[0] = TC_OBJECT;
		bytes[1] = TC_REFERENCE;
		bytes[2] = (char) ((match->second >> 24) & 0xFF);
		bytes[3] = (char) ((match->second >> 16) & 0xFF);
		bytes[4] = (char) ((match->second >> 8) & 0xFF);
		bytes[5] = (char) (match->second & 0xFF);

		ByteBuffer buf(bytes, sizeof(bytes));
		os->write(buf, p);

		objectHandle++;
	}
	else
	{
		classDescriptions->insert(ClassDescriptionMap::value_type(className, objectHandle));
		writeByte(TC_OBJECT, p);

		ByteBuffer buf(classDesc, len);
		os->write(buf, p);

		objectHandle += (classDescIncrement + 1);
	}
}
