// 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.

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "muuli_wdr.h"
#include "packets.h"                        // Packet
#	include "SearchDlg.h"
#	include "SearchList.h"
#	include "updownclient.h"
#	include "xmuleDlg.h"
#endif

#include "wx/xrc/xmlres.h"
#include "wx/xrc/xh_all.h"

bool IsValidClientIPPort(uint32_t nIP, uint16_t nPort)
{
    // this filters most of the false data:
    return nIP != 0 &&nPort != 0 && ((nIP) != nPort)
    && ((nIP &0x000000FF) != 0)
    && ((nIP &0x0000FF00) != 0)
    && ((nIP &0x00FF0000) != 0)
    && ((nIP &0xFF000000) != 0);
}

CSearchFile::CSearchFile(char *in_data, wxUint32 nSearchID)
{
    //in_data==ascii-string until first '0x00'-byte
    int startpos = 0, endpos = 0, tagcount = 0, i = 0, c = 0;
    wxUint32 uFileSize = 0;
    int iAvailability = 0;
    m_nSearchID = nSearchID;
    while (in_data[endpos])
    {
        if (in_data[endpos] == '|')
        {
            switch (tagcount)
            {
                //clientid:
            case 0:
                m_nClientID = 0;
                while (startpos < endpos)
                {
                    m_nClientID = m_nClientID *10 + in_data[startpos++] - '0';
                }
                break;
                //clientport:
            case 1:
                m_nClientPort = 0;
                while (startpos < endpos)
                {
                    m_nClientPort = m_nClientPort *10 + in_data[startpos++] - '0';
                }
                break;
                //ed2kfilename:
            case 2:
                char *pszFileName;
                pszFileName = new char[1 + endpos - startpos];
                i = 0;
                while (startpos < endpos)
                {
                    pszFileName[i++] = in_data[startpos++];
                }
                pszFileName[i] = 0;
                taglist.Add(new CTag(FT_FILENAME, pszFileName));
                break;
                //ed2kfilesize:
            case 3:
                while (startpos < endpos)
                {
                    uFileSize = uFileSize *10 + in_data[startpos++] - '0';
                }
                taglist.Add(new CTag(FT_FILESIZE, uFileSize));
                break;
                //ed2kfileavailability:
            case 4:
                while (startpos < endpos)
                {
                    iAvailability = iAvailability *10 + in_data[startpos++] - '0';
                }
                taglist.Add(new CTag(FT_SOURCES, iAvailability));
                break;
                //ed2kfiletype:
            case 5:
                break;
                //ed2kfileid(md4):
            case 6:
                i = 0;
                while (startpos < endpos &&i < 16)
                {
                    c = in_data[startpos++];
                    if (c >= 'a' &&c <= 'f') m_abyFileHash[i] = c - 'a' + 10;
                    else if(c >= 'A' &&c <= 'F') m_abyFileHash[i] = c - 'A' + 10;
                    else if(c >= '0' &&c <= '9') m_abyFileHash[i] = c - '0';
                    c = in_data[startpos++];
                    m_abyFileHash[i] = m_abyFileHash[i] << 4;
                    if (c >= 'a' &&c <= 'f') m_abyFileHash[i] += c - 'a' + 10;
                    else if(c >= 'A' &&c <= 'F') m_abyFileHash[i] += c - 'A' + 10;
                    else if(c >= '0' &&c <= '9') m_abyFileHash[i] += c - '0';
                    i++;
                }
                break;
                //ed2kfileartist:
            case 7:
                break;
                //ed2kfilealbum:
            case 8:
                break;
                //ed2kfiletitle:
            case 9:
                break;
                //ed2kfilelength:
            case 10:
                break;
                //ed2kfilebitrate:
            case 11:
                break;
                //ed2kfilecodec:
            case 12:
                break;
            default:
                break;
            }
            startpos = endpos + 1;
            tagcount++;
        }
        endpos++;
    }
    if (!IsValidClientIPPort(m_nClientID, m_nClientPort))
    {
        m_nClientID = 0;
        m_nClientPort = 0;
    }
    m_nClientServerIP = 0;
    m_nClientServerPort = 0;
    m_pszDirectory = NULL;
    m_list_bExpanded = false;
    m_list_parent = NULL;
    m_list_childcount = 0;
    m_bPreviewPossible = false;
}

