//this file is part of eMule
//Copyright (C)2002-2007 Merkur ( strEmail.Format("%s@%s", "devteam", "emule-project.net") / http://www.emule-project.net )
//
//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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "Friend.h"
#include "FriendList.h"
#include "OtherFunctions.h"
#include "UpDownClient.h"
#include "Packets.h"
#include "SafeFile.h"
#include "clientlist.h"
#include "ClientCredits.h" //>>> WiZaRd::Data without Client

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


CFriend::CFriend(void)
{
	m_dwLastSeen = 0;
	m_dwLastUsedIP = 0;
	m_nLastUsedPort = 0;
	m_dwLastChatted = 0;
	(void)m_strName;
#ifdef MOD_FUNCTIONS
	(void)m_strEMFName; //>>> WiZaRd::PNCheck/EMF
#endif
	m_LinkedClient = 0;
	md4clr(m_abyUserhash);

    m_friendSlot = false;
//>>> WiZaRd::Data without Client
	m_strSoft = _T("");
	m_uiUploaded = -1;
	m_uiDownloaded = -1;
//<<< WiZaRd::Data without Client
}

//Added this to work with the IRC.. Probably a better way to do it.. But wanted this in the release..
CFriend::CFriend(const uchar* abyUserhash, uint32 dwLastSeen, uint32 dwLastUsedIP, uint16 nLastUsedPort, 
				 uint32 dwLastChatted, LPCTSTR pszName, uint32 dwHasHash)
{
	m_dwLastSeen = dwLastSeen;
	m_dwLastUsedIP = dwLastUsedIP;
	m_nLastUsedPort = nLastUsedPort;
	m_dwLastChatted = dwLastChatted;
	if(dwHasHash && abyUserhash)
	{
		md4cpy(m_abyUserhash,abyUserhash);
	}
	else
		md4clr(m_abyUserhash);

	m_strName = pszName;
#ifdef MOD_FUNCTIONS
	(void)m_strEMFName; //>>> WiZaRd::PNCheck/EMF
#endif
	m_LinkedClient = 0;
    m_friendSlot = false;
//>>> WiZaRd::Data without Client
	m_strSoft = _T("");
	m_uiUploaded = -1;
	m_uiDownloaded = -1;
//<<< WiZaRd::Data without Client
}

CFriend::CFriend(CUpDownClient* client){
	ASSERT ( client );
	m_dwLastSeen = time(NULL);
	m_dwLastUsedIP = client->GetIP();
	m_nLastUsedPort = client->GetUserPort();
	m_dwLastChatted = 0;
    m_LinkedClient = NULL;
    m_friendSlot = false;
//>>> WiZaRd::Data without Client
	m_strSoft = _T("");
	m_uiUploaded = -1;
	m_uiDownloaded = -1;
//<<< WiZaRd::Data without Client
    SetLinkedClient(client);
}

CFriend::~CFriend(void)
{
	if(GetLinkedClient(true) != NULL)
	{
		m_LinkedClient->SetFriendSlot(false);
		m_LinkedClient->m_Friend = NULL;
		m_LinkedClient = NULL;
	}
}

void CFriend::LoadFromFile(CFileDataIO* file)
{
	file->ReadHash16(m_abyUserhash);
	m_dwLastUsedIP = file->ReadUInt32();
	m_nLastUsedPort = file->ReadUInt16();
	m_dwLastSeen = file->ReadUInt32();
	m_dwLastChatted = file->ReadUInt32();

	UINT tagcount = file->ReadUInt32();
	for (UINT j = 0; j < tagcount; j++)
	{
		CTag* newtag = new CTag(file, false);
		switch (newtag->GetNameID())
		{
			case FF_NAME:
			{
				ASSERT( newtag->IsStr() );
				if (newtag->IsStr())
				{
					if (m_strName.IsEmpty())
						m_strName = newtag->GetStr();
				}
				break;
			}
			default:
			{
				if(newtag->GetNameID() == 0)
				{
					const LPCSTR tagname = newtag->GetName();
//>>> WiZaRd::Save FU
					if(strcmp(tagname, FF_FRIENDSLOT) == 0)
					{
						if(newtag->IsInt())
							m_friendSlot = newtag->GetInt() == 1;
					}
//<<< WiZaRd::Save FU
#ifdef MOD_FUNCTIONS
//>>> WiZaRd::PNCheck/EMF
					else if(strcmp(tagname, FF_EMF_NAME) == 0)
					{
						if(newtag->IsStr())
							m_strEMFName = newtag->GetStr();
					}
//<<< WiZaRd::PNCheck/EMF
#endif
//>>> WiZaRd::Data without Client
					else if(strcmp(tagname, FF_SOFT) == 0)
					{
						if(newtag->IsStr())
							m_strSoft = newtag->GetStr(); 
					}
					else if(strcmp(tagname, FF_UPLOAD) == 0)
					{
						if(newtag->IsInt64())
							m_uiUploaded = newtag->GetInt64();
					}
					else if(strcmp(tagname, FF_DOWNLOAD) == 0)
					{
						if(newtag->IsInt64())
							m_uiDownloaded = newtag->GetInt64();
					}
//<<< WiZaRd::Data without Client
				}
				break;			
			}
		}
		delete newtag;
	}
}

