// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-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"

#ifdef PRECOMP
    #include "xmule-headers.h"
#endif

#include "ClientList.h"                     // Needed for Module's Prototype(s) - audited 5 Nov 2004

#include "DownloadQueue.h"                  // Needed for CDownloadQueue - audited 5 Nov 2004
#include "ListenSocket.h"                   // Needed for CClientReqSocket - audited 5 Nov 2004
#include "updownclient.h"                   // Needed for CUpDownClient - audited 5 Nov 2004
#include "UploadQueue.h"                    // Needed for CUploadQueue - audited 5 Nov 2004
#include "xmule.h"                          // Needed for theApp - audited 4 Nov 2004

CClientList::CClientList()
{
}

CClientList::~CClientList()
{
}

// xrmb : statsclientstatus
void CClientList::GetStatistics(uint32_t &totalclient, int stats[], std::map<uint16_t, uint32_t>* clientVersionEDonkey, std::map< uint16_t, uint32_t >* clientVersionEDonkeyHybrid, std::map< uint8_t, uint32_t >* clientVersionEMule)
{
    memset(stats, 0, 8 * sizeof(int));
    //if(clientStatus)		clientStatus->RemoveAll();
    totalclient = list.GetCount();

    if (clientVersionEDonkey != NULL)
    {
        clientVersionEDonkey->clear();
    }

    if (clientVersionEMule != NULL)
    {
        clientVersionEMule->clear();
    }

    POSITION pos1, pos2;
    for (pos1 = list.GetHeadPosition(); (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
        CUpDownClient* cur_client = list.GetAt(pos2);
        switch (cur_client->GetClientSoft())
        {
        case SO_UNKNOWN: stats[0]++;
            break;
        case SO_EDONKEY:
            stats[1]++;
            if (clientVersionEDonkey)
            ( *clientVersionEDonkey) [cur_client->GetVersion() ]++;
            break;
        case SO_EDONKEYHYBRID:
            stats[4]++;
            if (clientVersionEDonkeyHybrid)
            ( *clientVersionEDonkeyHybrid) [cur_client->GetVersion() ]++;
            break;
        case SO_EMULE:
        case SO_OLDEMULE:
            stats[2]++;
            if (clientVersionEMule)
            {
                uint8_t version = cur_client->GetMuleVersion();
                ( *clientVersionEMule) [version]++;
            }
            break;
            //Didn't get much time to test this "xMule Compatable" feature.:
        case SO_CDONKEY:
            stats[5]++;
            break;
        case SO_AMULE:
        case SO_SHAREAZA:
        case SO_XMULE:
            stats[6]++;
            break;
        case SO_MLDONKEY:
            stats[3]++;
            break;
        case SO_NEW_MLDONKEY:
            stats[7]++;
            break;
        }
        //if(clientStatus) (*clientStatus)[cur_client->GetDownloadState()]++;
    }
}

void CClientList::AddClient(CUpDownClient *toadd, bool bSkipDupTest)
{
    if (!bSkipDupTest)
    {
        if (list.Find(toadd))
        return;
    }
    list.AddTail(toadd);
}

void CClientList::RemoveClient(CUpDownClient *toremove)
{
    POSITION pos = list.Find(toremove);
    if (pos)
    {
        //just to be sure...
        theApp.uploadqueue->RemoveFromUploadQueue(toremove);
        theApp.uploadqueue->RemoveFromWaitingQueue(toremove);
        theApp.downloadqueue->RemoveSource(toremove);
        list.RemoveAt(pos);
    }
}

void CClientList::DeleteAll()
{
    theApp.uploadqueue->DeleteAll();
    theApp.downloadqueue->DeleteAll();
    POSITION pos1, pos2;
    for (pos1 = list.GetHeadPosition() ; (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
        CUpDownClient* cur_client = list.GetAt(pos2);
        list.RemoveAt(pos2);
        // recursiv: this will call RemoveClient:
        delete cur_client;
    }
}

bool CClientList::AttachToAlreadyKnown(CUpDownClient **client, CClientReqSocket *sender)
{
    POSITION pos1, pos2;
    CUpDownClient *tocheck = ( *client);
    for (pos1 = list.GetHeadPosition() ; (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
        CUpDownClient *cur_client = list.GetAt(pos2);
        if (tocheck == cur_client)
        {
            return true;
        }
        if (tocheck->Compare(cur_client))
        {
            if (sender)
            {
                if (cur_client->socket)
                {
                    cur_client->socket->client = 0;
                    cur_client->socket->Safe_Delete();
                }
                cur_client->socket = sender;
                tocheck->socket = 0;
            }
            *client = 0;
            delete tocheck;
            *client = cur_client;
            return true;
        }
    }
    return false;
}

CUpDownClient *CClientList::FindClientByIP(uint32_t clientip, uint16_t port)
{
    POSITION pos1, pos2;
    for (pos1 = list.GetHeadPosition() ; (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
        CUpDownClient *cur_client = list.GetAt(pos2);
        if (cur_client->GetIP() == clientip &&cur_client->GetUserPort() == port)
        return cur_client;
    }
    return 0;
}

CUpDownClient *CClientList::FindClientByUserHash(unsigned char *clienthash)
{
    POSITION pos1, pos2;
    for (pos1 = list.GetHeadPosition() ; (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
        CUpDownClient *cur_client = list.GetAt(pos2);
        if (memcmp(cur_client->GetUserHash(), clienthash, 16))
        return cur_client;
    }
    return 0;
}

void CClientList::Debug_SocketDeleted(CClientReqSocket *deleted)
{
    POSITION pos1, pos2;
    for (pos1 = list.GetHeadPosition() ; (pos2 = pos1) != NULL ;)
    {
        list.GetNext(pos1);
    }
}

bool CClientList::Debug_IsValidClient(CUpDownClient *tocheck)
{
    return list.Find(tocheck);
}

