// 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
//
// 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"
#endif

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

#include "KnownFile.h"                      // Needed for CKnownFile - audited 4 Nov 2004
#include "opcodes.h"                        // Needed for ID_XMULEDLG - audited 4 Nov 2004
#include "otherfunctions.h"                 // Needed for nstrdup - audited 4 Nov 2004
#include "xmule.h"                          // Needed for theApp - audited 4 Nov 2004
#include "xmuleDlg.h"                       // Needed for theApp.xmuledlg - audited 4 Nov 2004

#include <wx/event.h>                       // Needed for wxCommandEvent

struct UnknownFile_Struct
{
    char *name;
    char *directory;
    CPartFile *owner;
};

wxMutex CAddFileThread::m_lockWaitingForHashList;

wxCondition CAddFileThread::m_runWaitingForHashList(m_lockWaitingForHashList);

CTypedPtrList < CPtrList, UnknownFile_Struct *> CAddFileThread::m_sWaitingForHashList;

volatile int CAddFileThread::m_endWaitingForHashList;

CAddFileThread::CAddFileThread(): wxThread(wxTHREAD_DETACHED)
{
}

void CAddFileThread::Setup()
{
    CAddFileThread *th = new CAddFileThread();
    th->Create();
    th->Run();
}

void CAddFileThread::Shutdown()
{
    m_lockWaitingForHashList.Lock();
#if defined(__DEBUG__)
    printf("Signaling hashing thread to terminate\n");
#endif
    // Tell the thread to exit
    m_endWaitingForHashList = 1;
    // Signal the thread there is something to do
    m_runWaitingForHashList.Signal();
    m_lockWaitingForHashList.Unlock();
}

void CAddFileThread::AddFile(const char *path, const char *name, CPartFile *part)
{
    UnknownFile_Struct *hashfile = new UnknownFile_Struct;
    hashfile->directory = nstrdup(path);
    hashfile->name = nstrdup(name);
    hashfile->owner = part;
    wxMutexLocker sLock(m_lockWaitingForHashList);
    m_sWaitingForHashList.AddTail(hashfile);
    m_runWaitingForHashList.Signal();
}

wxThread::ExitCode CAddFileThread::Entry()
{
    while (1)
    {
        m_lockWaitingForHashList.Lock();
        if (m_endWaitingForHashList)
        {
            m_lockWaitingForHashList.Unlock();
            wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, TM_HASHTHREADFINISHED);
            wxPostEvent(wxWindow::FindWindowById(ID_XMULEDLG), evt);
            return 0;
        }
        if (m_sWaitingForHashList.IsEmpty())
        {
            m_runWaitingForHashList.Wait();
            m_lockWaitingForHashList.Unlock();
            continue;
        }
        UnknownFile_Struct *hashfile = m_sWaitingForHashList.RemoveHead();
        m_lockWaitingForHashList.Unlock();
        CKnownFile *newrecord = new CKnownFile();
        printf("Sharing %s/%s\n", hashfile->directory, hashfile->name);
        // TODO: What we are supposed to do if the following does fail?
        newrecord->CreateFromFile(hashfile->directory, hashfile->name, &m_endWaitingForHashList);
        if (!m_endWaitingForHashList)
        {
            wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, TM_FINISHEDHASHING);
            evt.SetClientData(newrecord);
            evt.SetInt((int) hashfile->owner);
            wxPostEvent(theApp.xmuledlg, evt);
        }
        delete[] hashfile->name;
        delete[] hashfile->directory;
        delete hashfile;
    }
}

int CAddFileThread::GetCount()
{
    return m_sWaitingForHashList.GetCount();
}