void CFriend::WriteToFile(CFileDataIO* file)
{
	file->WriteHash16(m_abyUserhash);
	file->WriteUInt32(m_dwLastUsedIP);
	file->WriteUInt16(m_nLastUsedPort);
	file->WriteUInt32(m_dwLastSeen);
	file->WriteUInt32(m_dwLastChatted);

	uint32 uTagCount = 0;
	ULONG uTagCountFilePos = (ULONG)file->GetPosition();
	file->WriteUInt32(uTagCount);

	if (!m_strName.IsEmpty()){
		if (WriteOptED2KUTF8Tag(file, m_strName, FF_NAME))
			uTagCount++;
		CTag nametag(FF_NAME, m_strName);
		nametag.WriteTagToFile(file);
		uTagCount++;
	}

//>>> WiZaRd::Save FU
	if((m_LinkedClient != NULL && m_LinkedClient->GetFriendSlot()) || (m_LinkedClient == NULL && m_friendSlot)) 
	{
		CTag wrtag(FF_FRIENDSLOT, 1);
		wrtag.WriteTagToFile(file);
		uTagCount++;
	}
//<<< WiZaRd::Save FU
#ifdef MOD_FUNCTIONS
//>>> WiZaRd::PNCheck/EMF
	if(!m_strEMFName.IsEmpty())
	{
		CTag emftag(FF_EMF_NAME, m_strEMFName);
		emftag.WriteTagToFile(file);
		uTagCount++;
	}
//<<< WiZaRd::PNCheck/EMF
#endif
//>>> WiZaRd::Data without Client
	if(m_LinkedClient != NULL || !m_strSoft.IsEmpty())
	{
		if(m_LinkedClient)
//>>> WiZaRd::Show ModVer
			m_strSoft = m_LinkedClient->DbgGetFullClientSoftVer(); 
			//m_strSoft = m_LinkedClient->GetClientSoftVer();
//<<< WiZaRd::Show ModVer
		CTag wrtag(FF_SOFT, m_strSoft);
		wrtag.WriteTagToFile(file);
		uTagCount++;
	}
	if((m_LinkedClient != NULL && m_LinkedClient->Credits() && m_LinkedClient->Credits()->GetUploadedTotal()) || m_uiUploaded > -1) 
	{
		if(m_LinkedClient != NULL && m_LinkedClient->Credits() && m_LinkedClient->Credits()->GetUploadedTotal())
			m_uiUploaded = m_LinkedClient->Credits()->GetUploadedTotal();
		CTag wrtag(FF_UPLOAD, m_uiUploaded);
		wrtag.WriteTagToFile(file);
		uTagCount++;
	}
	if((m_LinkedClient != NULL && m_LinkedClient->Credits() && m_LinkedClient->Credits()->GetDownloadedTotal()) || m_uiDownloaded > -1) 
	{
		if(m_LinkedClient != NULL && m_LinkedClient->Credits() && m_LinkedClient->Credits()->GetDownloadedTotal())
			m_uiDownloaded = m_LinkedClient->Credits()->GetDownloadedTotal();
		CTag wrtag(FF_DOWNLOAD, m_uiDownloaded);
		wrtag.WriteTagToFile(file);
		uTagCount++;
	}
//<<< WiZaRd::Data without Client

	file->Seek(uTagCountFilePos, CFile::begin);
	file->WriteUInt32(uTagCount);
	file->Seek(0, CFile::end);
}

bool CFriend::HasUserhash() const
{
    for(int counter = 0; counter < 16; counter++) 
        if(m_abyUserhash[counter] != 0) 
            return true;

    return false;
}

void CFriend::SetFriendSlot(bool newValue) 
{
    if(GetLinkedClient() != NULL) 
        m_LinkedClient->SetFriendSlot(newValue);

    m_friendSlot = newValue;
}

bool CFriend::GetFriendSlot() const 
{
    if(GetLinkedClient() != NULL) 
        return m_LinkedClient->GetFriendSlot();
    else 
        return m_friendSlot;
}