CSearchFile::CSearchFile(CFile *in_data, uint32_t nSearchID, uint32_t nServerIP, uint16_t nServerPort, LPCTSTR pszDirectory)
{
    m_nSearchID = nSearchID;
    in_data->Read( &m_abyFileHash, 16);
    in_data->Read( &m_nClientID, 4);
    in_data->Read( &m_nClientPort, 2);
    if ((m_nClientID || m_nClientPort) && !IsValidClientIPPort(m_nClientID, m_nClientPort))
    {
        m_nClientID = 0;
        m_nClientPort = 0;
    }
    uint32_t tagcount;
    in_data->Read( &tagcount, 4);
    for (unsigned int i = 0 ; i != tagcount ;++i)
    {
        CTag *toadd = new CTag(in_data);
        taglist.Add(toadd);
    }
    // here we have two choices
    //	- if the server/client sent us a filetype, we could use it (though it could be wrong)
    //	- we always trust our filetype list and determine the filetype by the extension of the file
    char *tempName = GetStrTagValue(FT_FILENAME);
    if (!tempName)
    throw CInvalidPacket("No filename in search result");
    int iSize = (int) strlen(tempName) + 1;
    // required by tag format:
    if (iSize < 2) iSize = 2;
    m_pszFileName = new char[iSize];
    strcpy(m_pszFileName, tempName);
    m_nFileSize = GetIntTagValue(FT_FILESIZE);
    m_nClientServerIP = nServerIP;
    m_nClientServerPort = nServerPort;
    if (m_nClientServerIP &&m_nClientServerPort)
    {
        SServer *server = new SServer(m_nClientServerIP, m_nClientServerPort);
        server->m_uAvail = GetIntTagValue(FT_SOURCES);
        AddServer(server);
    }
    m_list_bExpanded = false;
    m_list_parent = NULL;
    m_list_childcount = 0;
    m_bPreviewPossible = false;
}

CSearchFile::CSearchFile(uint32_t nSearchID, const unsigned char *pucFileHash, uint32_t uFileSize, char *pszFileName, int iFileType, int iAvailability)
{
    m_nSearchID = nSearchID;
    md4cpy(m_abyFileHash, pucFileHash);
    taglist.Add(new CTag(FT_FILESIZE, uFileSize));
    taglist.Add(new CTag(FT_FILENAME, pszFileName));
    taglist.Add(new CTag(FT_SOURCES, iAvailability));
    SetFileName(pszFileName);
    SetFileSize(uFileSize);
    m_nClientID = 0;
    m_nClientPort = 0;
    m_nClientServerIP = 0;
    m_nClientServerPort = 0;
    m_pszDirectory = NULL;
    m_list_bExpanded = false;
    m_list_parent = NULL;
    m_list_childcount = 0;
    m_bPreviewPossible = false;
}

CSearchFile::~CSearchFile()
{
    for (int i = 0 ; i != taglist.GetSize() ; i++)
    {
        delete taglist[i];
    }

    taglist.RemoveAll();
    taglist.SetSize(0);
}

uint32_t CSearchFile::GetIntTagValue(uint8_t tagname)
{
    for (int i = 0 ; i != taglist.GetSize() ; i++)
    {
        if (taglist[i]->tag->specialtag == tagname)
        return taglist[i]->tag->intvalue;
    }
    return 0;
}

char *CSearchFile::GetStrTagValue(uint8_t tagname)
{
    for (int i = 0 ; i != taglist.GetSize() ; i++)
    {
        if (taglist[i]->tag->specialtag == tagname)
        return taglist[i]->tag->stringvalue;
    }
    return 0;
}

uint32_t CSearchFile::AddSources(uint32_t count)
{
    for (int i = 0 ; i != taglist.GetSize() ; i++)
    {
        if (taglist[i]->tag->specialtag == FT_SOURCES)
        {
            taglist[i]->tag->intvalue += count;
            return taglist[i]->tag->intvalue;
        }
    }
    return 0;
}

uint32_t CSearchFile::GetSourceCount()
{
    return GetIntTagValue(FT_SOURCES);
}

