#include "StdAfx.h"
#include "bandwidthmgr.h"

CBandWidthMgr::CBandWidthMgr(void)
{
	m_curSend = 0;
	m_curRecv = 0;
	m_allSend = 0;
	m_allRecv = 0;
	m_allCount = 0;
}

CBandWidthMgr::~CBandWidthMgr(void)
{
}

void CBandWidthMgr::Load(CWorkspaceAccess setting)
{
	CWorkspaceAccess limit = setting.GetAccess("Limit");

	//	設定ロード
	m_SendMaxServerBandWidth = limit.GetConfig("Send::MaxServerBandWidth",0) * 1024;
	m_SendMaxOneHostBandWidth = limit.GetConfig("Send::MaxOneHostBandWidth",0) * 1024;
	m_SendMaxOneConnectBandWidth = limit.GetConfig("Send::MaxOneConnectBandWidth",0) * 1024;

	m_RecvMaxServerBandWidth = limit.GetConfig("Recv::MaxServerBandWidth",0) * 1024;
	m_RecvMaxOneHostBandWidth = limit.GetConfig("Recv::MaxOneHostBandWidth",0) * 1024;
	m_RecvMaxOneConnectBandWidth = limit.GetConfig("Recv::MaxOneConnectBandWidth",0) * 1024;

	m_MaxOneHostConnect = setting.GetConfig("Basic::MaxOneHostConnect",0);
}


//	接続の追加
void CBandWidthMgr::AddConnection(CIPAddress host,CString code,int sendLimit,int recvLimit)
{
	SCOPE_LOCK();

	int index = FindConnection(code);
	if(index != -1)
	{
		m_connections[index].m_hostAddress = host;
		m_connections[index].m_connectionCode = code;
		m_connections[index].m_sendLimit = sendLimit;
		m_connections[index].m_recvLimit = recvLimit;
	}
	else
	{
		m_connections.Add(COneConnection(host,code,sendLimit,recvLimit));
	}
}


//	接続の削除
void CBandWidthMgr::DelConnection(CString code)
{
	SCOPE_LOCK();

	int index = FindConnection(code);
	if(index != -1)
	{
		m_connections.RemoveAt(index);
	}
}


//	接続の検索
int CBandWidthMgr::FindConnection(CString code)
{
	SCOPE_LOCK();

	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_connectionCode == code)
			return(i);
	}

	return(-1);
}

//	全接続数の取得
int CBandWidthMgr::GetAllConnectionCount()
{
	SCOPE_LOCK();

	return((int)m_connections.GetCount());
}

//	一つのホストの接続数を取得する
int CBandWidthMgr::GetHostConnectionCount(CIPAddress host)
{
	SCOPE_LOCK();

	int count = 0;
	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_hostAddress == host)
			count++;
	}

	return(count);
}

//	送信規制中の接続数を取得
int CBandWidthMgr::GetAllSendConnectionCount()
{
	SCOPE_LOCK();

	int count = 0;
	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_sendLimit)
			count++;
	}
	return(count);
}

//	１ホストから送信規制中の接続数を取得
int CBandWidthMgr::GetHostSendConnectionCount(CIPAddress host)
{
	SCOPE_LOCK();

	int count = 0;
	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_hostAddress == host && m_connections[i].m_sendLimit)
			count++;
	}
	
	return(count);
}

//	受信規制中の接続数を取得
int CBandWidthMgr::GetAllRecvConnectionCount()
{
	SCOPE_LOCK();

	int count = 0;
	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_recvLimit)
			count++;
	}
	return(count);
}

//	１ホストから受信規制中の接続数を取得
int CBandWidthMgr::GetHostRecvConnectionCount(CIPAddress host)
{
	SCOPE_LOCK();

	int count = 0;
	for(int i=0;i<m_connections.GetSize();i++)
	{
		if(m_connections[i].m_hostAddress == host && m_connections[i].m_recvLimit)
			count++;
	}
	
	return(count);
}


//	現在の最大送信速度を取得
int CBandWidthMgr::GetCurrentSendLimit(CIPAddress host)
{
	CSortArray<int,int>	list;

	//	サーバ全体
	int count = GetAllSendConnectionCount();
	if(m_SendMaxServerBandWidth != 0 && count != 0)
		list.Add(m_SendMaxServerBandWidth / count);

	//	１ホスト
	count = GetHostSendConnectionCount(host);
	if(m_SendMaxOneHostBandWidth != 0 && count != 0)
		list.Add(m_SendMaxOneHostBandWidth / count);

	//	１接続
	if(m_SendMaxOneConnectBandWidth != 0)
		list.Add(m_SendMaxOneConnectBandWidth);

	
	if(list.GetSize())
	{
		//	小さい順にソート
		list.Sort();

		return(list[0]);
	}
	else
	{
		return(0);	//	無効
	}
}

//	現在の最大受信速度を取得
int CBandWidthMgr::GetCurrentRecvLimit(CIPAddress host)
{
	CSortArray<int,int>	list;

	//	サーバ全体
	int count = GetAllRecvConnectionCount();
	if(m_RecvMaxServerBandWidth != 0 && count != 0)
		list.Add(m_RecvMaxServerBandWidth / count);

	//	１ホスト
	count = GetHostRecvConnectionCount(host);
	if(m_RecvMaxOneHostBandWidth != 0 && count != 0)
		list.Add(m_RecvMaxOneHostBandWidth / count);

	//	１接続
	if(m_RecvMaxOneConnectBandWidth != 0)
		list.Add(m_RecvMaxOneConnectBandWidth);

	
	if(list.GetSize())
	{
		//	小さい順にソート
		list.Sort();

		return(list[0]);
	}
	else
	{
		return(0);	//	無効
	}
}

