//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.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 "searchlist.h"

CSearchFile::CSearchFile(CFile* in_data,uint32 nSearchID){
	
	m_nSearchID = nSearchID;
	in_data->Read(&filehash,16);
	in_data->Read(&clientip,4);
	in_data->Read(&clientport,2);
	uint32 tagcount;
	in_data->Read(&tagcount,4);
	for (int i = 0;i != tagcount; i++){
		CTag* toadd = new CTag(in_data);
		taglist.Add(toadd);
	}

	int iSize = 2;
	char* tempName = GetStrTagValue(FT_FILENAME);
	if( tempName != NULL && (strlen(tempName)>0) )
		iSize = (int)strlen(tempName)+1;
	filename = new char[iSize];
	if (tempName == NULL)
		strcpy(filename,"?");
	else
		strcpy(filename,tempName);
	filesize = GetIntTagValue(FT_FILESIZE);
}

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

uint32 CSearchFile::GetIntTagValue(uint8 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 tagname){
	for (int i = 0; i != taglist.GetSize(); i++){
		if (taglist[i]->tag->specialtag == tagname)
			return taglist[i]->tag->stringvalue;			
	}
	return 0;
}
uint32 CSearchFile::AddSources(uint32 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 CSearchFile::GetSourceCount(){
	return GetIntTagValue(FT_SOURCES);
}

CSearchList::CSearchList(){
	outputwnd = 0;
}

CSearchList::~CSearchList(){
	Clear();
}

void CSearchList::Clear(){
	for(POSITION pos = list.GetHeadPosition(); pos != NULL; pos = list.GetHeadPosition()) {
		delete list.GetAt(pos);
		list.RemoveAt(pos);
	}
}

void CSearchList::RemoveResults( uint32 nSearchID){
	// this will not delete the item from the window, make sure your code does it if you call this
	ASSERT( outputwnd );
	POSITION pos1, pos2;
	for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
		list.GetNext(pos1);
		CSearchFile* cur_file =	list.GetAt(pos2);
		if( cur_file->GetSearchID() == nSearchID ){
			list.RemoveAt(pos2);
			delete cur_file;
		}
	}
}

void CSearchList::ShowResults( uint32 nSearchID){
	ASSERT( outputwnd );
	outputwnd->SetRedraw(false);
	for (POSITION pos = list.GetHeadPosition(); pos !=0;list.GetNext(pos)){
		if( ((CSearchFile*)list.GetAt(pos))->GetSearchID() == nSearchID ){
			outputwnd->AddResult(list.GetAt(pos));
		}
	}
	outputwnd->SetRedraw(true);
}

void CSearchList::RemoveResults( CSearchFile* todel ){
	for (POSITION pos = list.GetHeadPosition(); pos !=0;list.GetNext(pos)){
		if( (CSearchFile*)list.GetAt(pos) == todel ){
			theApp.emuledlg->searchwnd.searchlistctrl.RemoveResult( todel );
			list.RemoveAt(pos);
			delete todel;
			return;
		}
	}
}

void CSearchList::NewSearch(CSearchListCtrl* in_wnd, CString resTypes, uint16 nSearchID){
	if(in_wnd)
		outputwnd = in_wnd;

	resultType=resTypes;
	m_nCurrentSearch = nSearchID;
	myHashList="";
	
	foundFilesCount.SetAt(nSearchID,0);
}

uint16 CSearchList::ProcessSearchanswer(char* in_packet, uint32 size, CUpDownClient* Sender){
	CSafeMemFile* packet = new CSafeMemFile((BYTE*)in_packet,size,0);
	if (Sender)
		theApp.emuledlg->searchwnd.CreateNewTab(CString(Sender->GetUserName()),(uint32)Sender);
	uint32 results;
	packet->Read(&results,4);

	uint32 mySearchID=( (Sender != NULL)? (uint32)Sender : m_nCurrentSearch);
	foundFilesCount.SetAt(mySearchID,0);

	for (int i = 0; i != results; i++){
		CSearchFile* toadd = new CSearchFile(packet, mySearchID);
		AddToList(toadd, (Sender != NULL) );
	}
	
	packet->Close();
	delete packet;
	return GetResultCount();
}

uint16 CSearchList::ProcessUDPSearchanswer(char* in_packet, uint32 size){
	CSafeMemFile* packet = new CSafeMemFile((BYTE*)in_packet,size,0);
	CSearchFile* toadd = new CSearchFile(packet, m_nCurrentSearch);
	AddToList(toadd);
	packet->Close();
	delete packet;
	return GetResultCount();
}

bool CSearchList::AddToList(CSearchFile* toadd, bool bClientResponse){
	if (!bClientResponse && !(resultType == GetResString(IDS_SEARCH_ANY) || GetFiletypeByName(toadd->GetFileName())==resultType)){
		delete toadd;
		return false;
	}
	for (POSITION pos = list.GetHeadPosition(); pos != NULL; list.GetNext(pos)){
		CSearchFile* cur_file = list.GetAt(pos);
		if ( (!memcmp(toadd->GetFileHash(),cur_file->GetFileHash(),16)) && cur_file->GetSearchID() ==  toadd->GetSearchID()){
			cur_file->AddSources(toadd->GetIntTagValue(FT_SOURCES));
			if (outputwnd)
				outputwnd->UpdateSources(cur_file);
			delete toadd;
			return true;
		}
	}
	
	if (list.AddTail(toadd)) {	
		uint16 tempValue;
		foundFilesCount.Lookup(toadd->GetSearchID(),tempValue);
		foundFilesCount.SetAt(toadd->GetSearchID(),tempValue+1);
	}
	if (outputwnd)
		outputwnd->AddResult(toadd);
	return true;
}

uint16 CSearchList::GetResultCount(uint32 nSearchID) {
	uint16 hits = 0;
	for (POSITION pos = list.GetHeadPosition(); pos != NULL; list.GetNext(pos)){
		if( list.GetAt(pos)->GetSearchID() == nSearchID )
			hits += list.GetAt(pos)->GetIntTagValue(FT_SOURCES);
	}
	return hits;
}


uint16 CSearchList::GetResultCount(){
	return GetResultCount(m_nCurrentSearch);
}