void CFriend::SetLinkedClient(CUpDownClient* linkedClient) 
{
	if(linkedClient != m_LinkedClient) 
	{
		if(linkedClient != NULL) 
		{
          	if(m_LinkedClient == NULL) 
           		linkedClient->SetFriendSlot(m_friendSlot);
          	else 
           		linkedClient->SetFriendSlot(m_LinkedClient->GetFriendSlot());

			m_dwLastSeen = time(NULL);
			m_dwLastUsedIP = linkedClient->GetIP();
			m_nLastUsedPort = linkedClient->GetUserPort();
//>>> WiZaRd::PNCheck/EMF
#ifdef MOD_FUNCTIONS
			if(m_strName.IsEmpty())
				m_strName = linkedClient->GetUserName(); 
			else
				linkedClient->SetUserName(m_strName);
#else
			m_strName = linkedClient->GetUserName(); 
#endif
//<<< WiZaRd::PNCheck/EMF
			md4cpy(m_abyUserhash,linkedClient->GetUserHash());
//>>> WiZaRd::Data without Client
//>>> WiZaRd::Show ModVer
			m_strSoft = linkedClient->DbgGetFullClientSoftVer();
//			m_strSoft = linkedClient->GetClientSoftVer();
//<<< WiZaRd::Show ModVer
			if(linkedClient->Credits())
			{
				m_uiUploaded = linkedClient->Credits()->GetUploadedTotal();
				m_uiDownloaded = linkedClient->Credits()->GetDownloadedTotal();
			}
//<<< WiZaRd::Data without Client
			linkedClient->m_Friend = this;
		} 
		else if(m_LinkedClient != NULL) 
		{
//>>> WiZaRd::Data without Client
//>>> WiZaRd::Show ModVer
			m_strSoft = m_LinkedClient->DbgGetFullClientSoftVer();
//			m_strSoft = m_LinkedClient->GetClientSoftVer();
//<<< WiZaRd::Show ModVer
			if(m_LinkedClient->Credits())
			{
				m_uiUploaded = m_LinkedClient->Credits()->GetUploadedTotal();
				m_uiDownloaded = m_LinkedClient->Credits()->GetDownloadedTotal();
			}
//<<< WiZaRd::Data without Client
			m_friendSlot = m_LinkedClient->GetFriendSlot();
		}

		if(m_LinkedClient != NULL) 
		{
			// the old client is no longer friend, since it is no longer the linked client
			m_LinkedClient->SetFriendSlot(false);
			m_LinkedClient->m_Friend = NULL;
		}

		m_LinkedClient = linkedClient;
	}
	theApp.friendlist->RefreshFriend(this);
}

CUpDownClient* CFriend::GetLinkedClient(bool bValidCheck) const
{
	if (bValidCheck && m_LinkedClient != NULL && !theApp.clientlist->IsValidClient(m_LinkedClient)){
		ASSERT( false );
		return NULL;
	}
	return m_LinkedClient; 
}

//>>> Data without Client
CString	CFriend::GetFriendName() const
{
	if(GetLinkedClient())
		return GetLinkedClient()->GetUserName();
	else if (!m_strName.IsEmpty())
		return m_strName;
	else
		return GetResString(IDS_UNKNOWN);
}

CString CFriend::GetFriendHash() const
{
	if (GetLinkedClient())
		return md4str(GetLinkedClient()->GetUserHash());
	else if (HasUserhash())
		return md4str(m_abyUserhash);
	else
		return GetResString(IDS_UNKNOWN);
}

CString	CFriend::GetIdentState() const
{
	if (GetLinkedClient())
	{
		if (theApp.clientcredits->CryptoAvailable() && GetLinkedClient()->Credits())
		{
			switch(GetLinkedClient()->Credits()->GetCurrentIdentState(GetLinkedClient()->GetIP()))
			{
				case IS_NOTAVAILABLE:
					return GetResString(IDS_IDENTNOSUPPORT);
				case IS_IDFAILED:
				case IS_IDNEEDED:
				case IS_IDBADGUY:
					return GetResString(IDS_IDENTFAILED);
				case IS_IDENTIFIED:
					return GetResString(IDS_IDENTOK);
			}
		}
		else
			return GetResString(IDS_IDENTNOSUPPORT);
	}
	return GetResString(IDS_UNKNOWN);
}

CString	CFriend::GetFriendSoft() const
{
	if (GetLinkedClient())
//>>> WiZaRd::Show ModVer
		return GetLinkedClient()->DbgGetFullClientSoftVer();
//		return GetLinkedClient()->GetClientSoftVer();
//<<< WiZaRd::Show ModVer
	else if (!m_strSoft.IsEmpty())
		return m_strSoft;
	else
		return GetResString(IDS_UNKNOWN);
}

CString	CFriend::GetFriendUploaded() const
{
	if(GetLinkedClient() && GetLinkedClient()->Credits())
		return CastItoXBytes(GetLinkedClient()->Credits()->GetUploadedTotal(), false, false);
	else if(m_uiUploaded > -1)
		return CastItoXBytes((uint64)m_uiUploaded, false, false);
	else
		return GetResString(IDS_UNKNOWN);
}

CString	CFriend::GetFriendDownloaded() const
{
	if(GetLinkedClient() && GetLinkedClient()->Credits())
		return CastItoXBytes(GetLinkedClient()->Credits()->GetDownloadedTotal(), false, false);
	else if(m_uiDownloaded > -1)
		return CastItoXBytes((uint64)m_uiDownloaded, false, false);
	else
		return GetResString(IDS_UNKNOWN);
}
//<<< Data without Client
