/* 
 * Copyright (C) 2012 Yee Young Han <websearch@naver.com> (http://blog.naver.com/websearch)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

#include "SipStackDefine.h"
#include "SipServerMap.h"
#include "UserMap.h"
#include "MemoryDebug.h"

CSipServerMap gclsSipServerMap;

CSipServerInfo::CSipServerInfo() : m_iPort(5060), m_bUse(true), m_bDelete(false)
{
}

/**
 * @ingroup SipLoadBalancer
 * @brief ÀÔ·ÂµÈ IP ÁÖ¼Ò ¹× Æ÷Æ® ¹øÈ£°¡ SIP ¼­¹ö Á¤º¸¿Í ÀÏÄ¡ÇÏ´ÂÁö °Ë»çÇÑ´Ù.
 * @param pszIp IP ÁÖ¼Ò
 * @param iPort Æ÷Æ® ¹øÈ£
 * @returns ÀÔ·Â‰é Á¤º¸°¡ SIP ¼­¹ö Á¤º¸¿Í ÀÏÄ¡ÇÏ¸é true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
 */
bool CSipServerInfo::Equal( const char * pszIp, int iPort )
{
	if( !strcmp( m_strIp.c_str(), pszIp ) && m_iPort == iPort ) return true;

	return false;
}

CSipServerMap::CSipServerMap() : m_iIndex(0)
{
}

CSipServerMap::~CSipServerMap()
{
}

/**
 * @ingroup SipLoadBalancer
 * @brief SIP ¼­¹ö Á¤º¸¸¦ ¸®½ºÆ®¿¡ Ãß°¡ÇÑ´Ù.
 * @param pszIp IP ÁÖ¼Ò
 * @param iPort Æ÷Æ® ¹øÈ£
 * @param bUse	»ç¿ë À¯¹«
 * @returns ¼º°øÇÏ¸é true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
 */
bool CSipServerMap::Insert( const char * pszIp, int iPort, bool bUse )
{
	if( pszIp == NULL || strlen(pszIp) == 0 ) return false;
	if( iPort <= 0 || iPort > 65535 ) return false;

	// ÀÌ¹Ì ¸®½ºÆ®¿¡ Á¸ÀçÇÏ¸é Ãß°¡ÇÏÁö ¾Ê´Â´Ù.
	if( Select( pszIp, iPort, bUse ) ) return true;

	CSipServerInfo clsInfo;

	clsInfo.m_strIp = pszIp;
	clsInfo.m_iPort = iPort;
	clsInfo.m_bUse = bUse;
	
	m_clsMutex.acquire();
	m_clsList.push_back( clsInfo );
	m_clsMutex.release();

	return true;
}

/**
 * @ingroup SipLoadBalancer
 * @brief Á¢¼ÓÇÒ SIP ¼­¹ö Á¤º¸¸¦ °¡Á®¿Â´Ù.
 * @param clsInfo SIP ¼­¹ö Á¤º¸¸¦ ÀúÀåÇÏ´Â º¯¼ö
 * @returns ¼º°øÇÏ¸é true ¸¦ ¸®ÅÏÇÏ°í ½ÇÆÐÇÏ¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
 */
bool CSipServerMap::SelectNext( CSipServerInfo & clsInfo )
{
	bool bRes = false;

	m_clsMutex.acquire();
	int iCount = (int)m_clsList.size();
	if( iCount > 0 )
	{
		if( m_iIndex >= iCount )
		{
			m_iIndex = 0;
		}

		clsInfo = m_clsList[m_iIndex];
		++m_iIndex;

		bRes = true;
	}
	m_clsMutex.release();

	return bRes;
}

/**
 * @ingroup SipLoadBalancer
 * @brief ÀÔ·ÂµÈ IP ÁÖ¼Ò, Æ÷Æ®¹øÈ£¿Í ÀÏÄ¡ÇÏ´Â SIP ¼­¹ö Á¤º¸°¡ Á¸ÀçÇÏ´ÂÁö °Ë»çÇÑ´Ù.
 * @param pszIp IP ÁÖ¼Ò
 * @param iPort Æ÷Æ® ¹øÈ£
 * @returns SIP ¼­¹ö°¡ °Ë»öµÇ¸é true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
 */
