/*
 * 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.
 */

#include <log4cxx/mdc.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/threadspecificdata.h>

#if LOG4CXX_CFSTRING_API
	#include <CoreFoundation/CFString.h>
#endif


using namespace log4cxx;
using namespace log4cxx::helpers;

MDC::MDC(const std::string& key1, const std::string& value) : key()
{
	Transcoder::decode(key1, key);
	LOG4CXX_DECODE_CHAR(v, value);
	putLS(key, v);
}

MDC::~MDC()
{
	LogString prevVal;
	remove(key, prevVal);
}

void MDC::putLS(const LogString& key, const LogString& value)
{
	ThreadSpecificData::put(key, value);
}

void MDC::put(const std::string& key, const std::string& value)
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LOG4CXX_DECODE_CHAR(lvalue, value);
	putLS(lkey, lvalue);
}

bool MDC::get(const LogString& key, LogString& value)
{
	ThreadSpecificData* data = ThreadSpecificData::getCurrentData();

	if (data != 0)
	{
		Map& map = data->getMap();

		Map::iterator it = map.find(key);

		if (it != map.end())
		{
			value.append(it->second);
			return true;
		}

		data->recycle();
	}

	return false;
}

std::string MDC::get(const std::string& key)
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LogString lvalue;

	if (get(lkey, lvalue))
	{
		LOG4CXX_ENCODE_CHAR(value, lvalue);
		return value;
	}

	return std::string();
}

bool MDC::remove(const LogString& key, LogString& value)
{
	ThreadSpecificData* data = ThreadSpecificData::getCurrentData();

	if (data != 0)
	{
		Map& map = data->getMap();
		Map::iterator it;

		if ((it = map.find(key)) != map.end())
		{
			value = it->second;
			map.erase(it);
			data->recycle();
			return true;
		}
	}

	return false;
}

std::string MDC::remove(const std::string& key)
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LogString lvalue;

	if (remove(lkey, lvalue))
	{
		LOG4CXX_ENCODE_CHAR(value, lvalue);
		return value;
	}

	return std::string();
}


void MDC::clear()
{
	ThreadSpecificData* data = ThreadSpecificData::getCurrentData();

	if (data != 0)
	{
		Map& map = data->getMap();
		map.erase(map.begin(), map.end());
		data->recycle();
	}
}


#if LOG4CXX_WCHAR_T_API
MDC::MDC(const std::wstring& key1, const std::wstring& value) : key()
{
	Transcoder::decode(key1, key);
	LOG4CXX_DECODE_WCHAR(v, value);
	putLS(key, v);
}

std::wstring MDC::get(const std::wstring& key)
{
	LOG4CXX_DECODE_WCHAR(lkey, key);
	LogString lvalue;

	if (get(lkey, lvalue))
	{
		LOG4CXX_ENCODE_WCHAR(value, lvalue);
		return value;
	}

	return std::wstring();
}

void MDC::put(const std::wstring& key, const std::wstring& value)
{
	LOG4CXX_DECODE_WCHAR(lkey, key);
	LOG4CXX_DECODE_WCHAR(lvalue, value);
	putLS(lkey, lvalue);
}


std::wstring MDC::remove(const std::wstring& key)
{
	LOG4CXX_DECODE_WCHAR(lkey, key);
	LogString lvalue;

	if (remove(lkey, lvalue))
	{
		LOG4CXX_ENCODE_WCHAR(value, lvalue);
		return value;
	}

	return std::wstring();
}
#endif

#if LOG4CXX_UNICHAR_API
MDC::MDC(const std::basic_string<UniChar>& key1, const std::basic_string<UniChar>& value)
{
	Transcoder::decode(key1, key);
	LOG4CXX_DECODE_UNICHAR(v, value);
	putLS(key, v);
}

std::basic_string<log4cxx::UniChar> MDC::get(const std::basic_string<log4cxx::UniChar>& key)
{
	LOG4CXX_DECODE_UNICHAR(lkey, key);
	LogString lvalue;

	if (get(lkey, lvalue))
	{
		LOG4CXX_ENCODE_UNICHAR(value, lvalue);
		return value;
	}

	return std::basic_string<UniChar>();
}

void MDC::put(const std::basic_string<UniChar>& key, const std::basic_string<log4cxx::UniChar>& value)
{
	LOG4CXX_DECODE_UNICHAR(lkey, key);
	LOG4CXX_DECODE_UNICHAR(lvalue, value);
	putLS(lkey, lvalue);
}


std::basic_string<log4cxx::UniChar> MDC::remove(const std::basic_string<log4cxx::UniChar>& key)
{
	LOG4CXX_DECODE_UNICHAR(lkey, key);
	LogString lvalue;

	if (remove(lkey, lvalue))
	{
		LOG4CXX_ENCODE_UNICHAR(value, lvalue);
		return value;
	}

	return std::basic_string<UniChar>();
}
#endif

#if LOG4CXX_CFSTRING_API

MDC::MDC(const CFStringRef& key1, const CFStringRef& value)
{
	Transcoder::decode(key1, key);
	LOG4CXX_DECODE_CFSTRING(v, value);
	putLS(key, v);
}

CFStringRef MDC::get(const CFStringRef& key)
{
	LOG4CXX_DECODE_CFSTRING(lkey, key);
	LogString lvalue;

	if (get(lkey, lvalue))
	{
		LOG4CXX_ENCODE_CFSTRING(value, lvalue);
		return value;
	}

	return CFSTR("");
}

void MDC::put(const CFStringRef& key, const CFStringRef& value)
{
	LOG4CXX_DECODE_CFSTRING(lkey, key);
	LOG4CXX_DECODE_CFSTRING(lvalue, value);
	putLS(lkey, lvalue);
}


CFStringRef MDC::remove(const CFStringRef& key)
{
	LOG4CXX_DECODE_CFSTRING(lkey, key);
	LogString lvalue;

	if (remove(lkey, lvalue))
	{
		LOG4CXX_ENCODE_CFSTRING(value, lvalue);
		return value;
	}

	return CFSTR("");
}
#endif

