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


// SearchListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "emule.h"
#include "SearchListCtrl.h"
#include "otherfunctions.h"


// CSearchListCtrl

IMPLEMENT_DYNAMIC(CSearchListCtrl, CMuleListCtrl)
CSearchListCtrl::CSearchListCtrl() {
	memset(&asc_sort,0,6);
   searchlist = 0;  // i_a 
   m_nResultsID = 0; // i_a 
}

void CSearchListCtrl::Init(CSearchList* in_searchlist){
	SetExtendedStyle(LVS_EX_FULLROWSELECT);
	ModifyStyle(LVS_SINGLESEL,0);
	searchlist = in_searchlist;

	InsertColumn(0,GetResString(IDS_DL_FILENAME),LVCFMT_LEFT,250);
	InsertColumn(1,GetResString(IDS_DL_SIZE),LVCFMT_LEFT,100);
	InsertColumn(2,GetResString(IDS_DL_SOURCES),LVCFMT_LEFT,50);
	InsertColumn(3,GetResString(IDS_TYPE),LVCFMT_LEFT,65);
	InsertColumn(4,GetResString(IDS_FILEID),LVCFMT_LEFT,220);

	m_SearchFileMenu.CreatePopupMenu();
	m_SearchFileMenu.AddMenuTitle(GetResString(IDS_FILE));
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_RESUME, GetResString(IDS_DOWNLOAD));
	m_SearchFileMenu.AppendMenu(MF_STRING, MP_JIGLE_FAKECHECK, IDS_JIGLE_FAKECHECK); // Added by Tarod [deltaHF]
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_GETED2KLINK, GetResString(IDS_DL_LINK1));
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_GETHTMLED2KLINK, GetResString(IDS_DL_LINK2));
	m_SearchFileMenu.AppendMenu(MF_SEPARATOR);
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_REMOVESELECTED, GetResString(IDS_REMOVESELECTED));
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_REMOVE, GetResString(IDS_REMOVESEARCHSTRING));
	m_SearchFileMenu.AppendMenu(MF_STRING,MP_REMOVEALL, GetResString(IDS_REMOVEALLSEARCH));
	m_SearchFileMenu.SetDefaultItem(MP_RESUME);

	asc_sort[2]=true;asc_sort[3]=true;
	LoadSettings(CPreferences::tableSearch);

	// Barry - Use preferred sort order from preferences
	int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableSearch);
	bool sortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableSearch);
	SetSortArrow(sortItem, sortAscending);
	SortItems(SortProc, sortItem + (sortAscending ? 0:10));
}

CSearchListCtrl::~CSearchListCtrl(){
}

void CSearchListCtrl::Localize() {
	CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
	HDITEM hdi;
	hdi.mask = HDI_TEXT;
	CString strRes;

	strRes = GetResString(IDS_DL_FILENAME);
	hdi.pszText = strRes.GetBuffer();
	pHeaderCtrl->SetItem(0, &hdi);
	strRes.ReleaseBuffer();

	strRes = GetResString(IDS_DL_SIZE);
	hdi.pszText = strRes.GetBuffer();
	pHeaderCtrl->SetItem(1, &hdi);
	strRes.ReleaseBuffer();

	strRes = GetResString(IDS_DL_SOURCES);
	hdi.pszText = strRes.GetBuffer();
	pHeaderCtrl->SetItem(2, &hdi);
	strRes.ReleaseBuffer();

	strRes = GetResString(IDS_TYPE);
	hdi.pszText = strRes.GetBuffer();
	pHeaderCtrl->SetItem(3, &hdi);
	strRes.ReleaseBuffer();

	strRes = GetResString(IDS_FILEID);
	hdi.pszText = strRes.GetBuffer();
	pHeaderCtrl->SetItem(4, &hdi);
	strRes.ReleaseBuffer();
}

BEGIN_MESSAGE_MAP(CSearchListCtrl, CMuleListCtrl)
	ON_NOTIFY_REFLECT ( NM_CUSTOMDRAW, OnCustomdraw )
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
	ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()

// CSearchListCtrl message handlers