//	転送情報追加
void CBandWidthMgr::AddTrans(__int64 send,__int64 recv)
{
	SCOPE_LOCK();

	CTime cur = CTime::GetCurrentTime();
	m_curSend += send;
	m_curRecv += recv;
	m_allSend += send;
	m_allRecv += recv;
	m_allCount++;

	m_trans1h.Add(COneTrans(cur,send,recv));
}

//	過去１時間の転送量取得
__int64 CBandWidthMgr::GetSend1h()
{
	SCOPE_LOCK();

	return(m_curSend);
}

//	過去１時間の転送量取得
__int64 CBandWidthMgr::GetRecv1h()
{
	SCOPE_LOCK();

	return(m_curRecv);
}

//	過去１時間の接続数
int CBandWidthMgr::GetCount1h()
{
	SCOPE_LOCK();

	UpdateTransInfo();
	return((int)m_trans1h.GetSize());
}

//	起動してからの転送量取得
__int64 CBandWidthMgr::GetAllSend()
{
	SCOPE_LOCK();

	return(m_allSend);
}

//	起動してからの転送量取得
__int64 CBandWidthMgr::GetAllRecv()
{
	SCOPE_LOCK();

	return(m_allRecv);
}


//	起動してからの接続数
int CBandWidthMgr::GetAllCount()
{
	SCOPE_LOCK();

	return(m_allCount);
}

//	転送情報更新
void CBandWidthMgr::UpdateTransInfo()
{
	SCOPE_LOCK();

	CTime cur = CTime::GetCurrentTime();
	for(int i=0;i<m_trans1h.GetSize();i++)
	{
		if(m_trans1h[i].m_time + CTimeSpan(0,1,0,0) < cur)
		{
			m_curSend -= m_trans1h[i].m_send;
			m_curRecv -= m_trans1h[i].m_recv;
			m_trans1h.RemoveAt(i);
		}
		else
			break;
	}
}


//	初期化
CBandWidthReference::CBandWidthReference(CBandWidthMgr *mgr,CIPAddress host,CString code)
{
	m_mgr = mgr;
	m_hostAddress = host;
	m_connectionCode = code;
	m_sendLimit = 0;
	m_recvLimit = 0;

	m_mgr->AddConnection(host,code,m_sendLimit,m_recvLimit);
}

//	削除
CBandWidthReference::~CBandWidthReference()
{
	m_mgr->DelConnection(m_connectionCode);
}

//	送信リミットの設定
void CBandWidthReference::SetSendLimit(int enable)
{
	m_sendLimit = enable;
	m_mgr->AddConnection(m_hostAddress,m_connectionCode,m_sendLimit,m_recvLimit);
}

//	受信リミットの設定
void CBandWidthReference::SetRecvLimit(int enable)
{
	m_recvLimit = enable;
	m_mgr->AddConnection(m_hostAddress,m_connectionCode,m_sendLimit,m_recvLimit);
}

//	リミットのチェック
int CBandWidthReference::IsLimitOver()
{
	if(m_mgr->GetHostConnectionCount(m_hostAddress) > m_mgr->m_MaxOneHostConnect && m_mgr->m_MaxOneHostConnect != 0)
		return(1);
	return(0);
}

//	送信最高速度の取得
int CBandWidthReference::GetCurrentSendLimit()
{
	if(m_sendLimit)
		return(m_mgr->GetCurrentSendLimit(m_hostAddress));
	else
		return(0);
}

//	受信最高速度の取得
int CBandWidthReference::GetCurrentRecvLimit()
{
	if(m_recvLimit)
		return(m_mgr->GetCurrentRecvLimit(m_hostAddress));
	else
		return(0);
}


//	初期化
CBandWidthLimit::CBandWidthLimit()
{
	m_prevTick = GetTickCount();
	m_curTime = 0;
	m_curTrans = 0;
}


//	速度調整のウェイト時間を取得
int CBandWidthLimit::GetWaitTick(int limitBytePerSec,int transByte)
{
	//	変数初期化
	int	subTick = GetTickCount() - m_prevTick;
	m_transByte = transByte;

	//	制限なし
	if(limitBytePerSec == 0)
		return(0);

	//	制限されていた場合の時間
	int limitedTick = 	transByte * 1000 / limitBytePerSec;

	if(subTick < limitedTick)
		return(limitedTick - subTick);
	else
		return(0);
}


//	現在の速度を取得
int CBandWidthLimit::GetCurSpeed()
{
	double curTrans = m_curTrans, curTime = m_curTime;
	double speed = curTrans * 1000.0 / curTime;

	return((int)speed);
}

//	１回の転送が終了
void CBandWidthLimit::OneTracsEnd()
{
	DWORD	curTick = GetTickCount();
	int tick = curTick - m_prevTick;
	m_prevTick = curTick;
	
	m_curTime += tick;
	m_curTrans += m_transByte;
	m_transLog.Add(CTrans(m_transByte,tick));

	//	20回分以上は削除
	if(m_transLog.GetSize() > 20)
	{
		m_curTime -= m_transLog[0].m_time;

		m_curTrans -= m_transLog[0].m_size;
		m_transLog.RemoveAt(0);
	}

}