bool CSipServerMap::Select( const char * pszIp, int iPort )
{
	SIP_SERVER_LIST::iterator itList;
	bool bFound = false;

	m_clsMutex.acquire();
	for( itList = m_clsList.begin(); itList != m_clsList.end(); ++itList )
	{
		if( itList->Equal( pszIp, iPort ) )
		{
			bFound = true;
			break;
		}
	}
	m_clsMutex.release();

	return bFound;
}

/**
 * @ingroup SipLoadBalancer
 * @brief ÀÔ·ÂµÈ IP ÁÖ¼Ò, Æ÷Æ®¹øÈ£¿Í ÀÏÄ¡ÇÏ´Â SIP ¼­¹ö Á¤º¸°¡ Á¸ÀçÇÏ¸é »ç¿ë À¯¹« ¹× »èÁ¦ À¯¹«¸¦ ¾÷µ¥ÀÌÆ®ÇÑ´Ù.
 * @param pszIp IP ÁÖ¼Ò
 * @param iPort Æ÷Æ® ¹øÈ£
 * @param bUse	»ç¿ë À¯¹«
 * @returns SIP ¼­¹ö°¡ °Ë»öµÇ¸é true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
 */
bool CSipServerMap::Select( const char * pszIp, int iPort, bool bUse )
{
	SIP_SERVER_LIST::iterator itList;
	bool bFound = false;

	m_clsMutex.acquire();
	for( itList = m_clsList.begin(); itList != m_clsList.end(); ++itList )
	{
		if( itList->Equal( pszIp, iPort ) )
		{
			itList->m_bUse = bUse;
			itList->m_bDelete = false;
			bFound = true;
			break;
		}
	}
	m_clsMutex.release();

	return bFound;
}

/**
 * @ingroup SipLoadBalancer
 * @brief ¸ðµç SIP ¼­¹ö Á¤º¸¿¡ »èÁ¦ Ç¥½Ã¸¦ ÇÑ´Ù.
 */
void CSipServerMap::SetDeleteAll( )
{
	SIP_SERVER_LIST::iterator itList;

	m_clsMutex.acquire();
	for( itList = m_clsList.begin(); itList != m_clsList.end(); ++itList )
	{
		itList->m_bDelete = true;
	}
	m_clsMutex.release();
}

/**
 * @ingroup SipLoadBalancer
 * @brief »èÁ¦ Ç¥½Ã°¡ µÈ SIP ¼­¹ö¸¦ »èÁ¦ÇÑ´Ù.
 */
void CSipServerMap::DeleteIfSet( )
{
	SIP_SERVER_LIST::iterator itList, itNext;

	m_clsMutex.acquire();
	for( itList = m_clsList.begin(); itList != m_clsList.end(); ++itList )
	{
LOOP_START:
		if( itList->m_bDelete == false ) 
		{
			if( itList->m_bUse == false )
			{
				gclsUserMap.DeleteSipServer( itList->m_strIp.c_str(), itList->m_iPort );
			}
			continue;
		}

		itNext = itList;
		++itNext;

		gclsUserMap.DeleteSipServer( itList->m_strIp.c_str(), itList->m_iPort );
		m_clsList.erase( itList );

		if( itNext == m_clsList.end() ) break;

		itList = itNext;
		goto LOOP_START;
	}
	m_clsMutex.release();
}

/**
 * @ingroup SipLoadBalancer
 * @brief ÀÚ·á±¸Á¶ ¸ð´ÏÅÍ¸µ¿ë ¹®ÀÚ¿­À» »ý¼ºÇÑ´Ù. 
 * @param strBuf ÀÚ·á±¸Á¶ ¸ð´ÏÅÍ¸µ¿ë ¹®ÀÚ¿­ º¯¼ö
 */
void CSipServerMap::GetString( CMonitorString & strBuf )
{
	SIP_SERVER_LIST::iterator itList;

	strBuf.Clear();

	m_clsMutex.acquire();
	for( itList = m_clsList.begin(); itList != m_clsList.end(); ++itList )
	{
		strBuf.AddCol( itList->m_strIp, itList->m_iPort );
		strBuf.AddCol( itList->m_bUse ? "use" : "no use" );
		strBuf.AddRow( itList->m_bDelete ? "del" : "" );
	}
	m_clsMutex.release();
}