void CSearchListCtrl::AddResult(CSearchFile* toshow){

	if (toshow->GetSearchID() != m_nResultsID)
		return;

	uint32 itemnr = GetItemCount();
	itemnr = InsertItem(LVIF_TEXT|LVIF_PARAM,itemnr,toshow->GetFileName(),0,0,1,(LPARAM)toshow);
	uint32 filesize = toshow->GetIntTagValue(FT_FILESIZE); 
	char buffer[50];
	CastItoXBytes(filesize,buffer);
	SetItemText(itemnr,1,buffer);
	itoa(toshow->GetIntTagValue(FT_SOURCES),buffer,10);
	SetItemText(itemnr,2,buffer);
	SetItemText(itemnr,3,GetFiletypeByName(toshow->GetFileName()));
	
	buffer[0] = 0;
	for (uint16 i = 0;i != 16;i++) // hmm I wonder if there is a standart function for this
		sprintf(buffer,"%s%02X",buffer,toshow->GetFileHash()[i]);
	SetItemText(itemnr,4,buffer);

	// update tab-counter for the given searchfile
	if (theApp.emuledlg->searchwnd.searchselect.GetItemCount()>0) {
		CString csName,sourceStr;
		int j;
		char szText[510];

		TCITEM tabitem;
		tabitem.mask = TCIF_PARAM;

		int tabCounter;
		for (tabCounter = 0; tabCounter < theApp.emuledlg->searchwnd.searchselect.GetItemCount();tabCounter++){
			theApp.emuledlg->searchwnd.searchselect.GetItem(tabCounter,&tabitem);
			if (tabitem.lParam == toshow->GetSearchID())
				break;
		}

		if (tabitem.lParam == toshow->GetSearchID()) {
			tabitem.pszText = szText;
			tabitem.cchTextMax = 510;
			tabitem.mask = TCIF_TEXT;
			theApp.emuledlg->searchwnd.searchselect.GetItem(tabCounter,&tabitem);
			
			csName.Format("%s",szText);

			tabitem.mask = TCIF_PARAM;
			theApp.emuledlg->searchwnd.searchselect.GetItem(tabCounter,&tabitem);

			sourceStr.Format(" (%u)", searchlist->GetFoundFiles(toshow->GetSearchID()) );

			j=csName.ReverseFind('(');
			if (j>0) csName=csName.Left(j-1);
			csName.Append(sourceStr);

			tabitem.mask = TCIF_TEXT;
			tabitem.pszText = csName.LockBuffer();
			theApp.emuledlg->searchwnd.searchselect.SetItem(tabCounter,&tabitem);
			csName.UnlockBuffer();
		}
	}

}

void CSearchListCtrl::UpdateSources(CSearchFile* toupdate){
	LVFINDINFO find;
	find.flags = LVFI_PARAM;
	find.lParam = (LPARAM)toupdate;
	int index = FindItem(&find);
	if (index != (-1)){
		char buffer[50];
		itoa(toupdate->GetSourceCount(),buffer,10);
		SetItemText(index,2,buffer);
		Update(index);
	}
}

void CSearchListCtrl::RemoveResult(CSearchFile* toremove){
	LVFINDINFO find;
	find.flags = LVFI_PARAM;
	find.lParam = (LPARAM)toremove;
	sint32 result = FindItem(&find);
	if(result != (-1) )
		this->DeleteItem(result);
}

void CSearchListCtrl::ShowResults(uint32 nResultsID){
	DeleteAllItems();
	m_nResultsID = nResultsID;
	searchlist->ShowResults(m_nResultsID);
}

void CSearchListCtrl::OnCustomdraw(NMHDR* pNMHDR, LRESULT* pResult ){
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );

    *pResult = CDRF_DODEFAULT;

    if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage){
        *pResult = CDRF_NOTIFYITEMDRAW;
    }
    else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage){
		COLORREF crText = ::GetSysColor(COLOR_WINDOWTEXT);
		uint32 red = GetRValue(crText);
		uint32 green = GetGValue(crText);
		uint32 blue = GetGValue(crText);

		CSearchFile* file = (CSearchFile*)pLVCD->nmcd.lItemlParam;
		if (!file)
			return;

		CKnownFile* sameFile = theApp.sharedfiles->GetFileByID(file->GetFileHash());
		if (!sameFile)
			sameFile = theApp.downloadqueue->GetFileByID(file->GetFileHash());

		if (sameFile) {
			if (sameFile->IsPartFile()) {
				// Already downloading
				red = (file->GetSourceCount()+4) * 20;
				if (red > 255) red = 255;
			}
			else {
				// Already downloaded
				green = 128;
			}
		}
		else {
			blue = (file->GetSourceCount()-1) * 20;
			if (blue > 255) blue = 255;
		}

		pLVCD->clrText = RGB(red, green ,blue);
        *pResult = CDRF_DODEFAULT;
     }
}

