// 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 "KnownFile.h"
#	include "KnownFileList.h"
#	include "SafeFile.h"
#	include "wintypes.h"
#	include "xmule.h"
#endif

#include <wx/utils.h>

static wxString KnownFileHash(const char *filename, uint32_t date, uint32_t size)
{
    return wxString::Format("%s%08lx%08lx", filename, static_cast<long unsigned int>(date), static_cast<long unsigned int>(size));
}

static wxString KnownFileHash(CKnownFile *file)
{
    return KnownFileHash(file->GetFileName(), file->GetFileDate(),
    file->GetFileSize());
}

CKnownFileList::CKnownFileList(char *in_appdir)
{
    appdir = in_appdir;
    accepted = 0;
    requested = 0;
    transfered = 0;
    Init();
}

CKnownFileList::~CKnownFileList()
{
    // TODO: Rather find the source of the lock leakage
    //	list_mut.Unlock();
    Clear();
}

bool CKnownFileList::Init()
{
    CKnownFile *Record = 0;
    CSafeFile file;
    /*try*/
    {
        char *fullpath = new char[strlen(appdir) + 10];
        strcpy(fullpath, appdir);
        strcat(fullpath, "known.met");
        if (!wxFileExists(fullpath))
        {
            //CFile::modeRead|CFile::osSequentialScan)) {
            delete[] fullpath;
            return false;
        }
        uint8_t header;
        file.Open(fullpath);
        delete[] fullpath;
        fullpath = NULL;
        file.Read( &header, 1);
        if (header != MET_HEADER)
        {
            file.Close();
            return false;
        }
        //CSingleLock sLock(&list_mut,true); // to make sure that its thread-safe
        wxMutexLocker sLock(list_mut);
        uint32_t RecordsNumber;
        file.Read( &RecordsNumber, 4);
        for (uint32_t i = 0 ; i != RecordsNumber ; i++)
        {
            Record = new CKnownFile();
            Record->LoadFromFile( &file);
            if (!Append(Record))
            delete Record;
        }
        //sLock.Unlock();
        file.Close();
        return true;
    }
#if 0
    catch(CFileException *error)
    {
        if (error->m_cause == CFileException::endOfFile)
        theApp.xmuledlg->AddLogLine(true, GetResString(IDS_ERR_SERVERMET_BAD));
        else
        {
            char buffer[150];
            error->GetErrorMessage(buffer, 150);
            theApp.xmuledlg->AddLogLine(true, GetResString(IDS_ERR_SERVERMET_UNKNOWN), buffer);
        }
        //memleak fix:
        error->Delete();
        return false;
    }
#endif
}

void CKnownFileList::Save()
{
    FILE *file = 0;
    char *fullpath = new char[strlen(appdir) + 1024];
    strcpy(fullpath, appdir);
    strcat(fullpath, "known.met");
    if (! (file = fopen(fullpath, "wb")))
    {
        delete[] fullpath;
        fullpath = NULL;
        return;
    }
    delete[] fullpath;
    fullpath = NULL;
    wxMutexLocker sLock(list_mut);
    fputc(MET_HEADER, file);
    uint32_t RecordsNumber = m_map.size();
    fwrite( &RecordsNumber, 4, 1, file);
    KnownFileMap::iterator it = m_map.begin();
    for (uint32_t i = 0 ; i != RecordsNumber ; i++, it++)
    {
        if (it == m_map.end())
        // TODO: Throw an exception:
        break;
        it->second->WriteToFile(file);
    }
    fclose(file);
}

void CKnownFileList::Clear()
{
    wxMutexLocker sLock(list_mut);
    for (KnownFileMap::iterator it = m_map.begin() ; it != m_map.end() ; it++)
    delete it->second;
    m_map.clear();
}

CKnownFile *CKnownFileList::FindKnownFile(char *filename, uint32_t in_date, uint32_t in_size)
{
    wxMutexLocker sLock(list_mut);
    KnownFileMap::iterator it = m_map.find(KnownFileHash(filename, in_date, in_size));
    if (it != m_map.end())
    return it->second;
    return 0;
}

bool CKnownFileList::SafeAddKFile(CKnownFile *toadd)
{
    wxMutexLocker sLock(list_mut);
    return Append(toadd);
}

bool CKnownFileList::Append(CKnownFile *Record)
{
    wxString HashString = KnownFileHash(Record);
    KnownFileMap::iterator it = m_map.find(HashString);
    if (it == m_map.end())
    {
        m_map[HashString] = Record;
        return true;
    }
    else
    {
        return false;
    }
}

