#include "acl_stdafx.hpp"
#ifndef ACL_PREPARE_COMPILE
#include "acl_cpp/stdlib/locker.hpp"
#include "acl_cpp/hsocket/hsclient.hpp"
#include "acl_cpp/hsocket/hspool.hpp"
#endif

namespace acl
{

hspool::hspool(const char* addr_rw, const char* addr_rd,
	bool cache_enable /* = true */, bool retry_enable /* = true */)
: cache_enable_(cache_enable)
, retry_enable_(retry_enable)
{
	acl_assert(addr_rw);
	addr_rw_ = acl_mystrdup(addr_rw);
	if (addr_rd != NULL)
		addr_rd_ = acl_mystrdup(addr_rd);
	else
		addr_rd_ = addr_rw_;
	locker_ = NEW locker(true);
}

hspool::~hspool()
{
	if (addr_rd_ != addr_rw_)
		acl_myfree(addr_rd_);
	acl_myfree(addr_rw_);

	std::list<hsclient*>::iterator it = pool_.begin();
	for (; it != pool_.end(); ++it)
		delete (*it);
	delete locker_;
}

hsclient* hspool::peek(const char* dbn, const char* tbl,
	const char* idx, const char* flds, bool readonly /* = false */)
{
	hsclient* client;
	const char* addr;

	if (readonly)
		addr = addr_rd_;
	else
		addr = addr_rw_;

	locker_->lock();

	// 先顺序查询符合表字段条件的连接对象
	std::list<hsclient*>::iterator it = pool_.begin();
	for (; it != pool_.end(); ++it)
	{
		// 如果地址不匹配查跳过，地址必须匹配
		if (strcmp((*it)->get_addr(), addr) != 0)
			continue;

		// 打开已经打开的表，查询表字段是否符合
		if ((*it)->open_tbl(dbn, tbl, idx, flds, false))
		{
			client = *it;
			pool_.erase(it);
			locker_->unlock();
			return (client);
		}
	}

	// 查询地址匹配的连接对象，如果存在一个匹配的连接对象，则
	// 打开新的表
	for (it = pool_.begin(); it != pool_.end();)
	{
		// 如果地址不匹配查跳过，地址必须匹配
		if (strcmp((*it)->get_addr(), addr) != 0)
		{
			++it;
			continue;
		}

		client = *it;
		it = pool_.erase(it); // 从连接池中删除

		// 打开新的表
		if (client->open_tbl(dbn, tbl, idx, flds, true))
		{
			locker_->unlock();
			return (client);
		}

		// 打开失败，则需要删除该连接对象
		delete client;
	}

	locker_->unlock();

	client = NEW hsclient(addr, cache_enable_, retry_enable_);

	if (client->open_tbl(dbn, tbl, idx, flds) == false)
	{
		delete client;
		return (NULL);
	}

	return (client);
}

void hspool::put(hsclient* client)
{
	acl_assert(client);
	locker_->lock();
	pool_.push_back(client);
	locker_->unlock();
}

}  // namespace acl