void CSearchListCtrl::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult){
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// if it's a second click on the same column then reverse the sort order,
	// otherwise sort the new column in ascending order.
//	asc_sort[pNMListView->iSubItem] = !asc_sort[pNMListView->iSubItem];
//	SetSortArrow(pNMListView->iSubItem, asc_sort[pNMListView->iSubItem]);
//	SortItems(&SortProc, pNMListView->iSubItem+ ((asc_sort[pNMListView->iSubItem])? 0:10));

	// Barry - Store sort order in preferences
	// Determine ascending based on whether already sorted on this column
	int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableSearch);
	bool m_oldSortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableSearch);
	bool sortAscending = (sortItem != pNMListView->iSubItem) ? true : !m_oldSortAscending;
	// Item is column clicked
	sortItem = pNMListView->iSubItem;
	// Save new preferences
	theApp.glob_prefs->SetColumnSortItem(CPreferences::tableSearch, sortItem);
	theApp.glob_prefs->SetColumnSortAscending(CPreferences::tableSearch, sortAscending);
	// Sort table
	SetSortArrow(sortItem, sortAscending);
	SortItems(SortProc, sortItem + (sortAscending ? 0:10));

	*pResult = 0;
}

int CSearchListCtrl::SortProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort){
	CSearchFile* item1 = (CSearchFile*)lParam1;
	CSearchFile* item2 = (CSearchFile*)lParam2;	
	switch(lParamSort){
		case 0: //filename asc
			return strcmpi(item1->GetFileName(),item2->GetFileName());
		case 10: //filename desc
			return strcmpi(item2->GetFileName(),item1->GetFileName());
		case 1: //size asc
			return item1->GetIntTagValue(FT_FILESIZE) - item2->GetIntTagValue(FT_FILESIZE);
		case 11: //size desc
			return item2->GetIntTagValue(FT_FILESIZE) - item1->GetIntTagValue(FT_FILESIZE);
		case 2: //sources asc
			return item1->GetIntTagValue(FT_SOURCES) - item2->GetIntTagValue(FT_SOURCES);
		case 12: //sources desc
			return item2->GetIntTagValue(FT_SOURCES) - item1->GetIntTagValue(FT_SOURCES);
		case 3: //type asc
			return GetFiletypeByName(item1->GetFileName()).Compare(GetFiletypeByName(item2->GetFileName()));

		case 13: //type  desc
			return GetFiletypeByName(item2->GetFileName()).Compare(GetFiletypeByName(item1->GetFileName()));

		case 4: //filahash asc
			return memcmp(item1->GetFileHash(),item2->GetFileHash(),16);
		case 14: //filehash desc
			return memcmp(item2->GetFileHash(),item1->GetFileHash(),16);
		default:
			return 0;
	}
}

void CSearchListCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
	UINT flag=(GetSelectionMark()!=(-1)) ? MF_ENABLED:MF_GRAYED;

	m_SearchFileMenu.EnableMenuItem(MP_RESUME,flag);
	m_SearchFileMenu.EnableMenuItem(MP_JIGLE_FAKECHECK, flag); // Added by Tarod [deltaHF] -fix, deltaHF forgot it
	m_SearchFileMenu.EnableMenuItem(MP_GETED2KLINK,flag);
	m_SearchFileMenu.EnableMenuItem(MP_GETHTMLED2KLINK,flag);
	
	m_SearchFileMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x,point.y,this);
}



BOOL CSearchListCtrl::OnCommand(WPARAM wParam, LPARAM lParam)
{
	CSearchFile* file ;
	int item;

	if (GetSelectionMark() != (-1)){
		file = (CSearchFile*)GetItemData(GetSelectionMark());
		switch (wParam){
			case MP_GETED2KLINK:
				{
					theApp.CopyTextToClipboard(theApp.CreateED2kLink(file));
					break;
				}
			case MP_GETHTMLED2KLINK:
				{
					theApp.CopyTextToClipboard(theApp.CreateHTMLED2kLink(file));
					break;
				}
			case MP_RESUME:
				{
					theApp.emuledlg->searchwnd.OnBnClickedSdownload();
					break;
				}
			case MP_REMOVEALL:
				{
					theApp.emuledlg->searchwnd.DeleteAllSearchs();
					break;
				}
			case MP_REMOVESELECTED:
				{
					SetRedraw(false);
					POSITION pos;
					while (GetFirstSelectedItemPosition()!=NULL) 
					{
						pos=GetFirstSelectedItemPosition();
						item = this->GetNextSelectedItem(pos); 
						theApp.searchlist->RemoveResults( (CSearchFile*)this->GetItemData(item) );
					}
					SetRedraw(true);
					break;
				}
			case MP_JIGLE_FAKECHECK: { // Added by Tarod [deltaHF]
				theApp.Action(NULL, NULL, file);
				break;
			}
		}
	}
	switch (wParam){
			case MP_REMOVE:
				{
					theApp.emuledlg->searchwnd.DeleteSearch(m_nResultsID);
					break;
				}
	}
	return true;
}
