//this file is part of eMule
//Copyright (C)2002-2008 Merkur ( strEmail.Format("%s@%s", "devteam", "emule-project.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 "emule.h"
#include "emuledlg.h"
#include "SharedFilesCtrl.h"
#include "OtherFunctions.h"
#include "FileInfoDialog.h"
#include "MetaDataDlg.h"
#include "ED2kLinkDlg.h"
#include "ArchivePreviewDlg.h"
#include "CommentDialog.h"
#include "HighColorTab.hpp"
#include "ListViewWalkerPropertySheet.h"
#include "UserMsgs.h"
#include "ResizableLib/ResizableSheet.h"
#include "KnownFile.h"
#include "MapKey.h"
#include "SharedFileList.h"
#include "MemDC.h"
#include "PartFile.h"
#include "MenuCmds.h"
#include "IrcWnd.h"
#include "SharedFilesWnd.h"
#include "Opcodes.h"
#include "InputBox.h"
#include "WebServices.h"
#include "TransferWnd.h"
#include "ClientList.h"
#include "UpDownClient.h"
#include "Collection.h"
#include "CollectionCreateDialog.h"
#include "CollectionViewDialog.h"
#include "SharedDirsTreeCtrl.h"
#include "SearchParams.h"
#include "SearchDlg.h"
#include "SearchResultsWnd.h"
#include "ToolTipCtrlX.h"
#include "kademlia/kademlia/kademlia.h"
#include "kademlia/kademlia/UDPFirewallTester.h"
#include "Neo/Functions.h" // gomez82 >>> MOD 
#include "downloadqueue.h" // gomez82 >>> SP - [SharedParts] 
// gomez82 >>> CRC - [MorphCRCTag] 
#include "Neo/GUI/AddCRC32TagDialog.h" 
#include "UserMsgs.h"
#include "log.h"
// gomez82 >>> CRC END 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

bool NeedArchiveInfoPage(const CSimpleArray<CObject*>* paItems);
void UpdateFileDetailsPages(CListViewWalkerPropertySheet *pSheet,
							CResizablePage *pArchiveInfo, CResizablePage *pMediaInfo);


//////////////////////////////////////////////////////////////////////////////
// CSharedFileDetailsSheet

class CSharedFileDetailsSheet : public CListViewWalkerPropertySheet
{
	DECLARE_DYNAMIC(CSharedFileDetailsSheet)

public:
	CSharedFileDetailsSheet(CTypedPtrList<CPtrList, CKnownFile*>& aFiles, UINT uPshInvokePage = 0, CListCtrlItemWalk* pListCtrl = NULL);
	virtual ~CSharedFileDetailsSheet();

protected:
	CFileInfoDialog		m_wndMediaInfo;
	CMetaDataDlg		m_wndMetaData;
	CED2kLinkDlg		m_wndFileLink;
	CCommentDialog		m_wndFileComments;
	CArchivePreviewDlg	m_wndArchiveInfo;

	UINT m_uPshInvokePage;
	static LPCTSTR m_pPshStartPage;

	void UpdateTitle();

	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
	virtual BOOL OnInitDialog();

	DECLARE_MESSAGE_MAP()
	afx_msg void OnDestroy();
	afx_msg LRESULT OnDataChanged(WPARAM, LPARAM);
};

LPCTSTR CSharedFileDetailsSheet::m_pPshStartPage;

IMPLEMENT_DYNAMIC(CSharedFileDetailsSheet, CListViewWalkerPropertySheet)

BEGIN_MESSAGE_MAP(CSharedFileDetailsSheet, CListViewWalkerPropertySheet)
	ON_WM_DESTROY()
	ON_MESSAGE(UM_DATA_CHANGED, OnDataChanged)
END_MESSAGE_MAP()

CSharedFileDetailsSheet::CSharedFileDetailsSheet(CTypedPtrList<CPtrList, CKnownFile*>& aFiles, UINT uPshInvokePage, CListCtrlItemWalk* pListCtrl)
	: CListViewWalkerPropertySheet(pListCtrl)
{
	m_uPshInvokePage = uPshInvokePage;
	POSITION pos = aFiles.GetHeadPosition();
	while (pos)
		m_aItems.Add(aFiles.GetNext(pos));
	m_psh.dwFlags &= ~PSH_HASHELP;

	m_wndFileComments.m_psp.dwFlags &= ~PSP_HASHELP;
	m_wndFileComments.m_psp.dwFlags |= PSP_USEICONID;
	m_wndFileComments.m_psp.pszIcon = _T("FileComments");
	m_wndFileComments.SetFiles(&m_aItems);
	AddPage(&m_wndFileComments);

	m_wndArchiveInfo.m_psp.dwFlags &= ~PSP_HASHELP;
	m_wndArchiveInfo.m_psp.dwFlags |= PSP_USEICONID;
	m_wndArchiveInfo.m_psp.pszIcon = _T("ARCHIVE_PREVIEW");
	m_wndArchiveInfo.SetFiles(&m_aItems);
	m_wndMediaInfo.m_psp.dwFlags &= ~PSP_HASHELP;
	m_wndMediaInfo.m_psp.dwFlags |= PSP_USEICONID;
	m_wndMediaInfo.m_psp.pszIcon = _T("MEDIAINFO");
	m_wndMediaInfo.SetFiles(&m_aItems);
	if (NeedArchiveInfoPage(&m_aItems))
		AddPage(&m_wndArchiveInfo);
	else
		AddPage(&m_wndMediaInfo);

	m_wndMetaData.m_psp.dwFlags &= ~PSP_HASHELP;
	m_wndMetaData.m_psp.dwFlags |= PSP_USEICONID;
	m_wndMetaData.m_psp.pszIcon = _T("METADATA");
	if (m_aItems.GetSize() == 1 && thePrefs.IsExtControlsEnabled()) {
		m_wndMetaData.SetFiles(&m_aItems);
		AddPage(&m_wndMetaData);
	}

	m_wndFileLink.m_psp.dwFlags &= ~PSP_HASHELP;
	m_wndFileLink.m_psp.dwFlags |= PSP_USEICONID;
	m_wndFileLink.m_psp.pszIcon = _T("ED2KLINK");
	m_wndFileLink.SetFiles(&m_aItems);
	AddPage(&m_wndFileLink);

	LPCTSTR pPshStartPage = m_pPshStartPage;
	if (m_uPshInvokePage != 0)
		pPshStartPage = MAKEINTRESOURCE(m_uPshInvokePage);
	for (int i = 0; i < m_pages.GetSize(); i++)
	{
		CPropertyPage* pPage = GetPage(i);
		if (pPage->m_psp.pszTemplate == pPshStartPage)
		{
			m_psh.nStartPage = i;
			break;
		}
	}
}

CSharedFileDetailsSheet::~CSharedFileDetailsSheet()
{
}

void CSharedFileDetailsSheet::OnDestroy()
{
	if (m_uPshInvokePage == 0)
		m_pPshStartPage = GetPage(GetActiveIndex())->m_psp.pszTemplate;
	CListViewWalkerPropertySheet::OnDestroy();
}

BOOL CSharedFileDetailsSheet::OnInitDialog()
{
	EnableStackedTabs(FALSE);
	BOOL bResult = CListViewWalkerPropertySheet::OnInitDialog();
	HighColorTab::UpdateImageList(*this);
	InitWindowStyles(this);
	EnableSaveRestore(_T("SharedFileDetailsSheet")); // call this after(!) OnInitDialog
	UpdateTitle();
	return bResult;
}

LRESULT CSharedFileDetailsSheet::OnDataChanged(WPARAM, LPARAM)
{
	UpdateTitle();
	UpdateFileDetailsPages(this, &m_wndArchiveInfo, &m_wndMediaInfo);
	return 1;
}

void CSharedFileDetailsSheet::UpdateTitle()
{
	if (m_aItems.GetSize() == 1)
		SetWindowText(GetResString(IDS_DETAILS) + _T(": ") + STATIC_DOWNCAST(CKnownFile, m_aItems[0])->GetFileName());
	else
		SetWindowText(GetResString(IDS_DETAILS));
}

BOOL CSharedFileDetailsSheet::OnCommand(WPARAM wParam, LPARAM lParam)
{
	if (wParam == ID_APPLY_NOW)
	{
		CSharedFilesCtrl* pSharedFilesCtrl = DYNAMIC_DOWNCAST(CSharedFilesCtrl, m_pListCtrl->GetListCtrl());
		if (pSharedFilesCtrl)
		{
			for (int i = 0; i < m_aItems.GetSize(); i++) {
				// so, and why does this not(!) work while the sheet is open ??
				pSharedFilesCtrl->UpdateFile(DYNAMIC_DOWNCAST(CKnownFile, m_aItems[i]));
			}
		}
	}

	return CListViewWalkerPropertySheet::OnCommand(wParam, lParam);
}


//////////////////////////////////////////////////////////////////////////////
// CSharedFilesCtrl
IMPLEMENT_DYNAMIC(CSharedItem, CObject) // gomez82 >>> SP - [SharedParts] 

IMPLEMENT_DYNAMIC(CSharedFilesCtrl, CMuleListCtrl)

BEGIN_MESSAGE_MAP(CSharedFilesCtrl, CMuleListCtrl)
	ON_WM_SYSCOLORCHANGE()
	ON_WM_CONTEXTMENU()
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
	ON_NOTIFY_REFLECT(NM_CLICK, OnClick) // gomez82 >>> NTS - [NeoTreeStyle] 
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo)
	ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnLvnGetInfoTip)
	ON_WM_KEYDOWN()
	ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindragFilelist) // gomez82 >>> SDD - [ShareDargAndDrop] 
	// gomez82 >>> CRC - [MorphCRCTag] 
	ON_MESSAGE(UM_CRC32_RENAMEFILE,	OnCRC32RenameFile)
	ON_MESSAGE(UM_CRC32_UPDATEFILE, OnCRC32UpdateFile)
	// gomez82 >>> CRC END 
END_MESSAGE_MAP()

CSharedFilesCtrl::CSharedFilesCtrl()
	: CSharedFilesListCtrlItemWalk(this) // gomez82 >>> SP - [SharedParts] 
	//: CListCtrlItemWalk(this)
{
	memset(&sortstat, 0, sizeof(sortstat));
	nAICHHashing = 0;
	m_pDirectoryFilter = NULL;
	SetGeneralPurposeFind(true, false);
	m_pToolTip = new CToolTipCtrlX;
}

CSharedFilesCtrl::~CSharedFilesCtrl()
{
	// gomez82 >>> FIX - [DestroyMenu] 
	if (m_PrioMenu) VERIFY( m_PrioMenu.DestroyMenu() );
	if (m_CRC32Menu) VERIFY( m_CRC32Menu.DestroyMenu() ); // gomez82 >>> CRC - [MorphCRCTag]
	// gomez82 >>> FIX END 
	//// gomez82 >>> START - Added by SiRoB, HIDEOS
	if (m_HideOSMenu) VERIFY( m_HideOSMenu.DestroyMenu() );
	if (m_SelectiveChunkMenu) VERIFY( m_SelectiveChunkMenu.DestroyMenu() );
	//// gomez82 >>> END   - Added by SiRoB, HIDEOS
	//// gomez82 >>> START - Added by SiRoB, SHARE_ONLY_THE_NEED
	if (m_ShareOnlyTheNeedMenu) VERIFY( m_ShareOnlyTheNeedMenu.DestroyMenu() );
	//// gomez82 >>> END   - Added by SiRoB, SHARE_ONLY_THE_NEED
	// <CB Mod : Fix : By Wizard>
	if (m_CollectionsMenu) VERIFY( m_CollectionsMenu.DestroyMenu() );
	if (m_SharedFilesMenu) VERIFY( m_SharedFilesMenu.DestroyMenu() );
	// </CB Mod : Fix : By Wizard>	

	delete m_pToolTip;
}
// gomez82 columns
#define COL_HOS (14)
#define COL_SOTN (15)
#define COL_QUEUE (16)
#define COL_UPPARTS (17)

void CSharedFilesCtrl::Init()
{
	SetName(_T("SharedFilesCtrl"));

	CImageList ilDummyImageList; //dummy list for getting the proper height of listview entries
	ilDummyImageList.Create(1, theApp.GetSmallSytemIconSize().cy,theApp.m_iDfltImageListColorFlags|ILC_MASK, 1, 1); 
	SetImageList(&ilDummyImageList, LVSIL_SMALL);
	ASSERT( (GetStyle() & LVS_SHAREIMAGELISTS) == 0 );
	ilDummyImageList.Detach();

	SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
	ASSERT( (GetStyle() & LVS_SINGLESEL) == 0 );

	InsertColumn(0, GetResString(IDS_DL_FILENAME) ,LVCFMT_LEFT,250,0);
	InsertColumn(1,GetResString(IDS_DL_SIZE),LVCFMT_LEFT,100,1);
	InsertColumn(2,GetResString(IDS_TYPE),LVCFMT_LEFT,50,2);
	InsertColumn(3,GetResString(IDS_PRIORITY),LVCFMT_LEFT,70,3);
	InsertColumn(4,GetResString(IDS_FILEID),LVCFMT_LEFT,220,4);
	InsertColumn(5,GetResString(IDS_SF_REQUESTS),LVCFMT_LEFT,100,5);
	InsertColumn(6,GetResString(IDS_SF_ACCEPTS),LVCFMT_LEFT,100,6);
	InsertColumn(7,GetResString(IDS_SF_TRANSFERRED),LVCFMT_LEFT,120,7);
	InsertColumn(8,GetResString(IDS_UPSTATUS),LVCFMT_LEFT,100,8);
	InsertColumn(9,GetResString(IDS_FOLDER),LVCFMT_LEFT,200,9);
	InsertColumn(10,GetResString(IDS_COMPLSOURCES),LVCFMT_LEFT,100,10);
	InsertColumn(11,GetResString(IDS_SHAREDTITLE),LVCFMT_LEFT,200,11);
	InsertColumn(12,GetResString(IDS_CAT),LVCFMT_LEFT,100,12); // gomez82 >>> NSC - [NeoSharedCategories] 
	InsertColumn(13,GetResString(IDS_X_CRC),LVCFMT_LEFT,100,13); // gomez82 >>> CRC - [MorphCRCTag] 
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
    InsertColumn(COL_HOS,GetResString(IDS_HIDEOS),LVCFMT_LEFT,100,COL_HOS);
	InsertColumn(COL_SOTN,GetResString(IDS_SHAREONLYTHENEED),LVCFMT_LEFT,100,COL_SOTN);
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	InsertColumn(COL_QUEUE,_T("On Queue"),LVCFMT_LEFT,170,COL_QUEUE);
	InsertColumn(COL_UPPARTS,GetResString(IDS_SF_UPLOADED_PARTS),LVCFMT_LEFT,170,COL_UPPARTS);//spreadbar
	SetAllIcons();
	CreateMenues();
	LoadSettings();

	// Barry - Use preferred sort order from preferences
	SetSortArrow();
	SortItems(SortProc, GetSortItem() + (GetSortAscending() ? 0 : 20) + (GetSortSecondValue() ? 100 : 0));

	CToolTipCtrl* tooltip = GetToolTips();
	if (tooltip){
		m_pToolTip->SetFileIconToolTip(true);
		m_pToolTip->SubclassWindow(*tooltip);
		tooltip->ModifyStyle(0, TTS_NOPREFIX);
		tooltip->SetDelayTime(TTDT_AUTOPOP, 20000);
		tooltip->SetDelayTime(TTDT_INITIAL, thePrefs.GetToolTipDelay()*1000);
	}
}

void CSharedFilesCtrl::OnSysColorChange()
{
	CMuleListCtrl::OnSysColorChange();
	SetAllIcons();
	CreateMenues();
}

void CSharedFilesCtrl::SetAllIcons()
{
	m_ImageList.DeleteImageList();
	m_ImageList.Create(16,16,theApp.m_iDfltImageListColorFlags|ILC_MASK,0,1);
	m_ImageList.SetBkColor(CLR_NONE);
	m_ImageList.Add(CTempIconLoader(_T("EMPTY")));
	m_ImageList.Add(CTempIconLoader(_T("FileSharedServer"), 16, 16));
	m_ImageList.Add(CTempIconLoader(_T("FileSharedKad"), 16, 16));
	m_ImageList.Add(CTempIconLoader(_T("Rating_NotRated")));
	m_ImageList.Add(CTempIconLoader(_T("Rating_Fake")));
	m_ImageList.Add(CTempIconLoader(_T("Rating_Poor")));
	m_ImageList.Add(CTempIconLoader(_T("Rating_Fair")));
	m_ImageList.Add(CTempIconLoader(_T("Rating_Good")));
	m_ImageList.Add(CTempIconLoader(_T("Rating_Excellent")));
	m_ImageList.Add(CTempIconLoader(_T("Collection_Search"))); // rating for comments are searched on kad
	m_ImageList.SetOverlayImage(m_ImageList.Add(CTempIconLoader(_T("FileCommentsOvl"))), 1);
}

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

	strRes = GetResString(IDS_DL_FILENAME);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(0, &hdi);

	strRes = GetResString(IDS_DL_SIZE);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(1, &hdi);

	strRes = GetResString(IDS_TYPE);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(2, &hdi);

	strRes = GetResString(IDS_PRIORITY);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(3, &hdi);

	strRes = GetResString(IDS_FILEID);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(4, &hdi);

	strRes = GetResString(IDS_SF_REQUESTS);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(5, &hdi);

	strRes = GetResString(IDS_SF_ACCEPTS);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(6, &hdi);

	strRes = GetResString(IDS_SF_TRANSFERRED);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(7, &hdi);

	strRes = GetResString(IDS_SHARED_STATUS);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(8, &hdi);

	strRes = GetResString(IDS_FOLDER);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(9, &hdi);

	strRes = GetResString(IDS_COMPLSOURCES);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(10, &hdi);

	strRes = GetResString(IDS_SHAREDTITLE);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(11, &hdi);
	// gomez82 >>> NSC - [NeoSharedCategories] 
	strRes = GetResString(IDS_CAT);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(12, &hdi);
	strRes.ReleaseBuffer();
	// gomez82 >>> NSC END 
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
    strRes = GetResString(IDS_HIDEOS);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(COL_HOS, &hdi);

	strRes = GetResString(IDS_SHAREONLYTHENEED);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(COL_SOTN, &hdi);
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle

	strRes = _T("On Queue");
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(COL_QUEUE, &hdi);
	// gomez82 >>> Spread bars [Slugfiller/MorphXT] - Stulle
	strRes = GetResString(IDS_SF_UPLOADED_PARTS);
	hdi.pszText = const_cast<LPTSTR>((LPCTSTR)strRes);
	pHeaderCtrl->SetItem(COL_UPPARTS, &hdi);
	// gomez82 >>> Spread bars [Slugfiller/MorphXT] - Stulle
	CreateMenues();

	int iItems = GetItemCount();
	for (int i = 0; i < iItems; i++)
		Update(i);
}

void CSharedFilesCtrl::AddFile(const CKnownFile* file)
{
	if (!theApp.emuledlg->IsRunning())
		return;
	// check filter conditions if we should show this file right now
	if (m_pDirectoryFilter != NULL){
		CString strFilePath = file->GetPath();
		if (strFilePath.Right(1) == _T("\\")){
			strFilePath = strFilePath.Left(strFilePath.GetLength()-1);
		}
		switch(m_pDirectoryFilter->m_eItemType){
			case SDI_ALL:
				// No filter
				break;
			// gomez82 >>> NSC - [NeoSharedCategories] 
			case SDI_CATEGORIES:
				if (m_pDirectoryFilter->m_nCatFilter != -1 && (UINT)m_pDirectoryFilter->m_nCatFilter != file->GetCategory())
					return;
				break;
			// gomez82 >>> NSC END 
			case SDI_FILESYSTEMPARENT:
				return; // no files
				break;
			case SDI_NO:
				// some shared directory
			case SDI_CATINCOMING:
				// Categories with special incoming dirs
			case SDI_UNSHAREDDIRECTORY:
				// Items from the whole filesystem tree
				if (strFilePath.CompareNoCase(m_pDirectoryFilter->m_strFullPath) != 0)
					return;
				break;
			case SDI_TEMP:
				// only tempfiles
				if (!file->IsPartFile())
					return;
				else if (m_pDirectoryFilter->m_nCatFilter != -1 && (UINT)m_pDirectoryFilter->m_nCatFilter != ((CPartFile*)file)->GetCategory())
					return;
				break;
			case SDI_DIRECTORY:
				// any userselected shared dir but not incoming or temp
				if (file->IsPartFile())
					return;
				if (strFilePath.CompareNoCase(thePrefs.GetMuleDirectory(EMULE_INCOMINGDIR)) == 0)
					return;
				break;
			case SDI_INCOMING:
				// Main incoming directory
				if (strFilePath.CompareNoCase(thePrefs.GetMuleDirectory(EMULE_INCOMINGDIR)) != 0)
					return;
				// Hmm should we show all incoming files dirs or only those from the main incoming dir here?
				// hard choice, will only show the main for now
				break;

		}
	}

	if (FindFile(file) != -1)
		return;
	// gomez82 >>> SP - [SharedParts] 
	CSharedItem *ItemData = new CSharedItem ;
	
	ItemData->isFile = true;
	ItemData->isOpen = false;
	ItemData->KnownFile = const_cast <CKnownFile*> (file);
	ItemData->Part = 0;
	ItemData->Parts = file->GetPartCount();

	int iItem = InsertItem(LVIF_TEXT|LVIF_PARAM, GetItemCount(), LPSTR_TEXTCALLBACK, 0, 0, 0, (LPARAM)ItemData); 
	// gomez82 >>> SP END 
//	int iItem = InsertItem(LVIF_TEXT|LVIF_PARAM, GetItemCount(), LPSTR_TEXTCALLBACK, 0, 0, 0, (LPARAM)file);
	if (iItem >= 0)
		Update(iItem);
}

void CSharedFilesCtrl::RemoveFile(const CKnownFile* file)
{
	// gomez82 >>> SP - [SharedParts] 
	if(file == NULL)
		return;

	CSharedItem* ItemData;
	for(int nItem=0; nItem<GetItemCount(); nItem++)
	{
		ItemData=(CSharedItem*)GetItemData(nItem);
		if(ItemData->isFile && ItemData->KnownFile==file)
		{
			if(ItemData->isOpen)
			{
				for(uint16 Part=0; Part<ItemData->Parts; Part++)
				{
					CSharedItem* ItemDataPart=(CSharedItem*)GetItemData(nItem+1);
					if (ItemDataPart->isFile) 
						break;
					SetItemData(nItem+1, NULL);
					DeleteItem(nItem+1);
					if(ItemDataPart) 
						delete ItemDataPart;
				}
			}

			SetItemData(nItem, NULL);
			DeleteItem(nItem);
			if(ItemData) 
				delete ItemData;
		}
	}
	ShowFilesCount();
	// gomez82 >>> SP END 
	/*int iItem = FindFile(file);
	if (iItem != -1)
	{
		DeleteItem(iItem);
		ShowFilesCount();
	}*/
}

void CSharedFilesCtrl::UpdateFile(const CKnownFile* file)
{
	if (!file || !theApp.emuledlg->IsRunning())
		return;
	int iItem = FindFile(file);
	if (iItem != -1)
	{
		Update(iItem);
		if (GetItemState(iItem, LVIS_SELECTED))
			theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary();
	}
}

int CSharedFilesCtrl::FindFile(const CKnownFile* pFile)
{
	// gomez82 >>> SP - [SharedParts] 
	CSharedItem* ItemData;
	for(int nItem=0; nItem<GetItemCount(); nItem++)
	{
		ItemData=(CSharedItem*)GetItemData(nItem);
		if(ItemData->isFile && ItemData->KnownFile == pFile)
			return nItem;
	}

	return -1;
	// gomez82 >>> SP END 

	/*LVFINDINFO find;
	find.flags = LVFI_PARAM;
	find.lParam = (LPARAM)pFile;
	return FindItem(&find);*/
}

// gomez82 >>> SP - [SharedParts] 
void CSharedFilesCtrl::UpdatePart(const CSharedItem* part)
{
	if (!part || !theApp.emuledlg->IsRunning())
		return;
	int iItem = FindPart(part);
	if (iItem != -1)
	{
		Update(iItem);
		/*if (GetItemState(iItem, LVIS_SELECTED))
			theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary();*/
	}
}

int CSharedFilesCtrl::FindPart(const CSharedItem* pPart)
{
	CSharedItem* ItemData;
	for(int nItem=0; nItem<GetItemCount(); nItem++)
	{
		ItemData=(CSharedItem*)GetItemData(nItem);
		if(ItemData==pPart)
			return nItem;
	}

	return -1;
}
// gomez82 >>> SP END 


void CSharedFilesCtrl::ReloadFileList()
{
	DeleteAllItems();
	theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary();
	
	CCKey bufKey;
	CKnownFile* cur_file;
	for (POSITION pos = theApp.sharedfiles->m_Files_map.GetStartPosition(); pos != 0; ){
		theApp.sharedfiles->m_Files_map.GetNextAssoc(pos, bufKey, cur_file);
		AddFile(cur_file);
	}
	ShowFilesCount();
}

void CSharedFilesCtrl::ShowFilesCount()
{
	CString str;
	if (theApp.sharedfiles->GetHashingCount() + nAICHHashing)
		str.Format(_T(" (%i, %s %i)"), theApp.sharedfiles->GetCount(), GetResString(IDS_HASHING), theApp.sharedfiles->GetHashingCount() + nAICHHashing);
	else
		str.Format(_T(" (%i)"), theApp.sharedfiles->GetCount());
	theApp.emuledlg->sharedfileswnd->GetDlgItem(IDC_TRAFFIC_TEXT)->SetWindowText(GetResString(IDS_SF_FILES) + str);
}


#define DLC_DT_TEXT (DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS)

void CSharedFilesCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	if (!theApp.emuledlg->IsRunning())
		return;
	if (!lpDrawItemStruct->itemData)
		return;
	CSharedItem* itemdata = (CSharedItem*)lpDrawItemStruct->itemData; // gomez82 >>> SP - [SharedParts] 
	CDC* odc = CDC::FromHandle(lpDrawItemStruct->hDC);
	BOOL bCtrlFocused = ((GetFocus() == this) || (GetStyle() & LVS_SHOWSELALWAYS));
	if (lpDrawItemStruct->itemState & ODS_SELECTED) {
		if (bCtrlFocused)
			odc->SetBkColor(m_crHighlight);
		else
			odc->SetBkColor(m_crNoHighlight);
	}
	// gomez82 >>> NSC - [NeoSharedCategories] 
	else 
	{
		COLORREF catcolor = thePrefs.GetCatColor(itemdata->KnownFile->GetCategory());

		// Lit: White category must be white because background can be changed 
		if(catcolor == 0)
			//odc->SetBkColor(GetBkColor());
			odc->SetBkColor(RGB(255,255,255));
		else
			odc->SetBkColor(RGB(
			//	(GetRValue(catcolor)*16+GetRValue(GetBkColor())*240)/256,
			//	(GetGValue(catcolor)*16+GetGValue(GetBkColor())*240)/256,
			//	(GetBValue(catcolor)*16+GetBValue(GetBkColor())*240)/256));
				(GetRValue(catcolor)*16+60945)/255,
				(GetGValue(catcolor)*16+60945)/255,
				(GetBValue(catcolor)*16+60945)/255));

	}
	// gomez82 >>> NSC END 
	//else
	COLORREF crOldBackColor = odc->GetBkColor(); // gomez82 >>> Optimizations - FillSolidRect
	//	odc->SetBkColor(GetBkColor());

	// gomez82 >>> NTS - [NeoTreeStyle] 
	BOOL notFirst = lpDrawItemStruct->itemID != 0;
	BOOL notLast = lpDrawItemStruct->itemID + 1 != (UINT)GetItemCount();
	int tree_start = 0;
	int tree_end = 0;
	// gomez82 >>> NTS END 

	///*const*/ CKnownFile* file = (CKnownFile*)lpDrawItemStruct->itemData; // SP - removed // gomez82 >>> SP - [SharedParts] 
	CMemDC dc(odc, &lpDrawItemStruct->rcItem);
	CFont* pOldFont = dc.SelectObject(GetFont());
	CRect cur_rec(lpDrawItemStruct->rcItem);
	COLORREF crOldTextColor = dc.SetTextColor((lpDrawItemStruct->itemState & ODS_SELECTED) ? m_crHighlightText : m_crWindowText);

	int iOldBkMode;
	if (m_crWindowTextBk == CLR_NONE){
		DefWindowProc(WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
		iOldBkMode = dc.SetBkMode(TRANSPARENT);
	}
	else
		iOldBkMode = OPAQUE;

	CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
	int iCount = pHeaderCtrl->GetItemCount();
	const int iMarginX = 4;
	cur_rec.right = cur_rec.left - iMarginX*2;
	cur_rec.left += iMarginX;
	//CString buffer; // SP - removed // gomez82 >>> SP - [SharedParts] 
	//int iIconDrawWidth = theApp.GetSmallSytemIconSize().cx + 3;
	for(int iCurrent = 0; iCurrent < iCount; iCurrent++){
		int iColumn = pHeaderCtrl->OrderToIndex(iCurrent);
		if( !IsColumnHidden(iColumn) ){
			//UINT uDTFlags = DLC_DT_TEXT; // SP - removed // gomez82 >>> SP - [SharedParts] 
			cur_rec.right += GetColumnWidth(iColumn);

			// gomez82 >>> NTS - [NeoTreeStyle] 
			if (iColumn==0){
				tree_start = cur_rec.left;
				tree_end = cur_rec.left + 12;
					}
			// gomez82 >>> NTS END 
			// gomez82 >>> SP - [SharedParts] 
			if(!itemdata->isFile){
				DrawPartItem(dc,iColumn,&cur_rec,itemdata);
			}else{
				DrawFileItem(dc,iColumn,&cur_rec,itemdata->KnownFile);
				}
			// gomez82 >>> SP END 
			dc.SetBkColor(crOldBackColor); // gomez82 >>> Optimizations - FillSolidRect

			cur_rec.left += GetColumnWidth(iColumn);
		}
	}
	ShowFilesCount();
	if (lpDrawItemStruct->itemState & ODS_SELECTED)
	{
		RECT outline_rec = lpDrawItemStruct->rcItem;

		outline_rec.top--;
		outline_rec.bottom++;
		dc.FrameRect(&outline_rec, &CBrush(GetBkColor()));
		outline_rec.top++;
		outline_rec.bottom--;
		outline_rec.left++;
		outline_rec.right--;

		if (lpDrawItemStruct->itemID != 0 && GetItemState(lpDrawItemStruct->itemID - 1, LVIS_SELECTED))
			outline_rec.top--;

		if (lpDrawItemStruct->itemID + 1 != (UINT)GetItemCount() && GetItemState(lpDrawItemStruct->itemID + 1, LVIS_SELECTED))
			outline_rec.bottom++;

		if (bCtrlFocused)
			dc.FrameRect(&outline_rec, &CBrush(m_crFocusLine));
		else
			dc.FrameRect(&outline_rec, &CBrush(m_crNoFocusLine));
	}
	
	// gomez82 >>> NTS - [NeoTreeStyle] 
	//draw tree last so it draws over selected and focus (looks better)
	if(thePrefs.UseTreeStyle()){
		if(tree_start < tree_end)
		{
			//set new bounds
			RECT tree_rect;
			tree_rect.top    = lpDrawItemStruct->rcItem.top;
			tree_rect.bottom = lpDrawItemStruct->rcItem.bottom;
			tree_rect.left   = tree_start;
			tree_rect.right  = tree_end;
			dc->SetBoundsRect(&tree_rect, DCB_DISABLE);

			//gather some information
			BOOL hasNext = notLast && !((const CSharedItem*)GetItemData(lpDrawItemStruct->itemID + 1))->isFile;
			BOOL isOpenRoot = hasNext && itemdata->isFile;
			BOOL isChild = !itemdata->isFile;

			//might as well calculate these now
			int treeCenter = tree_start + 4;
			int middle = (cur_rec.top + cur_rec.bottom + 1) / 2;

			//set up a new pen for drawing the tree
			CPen pn, *oldpn;
			pn.CreatePen(PS_SOLID, 1, RGB(128,128,128)/*m_crWindowText*/);
			oldpn = dc->SelectObject(&pn);

			if(isChild)
			{
				//draw the line to the status bar
				dc->MoveTo(tree_end+10, middle);
				dc->LineTo(tree_start + 4, middle);

				//draw the line to the child node
				if(hasNext)
				{
					dc->MoveTo(treeCenter, middle);
					dc->LineTo(treeCenter, cur_rec.bottom + 1);
				}
			}
			else if (isOpenRoot || (itemdata->isFile && itemdata->Parts > 1))
			{
				//draw box
				RECT circle_rec;
				circle_rec.top    = middle - 5;
				circle_rec.bottom = middle + 4;
				circle_rec.left   = treeCenter - 4;
				circle_rec.right  = treeCenter + 5;
				dc->FrameRect(&circle_rec, &CBrush(RGB(128,128,128)/*m_crWindowText*/));
				CPen penBlack;
				penBlack.CreatePen(PS_SOLID, 1, m_crWindowText);
				CPen* pOldPen2;
				pOldPen2 = dc->SelectObject(&penBlack);
				dc->MoveTo(treeCenter-2,middle - 1);
				dc->LineTo(treeCenter+3,middle - 1);
				
				if (!itemdata->isOpen)
				{
					dc->MoveTo(treeCenter,middle-3);
					dc->LineTo(treeCenter,middle+2);
				}
				dc->SelectObject(pOldPen2);
				//draw the line to the child node
				if (hasNext)
				{
					dc->MoveTo(treeCenter, middle + 4);
					dc->LineTo(treeCenter, cur_rec.bottom + 1);
				}
			}

			//draw the line back up to parent node
			if (notFirst && isChild)
			{
				dc->MoveTo(treeCenter, middle);
				dc->LineTo(treeCenter, cur_rec.top - 1);
			}

			//put the old pen back
			dc->SelectObject(oldpn);
			pn.DeleteObject();
		}
	}
	// gomez82 >>> NTS END 
	
	if (m_crWindowTextBk == CLR_NONE)
		dc.SetBkMode(iOldBkMode);
	dc.SelectObject(pOldFont);
	dc.SetTextColor(crOldTextColor);
}

// gomez82 >>> SP - [SharedParts] 
void CSharedFilesCtrl::DrawFileItem(CDC *dc, int iColumn, LPRECT cur_rec, CKnownFile *file)
{
	int iIconDrawWidth = theApp.GetSmallSytemIconSize().cx + 3;


	if (file->IsPartFile()){
		dc->SetTextColor((COLORREF)RGB(0,0,192));
	}else{
		dc->SetTextColor((COLORREF)RGB(0,0,0));
	}

	UINT uDTFlags = DLC_DT_TEXT; 
	CString buffer;

	switch(iColumn){
		case 0:{
			// gomez82 >>> NTS - [NeoTreeStyle]
			if(thePrefs.UseTreeStyle())
				cur_rec->left += 12;
			// gomez82 >>> NTS END

			int iImage = theApp.GetFileTypeSystemImageIdx(file->GetFileName());
			if (theApp.GetSystemImageList() != NULL)
				::ImageList_Draw(theApp.GetSystemImageList(), iImage, dc->GetSafeHdc(), cur_rec->left, cur_rec->top, ILD_NORMAL|ILD_TRANSPARENT);
			if (!file->GetFileComment().IsEmpty() || file->GetFileRating())
				m_ImageList.Draw(dc, 0, CPoint(cur_rec->left, cur_rec->top), ILD_NORMAL | ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1));
			cur_rec->left += (iIconDrawWidth - 3);

			if (thePrefs.ShowRatingIndicator() && (file->HasComment() || file->HasRating() || file->IsKadCommentSearchRunning()))
			{
				m_ImageList.Draw(dc, file->UserRating(true)+3, CPoint(cur_rec->left, cur_rec->top), ILD_NORMAL);
				cur_rec->left += 16;
				iIconDrawWidth += 16;
			}

			cur_rec->left += 3;

			buffer = file->GetFileName();
			break;
		}
		case 1:
			buffer = CastItoXBytes(file->GetFileSize(), false, false);
			uDTFlags |= DT_RIGHT;
			break;
		case 2:
			buffer = file->GetFileTypeDisplayStr();
			break;
		case 3:{
			buffer = file->GetUpPriorityDisplayString();

			break;
		}
		case 4:
			buffer = md4str(file->GetFileHash());
			break;
		case 5:
            buffer.Format(_T("%u (%u)"), file->statistic.GetRequests(), file->statistic.GetAllTimeRequests());
			break;
		case 6:
			buffer.Format(_T("%u (%u)"), file->statistic.GetAccepts(), file->statistic.GetAllTimeAccepts());
			break;
		case 7:
			buffer.Format(_T("%s (%s)"), CastItoXBytes(file->statistic.GetTransferred(), false, false), CastItoXBytes(file->statistic.GetAllTimeTransferred(), false, false));
			break;
		case 8:
			if (file->GetPartCount()){
				cur_rec->bottom--;
				cur_rec->top++;
					file->DrawShareStatusBar(dc,cur_rec,false,thePrefs.UseFlatBar());
				cur_rec->bottom++;
				cur_rec->top--;
			}
			break;
		case 9:
			buffer = file->GetPath();
			PathRemoveBackslash(buffer.GetBuffer());
			buffer.ReleaseBuffer();
			break;
		case 10:
            if (file->m_nCompleteSourcesCountLo == file->m_nCompleteSourcesCountHi)
				buffer.Format(_T("%u"), file->m_nCompleteSourcesCountLo);
            else if (file->m_nCompleteSourcesCountLo == 0)
				buffer.Format(_T("< %u"), file->m_nCompleteSourcesCountHi);
			else
				buffer.Format(_T("%u - %u"), file->m_nCompleteSourcesCountLo, file->m_nCompleteSourcesCountHi);
			break;
		case 11:{
			CPoint pt(cur_rec->left, cur_rec->top);
			m_ImageList.Draw(dc, file->GetPublishedED2K() ? 1 : 0, pt, ILD_NORMAL | ILD_TRANSPARENT);
			pt.x += 16;
			bool bSharedInKad;
			if ((uint32)time(NULL) < file->GetLastPublishTimeKadSrc())
			{
				if (theApp.IsFirewalled() && theApp.IsConnected())
				{
					if (theApp.clientlist->GetBuddy() && (file->GetLastPublishBuddy() == theApp.clientlist->GetBuddy()->GetIP()))
						bSharedInKad = true;
					else
						bSharedInKad = false;
				}
				else
					bSharedInKad = true;
			}
			else
				bSharedInKad = false;
			m_ImageList.Draw(dc, bSharedInKad ? 2 : 0, pt, ILD_NORMAL | ILD_TRANSPARENT);
			buffer.Empty();
			break;
		}
		// gomez82 >>> NSC - [NeoSharedCategories]
		case 12:
			if(file->GetCategory()!=0)
				buffer = thePrefs.GetCategory(file->GetCategory())->strTitle;
			else
				buffer.Empty();
			break;
		// gomez82 >>> NSC END
		// gomez82 >>> CRC - [MorphCRCTag] 
		case 13:
			if(file->IsCRC32Calculated()) {
				buffer.Format(_T("%02X%02X%02X%02X"),	(int) file->GetCalculatedCRC32() [3],
														(int) file->GetCalculatedCRC32() [2],
														(int) file->GetCalculatedCRC32() [1],
														(int) file->GetCalculatedCRC32() [0]);
				if(file->IsCRCOk())
					buffer.AppendFormat(_T(" %s"), GetResString(IDS_X_OK));
			}else
				buffer.Empty();
			break;
		// gomez82 >>> CRC END 
				// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
		case COL_HOS:
			{
				UINT hideOSInWork = file->HideOSInWork();
				buffer = _T("[") + GetResString((hideOSInWork>0)?IDS_ON_LABEL:IDS_OFF_LABEL) + _T("] ");
				if(file->GetHideOS()<0)
					buffer.Append(_T(" ") + ((CString)GetResString(IDS_DEFAULT)).Left(1) + _T(". "));
				hideOSInWork = (file->GetHideOS()>=0)?file->GetHideOS():thePrefs.GetHideOvershares();
				if (hideOSInWork>0)
					buffer.AppendFormat(_T("%i"), hideOSInWork);
				else
					buffer.AppendFormat(_T("%s"), GetResString(IDS_DISABLED));
				if (file->GetSelectiveChunk()>=0){
					if (file->GetSelectiveChunk())
						buffer.Append(_T(" + S"));
				}else
					if (thePrefs.IsSelectiveShareEnabled())
						buffer.Append(_T(" + ") + ((CString)GetResString(IDS_DEFAULT)).Left(1) + _T(". S"));
				break;
			}
		case COL_SOTN:
			if(file->GetShareOnlyTheNeed()>=0) {
				if (file->GetShareOnlyTheNeed())
					buffer.Format(_T("%i") ,file->GetShareOnlyTheNeed());
				else
					buffer = GetResString(IDS_DISABLED);
			} else {
				buffer = ((CString)GetResString(IDS_DEFAULT)).Left(1) + _T(". ") + GetResString((thePrefs.GetShareOnlyTheNeed())?IDS_ENABLED:IDS_DISABLED);
			}
			break;
			// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle				
			// gomez82 >>> Spread bars [Slugfiller/MorphXT] - Stulle
		case COL_QUEUE:
			buffer.Format(_T("%i") , file->GetQueuedCount());
			break;	
		case COL_UPPARTS:
				if(file->GetPartCount()){
			cur_rec->bottom--;
			cur_rec->top++;
			//CKnownFile* file ;
			file->statistic.DrawSpreadBar(dc,cur_rec,thePrefs.UseFlatBar());
			cur_rec->bottom++;
			cur_rec->top--;
}
			break;

	}

	if (iColumn != 8 ) 
		dc->DrawText(buffer, buffer.GetLength(), cur_rec, uDTFlags);
	if (iColumn == 0){
		cur_rec->left -= iIconDrawWidth;
		// gomez82 >>> NTS - [NeoTreeStyle]
		if(thePrefs.UseTreeStyle())
			cur_rec->left -= 12;
		// gomez82 >>> NTS END
	}
} 

void CSharedFilesCtrl::DrawPartItem(CDC *dc, int iColumn, LPRECT cur_rec, CSharedItem *part)
{
	UINT uDTFlags = DLC_DT_TEXT; 
	CString buffer;

	bool bOC = false;

	if(!bOC){
		bool PartDone=false;
		if(part->KnownFile->IsPartFile())
			PartDone = ((CPartFile*)part->KnownFile)->IsComplete(PARTSIZE*part->Part, PARTSIZE*part->Part+PARTSIZE-1, true);
		else
			PartDone = theApp.downloadqueue->IsFileExisting(part->KnownFile->GetFileHash(),false); 

		dc->SetTextColor(PartDone ? (COLORREF)RGB(0,0,0) : (COLORREF)RGB(192,192,192));
	}

	switch(iColumn){
		case 0:
			// gomez82 >>> NTS - [NeoTreeStyle]
			if(thePrefs.UseTreeStyle())
				cur_rec->left += 31;
			// gomez82 >>> NTS END

			buffer.Format(GetResString(IDS_X_PART_ENTRY),part->Part);
			break;
		case 1:
			if(part->KnownFile->IsPartFile() && !((CPartFile*)part->KnownFile)->IsComplete(PARTSIZE*part->Part, PARTSIZE*part->Part+PARTSIZE-1, true))
				buffer=GetResString(IDS_X_PART_NOT_DONE);
			else
				buffer=GetResString(IDS_X_PART_DONE);
			break;
		case 2:
			break;
		// gomez82 >>> MCS - [ManualChunkSelection]
		case 3:
			break;
		// gomez82 >>> MCS END
		case 4:
			buffer =  md4str(part->KnownFile->GetPartHash(part->Part));
			break;
		case 5:
			break;
		// gomez82 >>> NPT - [NeoPartTraffic]
		case 6:
			break;
		case 7:
			break;
		// gomez82 >>> NPT END
		case 8:
			break;
		case 9:
			break;
		case 10:{
			break;
		}
		case 11:
			break;
		case 12:
			break;
	
	}

	if (iColumn != 8 && iColumn != 13) // gomez82 >>> NPT - [NeoPartTraffic]
		dc->DrawText(buffer, buffer.GetLength(), cur_rec, uDTFlags);

	if (iColumn == 0){
		// gomez82 >>> NTS - [NeoTreeStyle]
		if(thePrefs.UseTreeStyle())
			cur_rec->left -= 31;
		// gomez82 >>> NTS END
	}
}
// gomez82 >>> SP END 


void CSharedFilesCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
	// gomez82 >>> SP - [SharedParts] -- Xanatos --
	int iSel = GetNextItem(-1, LVIS_SELECTED | LVIS_FOCUSED);

	CSharedItem* pSingleSelItem  = (iSel == -1) ? NULL : (CSharedItem*)GetItemData(iSel);
	if (pSingleSelItem && !pSingleSelItem->isFile){

		bool bFirstItem = true; 
		int iCompletePartSelected = 0; // gomez82 >>> PIX - [PartImportExport]
		int iInCompletePartSelected = 0; // gomez82 >>> MCS - [ManualChunkSelection]

//		UINT uPartPermMenuItem = 0; // gomez82 >>> MPS - [ManualPartSharing]

		CKnownFile* pSingleSelKnownFile = pSingleSelItem->KnownFile;
		CPartFile* pSingleSelPartFile = NULL;
		if(pSingleSelKnownFile->IsPartFile())
			pSingleSelPartFile = (CPartFile*)pSingleSelKnownFile;

		bool bFileExist = (theApp.downloadqueue->IsFileExisting(pSingleSelKnownFile->GetFileHash(),false));
		POSITION pos = GetFirstSelectedItemPosition();
		while (pos)
		{
			const CSharedItem* pItem = (CSharedItem*)GetItemData(GetNextSelectedItem(pos));

			if(pItem->isFile)
				continue;

			if(pItem->KnownFile != pSingleSelKnownFile){
				pSingleSelKnownFile = NULL;
				pSingleSelPartFile = NULL;
				bFileExist = false;
				break;
			}

			bool PartComplete = (!pSingleSelPartFile || pSingleSelPartFile->IsComplete(PARTSIZE*pItem->Part, PARTSIZE*pItem->Part+PARTSIZE-1, true)); 
			iCompletePartSelected += PartComplete ? 1 : 0; // gomez82 >>> PIX - [PartImportExport]  
			iInCompletePartSelected += PartComplete ? 0 : 1; // gomez82 >>> MCS - [ManualChunkSelection]



			bFirstItem = false;
		}

		CTitleMenu PartMenu;
		PartMenu.CreatePopupMenu();
		PartMenu.AddMenuTitle(GetResString(IDS_X_PARTS), true);





		GetPopupMenuPos(*this, point);
		PartMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON, point.x, point.y, this);

		VERIFY( PartMenu.DestroyMenu() );

		return;
	}
	// gomez82 >>> SP END 

	// get merged settings
	bool bFirstItem = true;
	int iSelectedItems = GetSelectedCount();
	int iCompleteFileSelected = -1;
	UINT uPrioMenuItem = 0;
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	int iHideOS = -1;
	UINT uHideOSMenuItem = 0;
	UINT uSelectiveChunkMenuItem = 0;
	UINT uShareOnlyTheNeedMenuItem = 0;
	CString buffer;
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle

	//const CKnownFile* pSingleSelFile = NULL;
	const CKnownFile* pSingleSelFile = pSingleSelItem ? pSingleSelItem->KnownFile : NULL; // gomez82 >>> SP - [SharedParts] 
	POSITION pos = GetFirstSelectedItemPosition();
	while (pos)
	{
		// gomez82 >>> SP - [SharedParts] 
		const CSharedItem* pItem = (CSharedItem*)GetItemData(GetNextSelectedItem(pos));
		if(!pItem->isFile)
			continue;
		const CKnownFile* pFile = pItem->KnownFile;
		// gomez82 >>> SP END 

		/*const CKnownFile* pFile = (CKnownFile*)GetItemData(GetNextSelectedItem(pos));
		if (bFirstItem)
			pSingleSelFile = pFile;
		else
			pSingleSelFile = NULL;*/

		int iCurCompleteFile = pFile->IsPartFile() ? 0 : 1;
		if (bFirstItem)
			iCompleteFileSelected = iCurCompleteFile;
		else if (iCompleteFileSelected != iCurCompleteFile)
			iCompleteFileSelected = -1;

		UINT uCurPrioMenuItem = 0;
        if(!pFile->GetPowerShared()) {
		    if (pFile->IsAutoUpPriority())
			    uCurPrioMenuItem = MP_PRIOAUTO;
		    else if (pFile->GetUpPriority() == PR_VERYLOW)
			    uCurPrioMenuItem = MP_PRIOVERYLOW;
		    else if (pFile->GetUpPriority() == PR_LOW)
			    uCurPrioMenuItem = MP_PRIOLOW;
		    else if (pFile->GetUpPriority() == PR_NORMAL)
			    uCurPrioMenuItem = MP_PRIONORMAL;
		    else if (pFile->GetUpPriority() == PR_HIGH)
			    uCurPrioMenuItem = MP_PRIOHIGH;
		    else if (pFile->GetUpPriority() == PR_VERYHIGH)
			    uCurPrioMenuItem = MP_PRIOVERYHIGH;
		    else
			    ASSERT(0);
        } else {
		    if (pFile->GetUpPriority() == PR_VERYLOW)
                uCurPrioMenuItem = MP_PRIO_POWERSHARE_VERYLOW;
		    else if (pFile->GetUpPriority() == PR_LOW)
			    uCurPrioMenuItem = MP_PRIO_POWERSHARE_LOW;
		    else if (pFile->GetUpPriority() == PR_NORMAL)
			    uCurPrioMenuItem = MP_PRIO_POWERSHARE_NORMAL;
		    else if (pFile->GetUpPriority() == PR_HIGH)
			    uCurPrioMenuItem = MP_PRIO_POWERSHARE_HIGH;
		    else if (pFile->GetUpPriority() == PR_VERYHIGH)
			    uCurPrioMenuItem = MP_PRIO_POWERSHARE_VERYHIGH;
		    else
			    ASSERT(0);
        }
		// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
		UINT uCurHideOSMenuItem = 0;
		int iCurHideOS = pFile->GetHideOS();
		if (iCurHideOS == -1)
			uCurHideOSMenuItem = MP_HIDEOS_DEFAULT;
		else
			uCurHideOSMenuItem = MP_HIDEOS_SET;
		if (bFirstItem)
		{
			uHideOSMenuItem = uCurHideOSMenuItem;
			iHideOS = iCurHideOS;
		}
		else if (uHideOSMenuItem != uCurHideOSMenuItem || iHideOS != iCurHideOS)
		{
			uHideOSMenuItem = 0;
			iHideOS = -1;
		}
		
		UINT uCurSelectiveChunkMenuItem = 0;
		if (pFile->GetSelectiveChunk() == -1)
			uCurSelectiveChunkMenuItem = MP_SELECTIVE_CHUNK;
		else
			uCurSelectiveChunkMenuItem = MP_SELECTIVE_CHUNK+1 + pFile->GetSelectiveChunk();
		if (bFirstItem)
			uSelectiveChunkMenuItem = uCurSelectiveChunkMenuItem;
		else if (uSelectiveChunkMenuItem != uCurSelectiveChunkMenuItem)
			uSelectiveChunkMenuItem = 0;

		UINT uCurShareOnlyTheNeedMenuItem = 0;
		if (pFile->GetShareOnlyTheNeed() == -1)
			uCurShareOnlyTheNeedMenuItem = MP_SHAREONLYTHENEED;
		else
			uCurShareOnlyTheNeedMenuItem = MP_SHAREONLYTHENEED+1 + pFile->GetShareOnlyTheNeed();
		if (bFirstItem)
			uShareOnlyTheNeedMenuItem = uCurShareOnlyTheNeedMenuItem ;
		else if (uShareOnlyTheNeedMenuItem != uCurShareOnlyTheNeedMenuItem)
			uShareOnlyTheNeedMenuItem = 0;
		// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle

		if (bFirstItem)
			uPrioMenuItem = uCurPrioMenuItem;
		else if (uPrioMenuItem != uCurPrioMenuItem)
			uPrioMenuItem = 0;

		bFirstItem = false;
	}

	m_SharedFilesMenu.EnableMenuItem((UINT_PTR)m_PrioMenu.m_hMenu, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED);
	m_PrioMenu.CheckMenuRadioItem(MP_PRIOVERYLOW, MP_PRIO_POWERSHARE_VERYHIGH, uPrioMenuItem, 0);

	bool bSingleCompleteFileSelected = (iSelectedItems == 1 && iCompleteFileSelected == 1);
	m_SharedFilesMenu.EnableMenuItem(MP_OPEN, bSingleCompleteFileSelected ? MF_ENABLED : MF_GRAYED);
	UINT uInsertedMenuItem = 0;
	static const TCHAR _szSkinPkgSuffix1[] = _T(".") EMULSKIN_BASEEXT _T(".zip");
	static const TCHAR _szSkinPkgSuffix2[] = _T(".") EMULSKIN_BASEEXT _T(".rar");
	if (bSingleCompleteFileSelected 
		&& pSingleSelFile 
		&& (   pSingleSelFile->GetFilePath().Right(ARRSIZE(_szSkinPkgSuffix1)-1).CompareNoCase(_szSkinPkgSuffix1) == 0
		    || pSingleSelFile->GetFilePath().Right(ARRSIZE(_szSkinPkgSuffix2)-1).CompareNoCase(_szSkinPkgSuffix2) == 0))
	{
		MENUITEMINFO mii = {0};
		mii.cbSize = sizeof mii;
		mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
		mii.fType = MFT_STRING;
		mii.fState = MFS_ENABLED;
		mii.wID = MP_INSTALL_SKIN;
		CString strBuff(GetResString(IDS_INSTALL_SKIN));
		mii.dwTypeData = const_cast<LPTSTR>((LPCTSTR)strBuff);
		if (::InsertMenuItem(m_SharedFilesMenu, MP_OPENFOLDER, FALSE, &mii))
			uInsertedMenuItem = mii.wID;
	}
	m_SharedFilesMenu.EnableMenuItem(MP_OPENFOLDER, bSingleCompleteFileSelected ? MF_ENABLED : MF_GRAYED);
	m_SharedFilesMenu.EnableMenuItem(MP_RENAME, bSingleCompleteFileSelected ? MF_ENABLED : MF_GRAYED);
	m_SharedFilesMenu.EnableMenuItem(MP_REMOVE, iCompleteFileSelected > 0 ? MF_ENABLED : MF_GRAYED);
	// gomez82 >>> SSF - [ShareSingleFiles] 
	bool bCanUnshare = false;
	if(pSingleSelFile)
	{
		for (POSITION pos = thePrefs.sharedfile_list.GetHeadPosition(); pos != 0; ) {
			if(thePrefs.sharedfile_list.GetNext(pos).CompareNoCase(MkPath(pSingleSelFile->GetPath(),pSingleSelFile->GetFileName())))
				continue;
			bCanUnshare = true;
			break;
		}
	}
	m_SharedFilesMenu.EnableMenuItem(MP_UNSHARE_FILE, bCanUnshare ? MF_ENABLED : MF_GRAYED);
	// gomez82 >>> SSF END 
	m_SharedFilesMenu.SetDefaultItem(bSingleCompleteFileSelected ? MP_OPEN : -1);
	m_SharedFilesMenu.EnableMenuItem(MP_CMT, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED);
	m_SharedFilesMenu.EnableMenuItem(MP_DETAIL, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED);
	m_SharedFilesMenu.EnableMenuItem(thePrefs.GetShowCopyEd2kLinkCmd() ? MP_GETED2KLINK : MP_SHOWED2KLINK, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED);
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	m_SharedFilesMenu.EnableMenuItem((UINT_PTR)m_HideOSMenu.m_hMenu, (iSelectedItems > 0 && iCompleteFileSelected > 0) ? MF_ENABLED : MF_GRAYED);
	m_SharedFilesMenu.EnableMenuItem((UINT_PTR)m_SelectiveChunkMenu.m_hMenu, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED);
	if (thePrefs.GetHideOvershares()==0)
		buffer.Format(_T(" (%s)"),GetResString(IDS_DISABLED));
	else
		buffer.Format(_T(" (%u)"),thePrefs.GetHideOvershares());
	m_HideOSMenu.ModifyMenu(MP_HIDEOS_DEFAULT, MF_STRING,MP_HIDEOS_DEFAULT, GetResString(IDS_DEFAULT) + buffer);
	if (iHideOS==-1)
		buffer = GetResString(IDS_EDIT);
	else if (iHideOS==0)
		buffer = GetResString(IDS_DISABLED);
	else
		buffer.Format(_T("%i"), iHideOS);
	m_HideOSMenu.ModifyMenu(MP_HIDEOS_SET, MF_STRING,MP_HIDEOS_SET, buffer);
	m_HideOSMenu.CheckMenuRadioItem(MP_HIDEOS_DEFAULT, MP_HIDEOS_SET, uHideOSMenuItem, 0);
	buffer.Format(_T(" (%s)"),thePrefs.IsSelectiveShareEnabled()?GetResString(IDS_ENABLED):GetResString(IDS_DISABLED));
	m_SelectiveChunkMenu.ModifyMenu(MP_SELECTIVE_CHUNK, MF_STRING, MP_SELECTIVE_CHUNK, GetResString(IDS_DEFAULT) + buffer);
	m_SelectiveChunkMenu.CheckMenuRadioItem(MP_SELECTIVE_CHUNK, MP_SELECTIVE_CHUNK_1, uSelectiveChunkMenuItem, 0);

	m_SharedFilesMenu.EnableMenuItem((UINT_PTR)m_ShareOnlyTheNeedMenu.m_hMenu, (iSelectedItems > 0 && iCompleteFileSelected > 0) ? MF_ENABLED : MF_GRAYED);
	buffer.Format(_T(" (%s)"),thePrefs.GetShareOnlyTheNeed()?GetResString(IDS_ENABLED):GetResString(IDS_DISABLED));
	m_ShareOnlyTheNeedMenu.ModifyMenu(MP_SHAREONLYTHENEED, MF_STRING, MP_SHAREONLYTHENEED, GetResString(IDS_DEFAULT) + buffer);
	m_ShareOnlyTheNeedMenu.CheckMenuRadioItem(MP_SHAREONLYTHENEED, MP_SHAREONLYTHENEED_1, uShareOnlyTheNeedMenuItem, 0);
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	m_SharedFilesMenu.EnableMenuItem(MP_SPREADBAR_RESET, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED); // Spread bars [Slugfiller/MorphXT] - Stulle

	m_SharedFilesMenu.EnableMenuItem(MP_FIND, GetItemCount() > 0 ? MF_ENABLED : MF_GRAYED);
	
	m_CollectionsMenu.EnableMenuItem(MP_MODIFYCOLLECTION, ( pSingleSelFile != NULL && pSingleSelFile->m_pCollection != NULL ) ? MF_ENABLED : MF_GRAYED);
	m_CollectionsMenu.EnableMenuItem(MP_VIEWCOLLECTION, ( pSingleSelFile != NULL && pSingleSelFile->m_pCollection != NULL ) ? MF_ENABLED : MF_GRAYED);
	m_CollectionsMenu.EnableMenuItem(MP_SEARCHAUTHOR, ( pSingleSelFile != NULL && pSingleSelFile->m_pCollection != NULL && !pSingleSelFile->m_pCollection->GetAuthorKeyHashString().IsEmpty()) ? MF_ENABLED : MF_GRAYED);

	m_SharedFilesMenu.EnableMenuItem((UINT_PTR)m_CRC32Menu.m_hMenu, iSelectedItems > 0 ? MF_ENABLED : MF_GRAYED); // gomez82 >>> CRC - [MorphCRCTag] 

#if defined(_DEBUG)
	if (thePrefs.IsExtControlsEnabled()){
	//JOHNTODO: Not for release as we need kad lowID users in the network to see how well this work work. Also, we do not support these links yet.
		if (iSelectedItems > 0 && theApp.IsConnected() && theApp.IsFirewalled() && theApp.clientlist->GetBuddy())
			m_SharedFilesMenu.EnableMenuItem(MP_GETKADSOURCELINK, MF_ENABLED);
		else
			m_SharedFilesMenu.EnableMenuItem(MP_GETKADSOURCELINK, MF_GRAYED);
	}
#endif
	m_SharedFilesMenu.EnableMenuItem(Irc_SetSendLink, iSelectedItems == 1 && theApp.emuledlg->ircwnd->IsConnected() ? MF_ENABLED : MF_GRAYED);
	// gomez82 >>> NSC - [NeoSharedCategories] 
	CTitleMenu CatsMenu;
	if(pSingleSelFile){
		CatsMenu.CreateMenu();
		CatsMenu.AddMenuTitle(NULL, true);
		UpdateCatMenu(CatsMenu,pSingleSelFile->GetCategory(),true);
		UINT flag = (thePrefs.GetFullCatCount() == 1) ? MF_GRAYED : MF_ENABLED;
		m_SharedFilesMenu.AppendMenu(MF_POPUP | flag, (UINT_PTR)CatsMenu.m_hMenu, GetResString(IDS_TOCAT), _T("CATEGORY"));
	}
	// gomez82 >>> NSC END 
	CTitleMenu WebMenu;
	WebMenu.CreateMenu();
	WebMenu.AddMenuTitle(NULL, true);
	int iWebMenuEntries = theWebServices.GetFileMenuEntries(&WebMenu);
	UINT flag2 = (iWebMenuEntries == 0 || iSelectedItems != 1) ? MF_GRAYED : MF_STRING;
	m_SharedFilesMenu.AppendMenu(flag2 | MF_POPUP, (UINT_PTR)WebMenu.m_hMenu, GetResString(IDS_WEBSERVICES), _T("WEB"));

	GetPopupMenuPos(*this, point);
	m_SharedFilesMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x,point.y,this);

	m_SharedFilesMenu.RemoveMenu(m_SharedFilesMenu.GetMenuItemCount()-1,MF_BYPOSITION);
	// gomez82 >>> NSC - [NeoSharedCategories] 
	if(iSelectedItems > 0)
		m_SharedFilesMenu.RemoveMenu(m_SharedFilesMenu.GetMenuItemCount()-1,MF_BYPOSITION); 
	// gomez82 >>> NSC END 
	VERIFY( WebMenu.DestroyMenu() );
	// gomez82 >>> NSC - [NeoSharedCategories] 
	if(iSelectedItems > 0)
		VERIFY( CatsMenu.DestroyMenu() );
	// gomez82 >>> NSC END 
	if (uInsertedMenuItem)
		VERIFY( m_SharedFilesMenu.RemoveMenu(uInsertedMenuItem, MF_BYCOMMAND) );
}

BOOL CSharedFilesCtrl::OnCommand(WPARAM wParam, LPARAM /*lParam*/)
{
	wParam = LOWORD(wParam);

	// gomez82 >>> SP - [SharedParts] 
	CSharedItem* pSingleSelItem  = NULL;
	
	int iSel = GetNextItem(-1, LVIS_SELECTED | LVIS_FOCUSED);
	if (iSel == -1)
		iSel = GetNextItem(-1, LVIS_SELECTED);
	if (iSel != -1)
		pSingleSelItem  = (CSharedItem*)GetItemData(iSel);

	if (pSingleSelItem && !pSingleSelItem->isFile){

		CTypedPtrList<CPtrList, CSharedItem*> selectedList;
		POSITION pos = GetFirstSelectedItemPosition();
		while (pos != NULL){
			int index = GetNextSelectedItem(pos);
			if (index >= 0){
				CSharedItem* pItem = (CSharedItem*)GetItemData(index);
				if(pItem->isFile) 
					continue;
				if(pItem->KnownFile != pSingleSelItem->KnownFile)
					continue;
				selectedList.AddTail(pItem);
			}
		}

//		const CSharedItem* part;
		/*
		switch (wParam){



		}
*/
		return TRUE;
	}
	// gomez82 >>> SP END 

	CTypedPtrList<CPtrList, CKnownFile*> selectedList;
	POSITION pos = GetFirstSelectedItemPosition();
	while (pos != NULL){
		int index = GetNextSelectedItem(pos);
		if (index >= 0)
		// gomez82 >>> SP - [SharedParts] 
		{
			CSharedItem* pItem = (CSharedItem*)GetItemData(index);
			if(!pItem->isFile) 
				continue;
			selectedList.AddTail(pItem->KnownFile);
		}
		// gomez82 >>> SP END 
		//	selectedList.AddTail((CKnownFile*)GetItemData(index));
	}

	if (   wParam == MP_CREATECOLLECTION
		|| wParam == MP_FIND
		|| selectedList.GetCount() > 0)
	{
		CKnownFile* file = NULL;
		if (selectedList.GetCount() == 1)
			file = selectedList.GetHead();

		switch (wParam){
			case Irc_SetSendLink:
				if (file)
					theApp.emuledlg->ircwnd->SetSendFileString(CreateED2kLink(file));
				break;
			case MP_GETED2KLINK:{
				CString str;
				POSITION pos = selectedList.GetHeadPosition();
				while (pos != NULL)
				{
					file = selectedList.GetNext(pos);
					if (!str.IsEmpty())
						str += _T("\r\n");
					str += CreateED2kLink(file);
				}
				theApp.CopyTextToClipboard(str);
				break;
			}
#if defined(_DEBUG)
			//JOHNTODO: Not for release as we need kad lowID users in the network to see how well this work work. Also, we do not support these links yet.
			case MP_GETKADSOURCELINK:{
				CString str;
				POSITION pos = selectedList.GetHeadPosition();
				while (pos != NULL)
				{
					file = selectedList.GetNext(pos);
					if (!str.IsEmpty())
						str += _T("\r\n");
					str += theApp.CreateKadSourceLink(file);
				}
				theApp.CopyTextToClipboard(str);
				break;
			}
#endif
			// file operations
			case MP_OPEN:
			case IDA_ENTER:
				if (file && !file->IsPartFile())
					OpenFile(file);
				break; 
			case MP_INSTALL_SKIN:
				if (file && !file->IsPartFile())
					InstallSkin(file->GetFilePath());
				break;
			case MP_OPENFOLDER:
				if (file && !file->IsPartFile())
					ShellExecute(NULL, _T("open"), file->GetPath(), NULL, NULL, SW_SHOW);
				break; 
			case MP_RENAME:
			case MPG_F2:
				if (file && !file->IsPartFile()){
					InputBox inputbox;
					CString title = GetResString(IDS_RENAME);
					title.Remove(_T('&'));
					inputbox.SetLabels(title, GetResString(IDS_DL_FILENAME), file->GetFileName());
					inputbox.SetEditFilenameMode();
					inputbox.DoModal();
					CString newname = inputbox.GetInput();
					if (!inputbox.WasCancelled() && newname.GetLength()>0)
					{
						// at least prevent users from specifying something like "..\dir\file"
						static const TCHAR _szInvFileNameChars[] = _T("\\/:*?\"<>|");
						if (newname.FindOneOf(_szInvFileNameChars) != -1){
							AfxMessageBox(GetErrorMessage(ERROR_BAD_PATHNAME));
							break;
						}

						CString newpath;
						PathCombine(newpath.GetBuffer(MAX_PATH), file->GetPath(), newname);
						newpath.ReleaseBuffer();
						if (_trename(file->GetFilePath(), newpath) != 0){
							CString strError;
							strError.Format(GetResString(IDS_ERR_RENAMESF), file->GetFilePath(), newpath, _tcserror(errno));
							AfxMessageBox(strError);
							break;
						}

						if (file->IsKindOf(RUNTIME_CLASS(CPartFile)))
						{
							file->SetFileName(newname);
							STATIC_DOWNCAST(CPartFile, file)->SetFullName(newpath); 
						}
						else
						{
							theApp.sharedfiles->RemoveKeywords(file);
							file->SetFileName(newname);
							theApp.sharedfiles->AddKeywords(file);
						}
						file->SetFilePath(newpath);
						UpdateFile(file);
					}
				}
				else
					MessageBeep(MB_OK);
				break;
			case MP_REMOVE:
			case MPG_DELETE:
			{
				if (IDNO == AfxMessageBox(GetResString(IDS_CONFIRM_FILEDELETE),MB_ICONWARNING | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_YESNO))
					return TRUE;

				SetRedraw(FALSE);
				bool bRemovedItems = false;
				while (!selectedList.IsEmpty())
				{
					CKnownFile* myfile = selectedList.RemoveHead();
					if (!myfile || myfile->IsPartFile())
						continue;
					
					BOOL delsucc = FALSE;
					if (!PathFileExists(myfile->GetFilePath()))
						delsucc = TRUE;
					else{
						// Delete
						if (!thePrefs.GetRemoveToBin()){
							delsucc = DeleteFile(myfile->GetFilePath());
						}
						else{
							// delete to recycle bin :(
							TCHAR todel[MAX_PATH+1];
							memset(todel, 0, sizeof todel);
							_tcsncpy(todel, myfile->GetFilePath(), ARRSIZE(todel)-2);

							SHFILEOPSTRUCT fp = {0};
							fp.wFunc = FO_DELETE;
							fp.hwnd = theApp.emuledlg->m_hWnd;
							fp.pFrom = todel;
							fp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;// | FOF_NOERRORUI
							delsucc = (SHFileOperation(&fp) == 0);
						}
					}
					if (delsucc){
						theApp.sharedfiles->RemoveFile(myfile);
						bRemovedItems = true;
						if (myfile->IsKindOf(RUNTIME_CLASS(CPartFile)))
							theApp.emuledlg->transferwnd->downloadlistctrl.ClearCompleted(static_cast<CPartFile*>(myfile));
					}
					else{
						CString strError;
						strError.Format( GetResString(IDS_ERR_DELFILE) + _T("\r\n\r\n%s"), myfile->GetFilePath(), GetErrorMessage(GetLastError()));
						AfxMessageBox(strError);
					}
				}
				SetRedraw(TRUE);
				if (bRemovedItems) {
					AutoSelectItem();
					// Depending on <no-idea> this does not always cause a
					// LVN_ITEMACTIVATE message sent. So, explicitly redraw
					// the item.
					theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary();
				}
				break; 
			}
			// gomez82 >>> SSF - [ShareSingleFiles] 
			case MP_UNSHARE_FILE: {
				if (IDNO == AfxMessageBox(GetResString(IDS_X_CONFIRM_FILEUSHARE),MB_ICONWARNING | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_YESNO))
					return TRUE;

				SetRedraw(FALSE);
				bool bRemovedItems = false;
				while (!selectedList.IsEmpty())
				{
					CKnownFile* myfile = selectedList.RemoveHead();
					if (!myfile || myfile->IsPartFile())
						continue;
					
					CString sFile = MkPath(myfile->GetPath(), myfile->GetFileName());
					bool bCanUnshare = false;
					POSITION remPos = NULL;
					for (POSITION pos = thePrefs.sharedfile_list.GetHeadPosition(); pos != 0; ) {
						remPos = pos;
						if(thePrefs.sharedfile_list.GetNext(pos).CompareNoCase(sFile))
							continue;
						bCanUnshare = true;
						break;
					}

					if (bCanUnshare){
						thePrefs.sharedfile_list.RemoveAt(remPos);
						theApp.sharedfiles->RemoveFile(myfile);
						bRemovedItems = true;
						if (myfile->IsKindOf(RUNTIME_CLASS(CPartFile)))
							theApp.emuledlg->transferwnd->downloadlistctrl.ClearCompleted(static_cast<CPartFile*>(myfile));
						thePrefs.Save();
					}
					else{
						CString strError;
						strError.Format(GetResString(IDS_X_ERR_UNSHARE), myfile->GetFilePath());
						AfxMessageBox(strError);
					}
				}
				SetRedraw(TRUE);
				if (bRemovedItems) {
					AutoSelectItem();
					// Depending on <no-idea> this does not always cause a
					// LVN_ITEMACTIVATE message sent. So, explicitly redraw
					// the item.
					theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary();
				}
                break; 
			}
			// gomez82 >>> SSF END 
			case MP_CMT:
				ShowFileDialog(selectedList, IDD_COMMENT);
                break; 
			case MPG_ALTENTER:
			case MP_DETAIL:
				ShowFileDialog(selectedList);
				break;
			case MP_FIND:
				OnFindStart();
				break;
			case MP_CREATECOLLECTION:
			{
				CCollection* pCollection = new CCollection();
				POSITION pos = selectedList.GetHeadPosition();
				while (pos != NULL)
				{
					pCollection->AddFileToCollection(selectedList.GetNext(pos),true);
				}
				CCollectionCreateDialog dialog;
				dialog.SetCollection(pCollection,true);
				dialog.DoModal();
				//We delete this collection object because when the newly created
				//collection file is added to the sharedfile list, it is read and verified
				//and which creates the colleciton object that is attached to that file..
				delete pCollection;
				break;
			}
			case MP_SEARCHAUTHOR:
				if (selectedList.GetCount() == 1 && file->m_pCollection)
				{
					SSearchParams* pParams = new SSearchParams;
					pParams->strExpression = file->m_pCollection->GetCollectionAuthorKeyString();
					pParams->eType = SearchTypeKademlia;
					pParams->strFileType = ED2KFTSTR_EMULECOLLECTION;
					pParams->strSpecialTitle = file->m_pCollection->m_sCollectionAuthorName;
					if (pParams->strSpecialTitle.GetLength() > 50){
						pParams->strSpecialTitle = pParams->strSpecialTitle.Left(50) + _T("...");
					}
					theApp.emuledlg->searchwnd->m_pwndResults->StartSearch(pParams);
				}
				break;
			case MP_VIEWCOLLECTION:
				if (selectedList.GetCount() == 1 && file->m_pCollection)
				{
					CCollectionViewDialog dialog;
					dialog.SetCollection(file->m_pCollection);
					dialog.DoModal();
				}
				break;
			case MP_MODIFYCOLLECTION:
				if (selectedList.GetCount() == 1 && file->m_pCollection)
				{
					CCollectionCreateDialog dialog;
					CCollection* pCollection = new CCollection(file->m_pCollection);
					dialog.SetCollection(pCollection,false);
					dialog.DoModal();
					delete pCollection;				
				}
				break;
			case MP_SHOWED2KLINK:
				ShowFileDialog(selectedList, IDD_ED2KLINK);
				break;
			case MP_PRIOVERYLOW:
			case MP_PRIOLOW:
			case MP_PRIONORMAL:
			case MP_PRIOHIGH:
			case MP_PRIOVERYHIGH:
            case MP_PRIO_POWERSHARE_VERYLOW:
			case MP_PRIO_POWERSHARE_LOW:
			case MP_PRIO_POWERSHARE_NORMAL:
			case MP_PRIO_POWERSHARE_HIGH:
			case MP_PRIO_POWERSHARE_VERYHIGH:
			case MP_PRIOAUTO:
				{
					POSITION pos = selectedList.GetHeadPosition();
					while (pos != NULL)
					{
						CKnownFile* file = selectedList.GetNext(pos);
						switch (wParam) {
							case MP_PRIOVERYLOW:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(false);
								file->SetUpPriority(PR_VERYLOW);
								UpdateFile(file);
								break;
							case MP_PRIOLOW:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(false);
								file->SetUpPriority(PR_LOW);
								UpdateFile(file);
								break;
							case MP_PRIONORMAL:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(false);
								file->SetUpPriority(PR_NORMAL);
								UpdateFile(file);
								break;
							case MP_PRIOHIGH:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(false);
								file->SetUpPriority(PR_HIGH);
								UpdateFile(file);
								break;
							case MP_PRIOVERYHIGH:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(false);
								file->SetUpPriority(PR_VERYHIGH);
								UpdateFile(file);
								break;	

							case MP_PRIO_POWERSHARE_VERYLOW:
							    file->SetAutoUpPriority(false);
                                file->SetPowerShared(true);
                                file->SetUpPriority(PR_VERYLOW);
                                //SetItemText(iSel,3,GetResString(IDS_POWERSHARE_PREFIX) + " " + GetResString(IDS_PRIOVERYLOW ));
								UpdateFile(file);
                                break;
							case MP_PRIO_POWERSHARE_LOW:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(true);
                                file->SetUpPriority(PR_LOW);
                                //SetItemText(iSel,3,GetResString(IDS_POWERSHARE_PREFIX) + " " + GetResString(IDS_PRIOLOW ));
								UpdateFile(file);
                                break;
							case MP_PRIO_POWERSHARE_NORMAL:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(true);
                                file->SetUpPriority(PR_NORMAL);
                                //SetItemText(iSel,3,GetResString(IDS_POWERSHARE_PREFIX) + " " + GetResString(IDS_PRIONORMAL ));
								UpdateFile(file);
                                break;
							case MP_PRIO_POWERSHARE_HIGH:
							    file->SetAutoUpPriority(false);
                                file->SetPowerShared(true);
                                file->SetUpPriority(PR_HIGH);
                                //SetItemText(iSel,3,GetResString(IDS_POWERSHARE_PREFIX) + " " + GetResString(IDS_PRIOHIGH ));
								UpdateFile(file);
                                break;
							case MP_PRIO_POWERSHARE_VERYHIGH:
								file->SetAutoUpPriority(false);
                                file->SetPowerShared(true);
                                file->SetUpPriority(PR_VERYHIGH);
                                //SetItemText(iSel,3,GetResString(IDS_POWERSHARE_PREFIX) + " " + GetResString(IDS_PRIORELEASE ));
								UpdateFile(file);
                                break;

							case MP_PRIOAUTO:
								file->SetAutoUpPriority(true);
                                file->SetPowerShared(false);
								file->UpdateAutoUpPriority();
								UpdateFile(file); 
								break;
						}
					}
					break;
				}
			// gomez82 >>> CRC - [MorphCRCTag] 
			case MP_CRC32_RECALCULATE: 
				// Remove existing CRC32 tags from the selected files
				if (!selectedList.IsEmpty()){
					POSITION pos = selectedList.GetHeadPosition();
					while (pos != NULL) {
						CKnownFile* file = selectedList.GetAt (pos);
						memset(file->GetCalculatedCRC32rw(),0,sizeof(BYTE)*4);
						//UpdateFile(file);
						selectedList.GetNext (pos);
					}
				}
				// Repaint the list 
				Invalidate();
				// !!! NO "break;" HERE !!!
				// This case branch must lead into the MP_CRC32_CALCULATE branch - 
				// so after removing the CRC's from the selected files they
				// are immediately recalculated!
			case MP_CRC32_CALCULATE: 
				if (!selectedList.IsEmpty()){
					// For every chosen file create a worker thread and add it
					// to the file processing thread
					POSITION pos = selectedList.GetHeadPosition();
					while (pos != NULL) {
						CCRC32CalcWorker* worker = new CCRC32CalcWorker;
						CKnownFile*  file = selectedList.GetAt (pos);
						const uchar* FileHash = file->GetFileHash ();
						worker->SetFileHashToProcess (FileHash);
						worker->SetFilePath (file->GetFilePath ());
						m_FileProcessingThread.AddFileProcessingWorker (worker);
						selectedList.GetNext (pos);
					}
					// Start the file processing thread to process the files.
					if (!m_FileProcessingThread.IsRunning ()) {
						// (Re-)start the thread, this will do the rest

						// If the thread object already exists, this will result in an
						// ASSERT - but that doesn't matter since we manually take care
						// that the thread does not run at this moment...
						m_FileProcessingThread.CreateThread ();
					}
				}
				break;
			case MP_CRC32_ABORT:
				// Message the File processing thread to stop any pending calculations
				if (m_FileProcessingThread.IsRunning ())
					m_FileProcessingThread.Terminate ();
				break;
			case MP_CRC32_TAG:
				if (!selectedList.IsEmpty()){
					AddCRC32InputBox AddCRCDialog;
					// Add the files to the dialog
					POSITION pos = selectedList.GetHeadPosition();
					while (pos != NULL) {
						CKnownFile*  file = selectedList.GetAt (pos);
						AddCRCDialog.m_FileList.AddTail (file);
						selectedList.GetNext (pos);
					}
				AddCRCDialog.DoModal();
					// gomez82 >>> MLD END
				}
				break;
			// gomez82 >>> CRC END 
			// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
			case MP_HIDEOS_DEFAULT:
			case MP_HIDEOS_SET:
			{
				POSITION pos = selectedList.GetHeadPosition();
				int newHideOS = -1;
				if (wParam==MP_HIDEOS_SET)
				{
					InputBox inputbox;
					CString title=GetResString(IDS_HIDEOS);
					CString currHideOS;
					if (file)
						currHideOS.Format(_T("%i"), (file->GetHideOS()>=0)?file->GetHideOS():thePrefs.GetHideOvershares());
					else
						currHideOS = _T("0");
					inputbox.SetLabels(GetResString(IDS_HIDEOS), GetResString(IDS_HIDEOVERSHARES), currHideOS);
					inputbox.SetNumber(true);
					int result = inputbox.DoModal();
					if (result == IDCANCEL || (newHideOS = inputbox.GetInputInt()) < 0)
						break;
				}
				SetRedraw(FALSE);
				while (pos != NULL)
				{
					file = selectedList.GetNext(pos);
					if  (newHideOS == file->GetHideOS()) break;
					file->SetHideOS(newHideOS);
					UpdateFile(file);
				}
				SetRedraw(TRUE);
				break;
			}
			// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
			// gomez82 >>> Spread bars [Slugfiller/MorphXT] - Stulle
			case MP_SPREADBAR_RESET:
			{
				SetRedraw(FALSE);
				POSITION pos = selectedList.GetHeadPosition();
				while (pos != NULL)
				{
					file = selectedList.GetNext(pos);
					file->statistic.ResetSpreadBar();
				}
				SetRedraw(TRUE);
			}
			   theApp.emuledlg->sharedfileswnd->Reload();
				break;
			// gomez82 >>> Spread bars [Slugfiller/MorphXT] - Stulle

			default:
				// gomez82 >>> NSC - [NeoSharedCategories] 
				if (wParam>=MP_ASSIGNCAT && wParam<=MP_ASSIGNCAT+99){
					SetRedraw(FALSE);
					while (!selectedList.IsEmpty()){
						CKnownFile *knownfile = selectedList.GetHead();
						knownfile->SetCategory(wParam - MP_ASSIGNCAT);
						//knownfile->UpdateDisplayedInfo(true);
						selectedList.RemoveHead();
					}
					SetRedraw(TRUE);
					ReloadFileList(); //UpdateCurrentCategoryView();
					if (thePrefs.ShowCatTabInfos())
						theApp.emuledlg->transferwnd->UpdateCatTabTitles();
				}
				// gomez82 >>> NSC END 	
			// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
				/*
				if (wParam>=MP_WEBURL && wParam<=MP_WEBURL+256){
					theWebServices.RunURL(file, wParam);
				}
				*/
				POSITION pos = selectedList.GetHeadPosition();
				while (pos != NULL)
				{
					file = selectedList.GetNext(pos);
				if (wParam>=MP_WEBURL && wParam<=MP_WEBURL+256){
					theWebServices.RunURL(file, wParam);
				}

					else if (wParam>=MP_SELECTIVE_CHUNK && wParam<=MP_SELECTIVE_CHUNK_1){
						file->SetSelectiveChunk(wParam==MP_SELECTIVE_CHUNK?-1:wParam-MP_SELECTIVE_CHUNK_0);
						UpdateFile(file);
					}else if (wParam>=MP_SHAREONLYTHENEED && wParam<=MP_SHAREONLYTHENEED_1){
						file->SetShareOnlyTheNeed(wParam==MP_SHAREONLYTHENEED?-1:wParam-MP_SHAREONLYTHENEED_0);
						UpdateFile(file);
					}


				}
				// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
				break;
		}
	}
	return TRUE;
}

void CSharedFilesCtrl::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult)
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	// Barry - Store sort order in preferences
	// Determine ascending based on whether already sorted on this column

	bool sortAscending = (GetSortItem() != pNMListView->iSubItem) ? true : !GetSortAscending();

	// Ornis 4-way-sorting
	int adder=0;
	if (pNMListView->iSubItem>=5 && pNMListView->iSubItem<=7)
	{
		ASSERT( pNMListView->iSubItem - 5 < ARRSIZE(sortstat) );
		if (!sortAscending)
			sortstat[pNMListView->iSubItem - 5] = !sortstat[pNMListView->iSubItem - 5];
		adder = sortstat[pNMListView->iSubItem-5] ? 0 : 100;
	}
	else if (pNMListView->iSubItem==11)
	{
		ASSERT( 3 < ARRSIZE(sortstat) );
		if (!sortAscending)
			sortstat[3] = !sortstat[3];
		adder = sortstat[3] ? 0 : 100;
	}

	// Sort table
	if (adder==0)	
		SetSortArrow(pNMListView->iSubItem, sortAscending); 
	else
		SetSortArrow(pNMListView->iSubItem, sortAscending ? arrowDoubleUp : arrowDoubleDown);

	UpdateSortHistory(pNMListView->iSubItem + adder + (sortAscending ? 0:20),20);
	SortItems(SortProc, pNMListView->iSubItem + adder + (sortAscending ? 0:20));

	*pResult = 0;
}

int CSharedFilesCtrl::SortProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	// gomez82 >>> SP - [SharedParts] 
	const CSharedItem* item1=(CSharedItem*)lParam1;
	const CSharedItem* item2=(CSharedItem*)lParam2;
	
	int iResult=0;

	if(item1->isFile != false && item2->isFile != false){
	//	if (showParts) return 0; // gomez82 >>> SEa - [SortAltExtension]
		iResult = Compare(item1->KnownFile,item2->KnownFile,lParamSort);
	}
	else if(item1->isFile == false && item2->isFile == false)
	{
		if(item1->KnownFile == item2->KnownFile) 
			iResult = Compare(item1,item2,lParamSort);
		else // different files
			iResult = 0;
	}
	else // compare file and part
	{
		return 0;
	}
	// gomez82 >>> SP END 
	return iResult;
}
	
int CSharedFilesCtrl::Compare(const CKnownFile* item1, const CKnownFile* item2, LPARAM lParamSort) // gomez82 >>> SP - [SharedParts] 
{
	int iResult=0;
	switch(lParamSort){
		case 0: //filename asc
			iResult=CompareLocaleStringNoCase(item1->GetFileName(),item2->GetFileName());
			break;
		case 20: //filename desc
			iResult=CompareLocaleStringNoCase(item2->GetFileName(),item1->GetFileName());
			break;

		case 1: //filesize asc
			iResult=item1->GetFileSize()==item2->GetFileSize()?0:(item1->GetFileSize()>item2->GetFileSize()?1:-1);
			break;

		case 21: //filesize desc
			iResult=item1->GetFileSize()==item2->GetFileSize()?0:(item2->GetFileSize()>item1->GetFileSize()?1:-1);
			break;

		case 2: //filetype asc
			iResult=item1->GetFileTypeDisplayStr().Compare(item2->GetFileTypeDisplayStr());
			break;
		case 22: //filetype desc
			iResult=item2->GetFileTypeDisplayStr().Compare(item1->GetFileTypeDisplayStr());
			break;

		case 3: //prio asc
		case 23: //prio desc
            if(item1->GetPowerShared() == item2->GetPowerShared()) {
			    uint8 p1=item1->GetUpPriority() +1;
			    if(p1==5)
				    p1=0;
			    uint8 p2=item2->GetUpPriority() +1;
			    if(p2==5)
				    p2=0;
			    iResult=p1-p2;
            } else if(item1->GetPowerShared()) {
                // item1 is larger
                iResult = 1;
            } else {
                // item2 is larger
                iResult = -1;
            }

            if(lParamSort == 23) {
                iResult = -iResult;
            }
			break;

		case 4: //fileID asc
			iResult=memcmp(item1->GetFileHash(), item2->GetFileHash(), 16);
			break;
		case 24: //fileID desc
			iResult=memcmp(item2->GetFileHash(), item1->GetFileHash(), 16);
			break;

		case 5: //requests asc
			iResult=item1->statistic.GetRequests() - item2->statistic.GetRequests();
			break;
		case 25: //requests desc
			iResult=item2->statistic.GetRequests() - item1->statistic.GetRequests();
			break;
		
		case 6: //acc requests asc
			iResult=item1->statistic.GetAccepts() - item2->statistic.GetAccepts();
			break;
		case 26: //acc requests desc
			iResult=item2->statistic.GetAccepts() - item1->statistic.GetAccepts();
			break;
		
		case 7: //all transferred asc
			iResult=item1->statistic.GetTransferred()==item2->statistic.GetTransferred()?0:(item1->statistic.GetTransferred()>item2->statistic.GetTransferred()?1:-1);
			break;
		case 27: //all transferred desc
			iResult=item1->statistic.GetTransferred()==item2->statistic.GetTransferred()?0:(item2->statistic.GetTransferred()>item1->statistic.GetTransferred()?1:-1);
			break;

		case 9: //folder asc
			iResult=CompareLocaleStringNoCase(item1->GetPath(),item2->GetPath());
			break;
		case 29: //folder desc
			iResult=CompareLocaleStringNoCase(item2->GetPath(),item1->GetPath());
			break;

		case 10: //complete sources asc
			iResult=CompareUnsigned(item1->m_nCompleteSourcesCount, item2->m_nCompleteSourcesCount);
			break;
		case 30: //complete sources desc
			iResult=CompareUnsigned(item2->m_nCompleteSourcesCount, item1->m_nCompleteSourcesCount);
			break;

		case 11: //ed2k shared asc
			iResult=item1->GetPublishedED2K() - item2->GetPublishedED2K();
			break;
		case 31: //ed2k shared desc
			iResult=item2->GetPublishedED2K() - item1->GetPublishedED2K();
			break;
		// gomez82 >>> CRC - [MorphCRCTag] 
		case 13:
			iResult=item2->IsCRCOk()-item1->IsCRCOk();
			break;
		case 33:
			iResult=item1->IsCRCOk()-item2->IsCRCOk();
		// gomez82 >>> CRC END 
		case 105: //all requests asc
			iResult=CompareUnsigned(item1->statistic.GetAllTimeRequests(), item2->statistic.GetAllTimeRequests());
			break;
		case 125: //all requests desc
			iResult=CompareUnsigned(item2->statistic.GetAllTimeRequests(), item1->statistic.GetAllTimeRequests());
			break;

		case 106: //all acc requests asc
			iResult=CompareUnsigned(item1->statistic.GetAllTimeAccepts(), item2->statistic.GetAllTimeAccepts());
			break;
		case 126: //all acc requests desc
			iResult=CompareUnsigned(item2->statistic.GetAllTimeAccepts(), item1->statistic.GetAllTimeAccepts());
			break;

		case 107: //all transferred asc
			iResult=item1->statistic.GetAllTimeTransferred()==item2->statistic.GetAllTimeTransferred()?0:(item1->statistic.GetAllTimeTransferred()>item2->statistic.GetAllTimeTransferred()?1:-1);
			break;
		case 127: //all transferred desc
			iResult=item1->statistic.GetAllTimeTransferred()==item2->statistic.GetAllTimeTransferred()?0:(item2->statistic.GetAllTimeTransferred()>item1->statistic.GetAllTimeTransferred()?1:-1);
			break;

		case 111:{ //kad shared asc
			uint32 tNow = time(NULL);
			int i1 = (tNow < item1->GetLastPublishTimeKadSrc()) ? 1 : 0;
			int i2 = (tNow < item2->GetLastPublishTimeKadSrc()) ? 1 : 0;
			iResult=i1 - i2;
			break;
		}
		case 131:{ //kad shared desc
			uint32 tNow = time(NULL);
			int i1 = (tNow < item1->GetLastPublishTimeKadSrc()) ? 1 : 0;
			int i2 = (tNow < item2->GetLastPublishTimeKadSrc()) ? 1 : 0;
			iResult=i2 - i1;
			break;
		}
		// gomez82 >>> NSC - [NeoSharedCategories] 
		case 12:
			iResult=CompareLocaleStringNoCase(	(const_cast<CKnownFile*>(item1)->GetCategory()!=0)?thePrefs.GetCategory(const_cast<CKnownFile*>(item1)->GetCategory())->strTitle:GetResString(IDS_ALL),
											(const_cast<CKnownFile*>(item2)->GetCategory()!=0)?thePrefs.GetCategory(const_cast<CKnownFile*>(item2)->GetCategory())->strTitle:GetResString(IDS_ALL) );
			break;
		case 32:
			iResult=-CompareLocaleStringNoCase( (const_cast<CKnownFile*>(item1)->GetCategory()!=0)?thePrefs.GetCategory(const_cast<CKnownFile*>(item1)->GetCategory())->strTitle:GetResString(IDS_ALL),
											 (const_cast<CKnownFile*>(item2)->GetCategory()!=0)?thePrefs.GetCategory(const_cast<CKnownFile*>(item2)->GetCategory())->strTitle:GetResString(IDS_ALL) );
			break;
		// gomez82 >>> NSC END 
		default: 
			iResult=0;
			break;
	}

	return iResult;
}

// gomez82 >>> SP - [SharedParts] 
#define sortcmp(a, b) ((a)==(b)) ? 0 : (((a)<(b))?-1:1)
int CSharedFilesCtrl::Compare(const CSharedItem* item1, const CSharedItem* item2, LPARAM lParamSort)
{
	int iResult=0;
	switch(lParamSort){
		case 0: //filename asc
			iResult=sortcmp(item1->Part, item2->Part);
			break;
		case 20: //filename desc
			iResult=sortcmp(item2->Part, item1->Part);
			break;

		case 1: //filesize asc
			iResult=(!item1->KnownFile->IsPartFile() || ((CPartFile*)item1->KnownFile)->IsComplete(PARTSIZE*item1->Part, PARTSIZE*item1->Part+PARTSIZE-1, true)) - (!item2->KnownFile->IsPartFile() || ((CPartFile*)item2->KnownFile)->IsComplete(PARTSIZE*item2->Part, PARTSIZE*item2->Part+PARTSIZE-1, true));
			break;
		case 21: //filesize desc
			iResult=(!item2->KnownFile->IsPartFile() || ((CPartFile*)item2->KnownFile)->IsComplete(PARTSIZE*item2->Part, PARTSIZE*item2->Part+PARTSIZE-1, true)) - (!item1->KnownFile->IsPartFile() || ((CPartFile*)item1->KnownFile)->IsComplete(PARTSIZE*item1->Part, PARTSIZE*item1->Part+PARTSIZE-1, true));
			break;


		//case 2: //filetype asc
			
		//case 22: //filetype desc

		// gomez82 >>> MCS - [ManualChunkSelection]
		case 3: //prio asc
//			iResult=(item1->KnownFile->IsPartFile() ? ((CPartFile*)item1->KnownFile)->PartPrefs->GetWantedPart(item1->Part) : PR_PART_NORMAL) - (item2->KnownFile->IsPartFile() ? ((CPartFile*)item2->KnownFile)->PartPrefs->GetWantedPart(item2->Part) : PR_PART_NORMAL);
			break;
		case 23: //prio desc
//			iResult=(item2->KnownFile->IsPartFile() ? ((CPartFile*)item2->KnownFile)->PartPrefs->GetWantedPart(item2->Part) : PR_PART_NORMAL) - (item1->KnownFile->IsPartFile() ? ((CPartFile*)item1->KnownFile)->PartPrefs->GetWantedPart(item1->Part) : PR_PART_NORMAL);
			break;
		// gomez82 >>> MCS END

		case 4: //fileID asc
			iResult=memcmp(item1->KnownFile->GetPartHash(item1->Part), item2->KnownFile->GetPartHash(item2->Part), 16);
			break;
		case 24: //fileID desc
			iResult=memcmp(item2->KnownFile->GetPartHash(item2->Part), item1->KnownFile->GetPartHash(item1->Part), 16);
			break;

		//case 5: //requests asc
			
		//case 25: //requests desc
			
		
		//case 6: //acc requests asc
		//	iResult=item1->KnownFile->statistic.GetPartAccepted(item1->Part, true) - item2->KnownFile->statistic.GetPartAccepted(item2->Part, true);
		//	break;
		//case 26: //acc requests desc
		//	iResult=item2->KnownFile->statistic.GetPartAccepted(item2->Part, true) - item1->KnownFile->statistic.GetPartAccepted(item1->Part, true);
		//	break;
		
		case 7: //all transferred asc
//			iResult=item1->KnownFile->statistic.GetPartTrafficSession(item1->Part)==item2->KnownFile->statistic.GetPartTrafficSession(item2->Part)?0:(item1->KnownFile->statistic.GetPartTrafficSession(item1->Part)>item2->KnownFile->statistic.GetPartTrafficSession(item2->Part)?1:-1);
			break;
		case 27: //all transferred desc
//			iResult=item1->KnownFile->statistic.GetPartTrafficSession(item1->Part)==item2->KnownFile->statistic.GetPartTrafficSession(item2->Part)?0:(item2->KnownFile->statistic.GetPartTrafficSession(item2->Part)>item1->KnownFile->statistic.GetPartTrafficSession(item1->Part)?1:-1);
			break;

		//case 9: //folder asc

		//case 29: //folder desc

		case 10: //complete sources asc
//			iResult=CompareUnsigned(item1->KnownFile->GetPartAvailibility(item1->Part), item2->KnownFile->GetPartAvailibility(item2->Part));
			break;
		case 30: //complete sources desc
//			iResult=CompareUnsigned(item2->KnownFile->GetPartAvailibility(item2->Part), item1->KnownFile->GetPartAvailibility(item1->Part));
			break;

		//case 11: //ed2k shared asc
			
		//case 31: //ed2k shared desc
			

		//case 12: //permission asc

		//case 32: //permission desc 



		//case 105: //all requests asc
			
		//case 125: //all requests desc	





		//case 111: //kad shared asc
		//case 131: //kad shared desc


		default: 
			iResult=0;
			break;
	}
	return iResult;
}
// gomez82 >>> SP END 
void CSharedFilesCtrl::OpenFile(const CKnownFile* file)
{
	if(file->m_pCollection)
	{
		CCollectionViewDialog dialog;
		dialog.SetCollection(file->m_pCollection);
		dialog.DoModal();
	}
	else
		ShellOpenFile(file->GetFilePath(), NULL);
}
// gomez82 >>> NTS - [NeoTreeStyle] 
void CSharedFilesCtrl::OnClick(NMHDR* pNMHDR, LRESULT* /*pResult*/)
{
	POINT point;
	::GetCursorPos(&point);
	CPoint p = point; 
    ScreenToClient(&p);

	LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);

	if (p.x<12) 
		ExpandCollapseItem(pNMIA->iItem);

	theApp.emuledlg->sharedfileswnd->ShowSelectedFilesSummary(); // Need for update the status fields
}
// gomez82 >>> NTS END 

void CSharedFilesCtrl::OnNMDblclk(NMHDR* pNMHDR, LRESULT* pResult)
{
	int iSel = GetNextItem(-1, LVIS_SELECTED | LVIS_FOCUSED);
	if (iSel != -1)
	{
		// gomez82 >>> SP - [SharedParts] 
		if(thePrefs.IsDoubleClickEnabled()){
			NMITEMACTIVATE *i=(NMITEMACTIVATE*)pNMHDR;
			ExpandCollapseItem(i->iItem);
		}
		else{
			CKnownFile* file = ((CSharedItem*)GetItemData(iSel))->KnownFile;
		// gomez82 >>> SP END 
			//CKnownFile* file = (CKnownFile*)GetItemData(iSel);
		if (file)
		{
			if (GetKeyState(VK_MENU) & 0x8000)
			{
				CTypedPtrList<CPtrList, CKnownFile*> aFiles;
				aFiles.AddHead(file);
				ShowFileDialog(aFiles);
			}
			else if (!file->IsPartFile())
				OpenFile(file);
		}
		} // gomez82 >>> SP - [SharedParts] 
	}
	*pResult = 0;
}

void CSharedFilesCtrl::CreateMenues()
{
	if (m_PrioMenu) VERIFY( m_PrioMenu.DestroyMenu() );
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	if (m_HideOSMenu) VERIFY( m_HideOSMenu.DestroyMenu() );
	if (m_SelectiveChunkMenu) VERIFY( m_SelectiveChunkMenu.DestroyMenu() );
	//// gomez82 >>> END   - Added by SiRoB, HIDEOS
	//// gomez82 >>> START - Added by SiRoB, SHARE_ONLY_THE_NEED
	if (m_ShareOnlyTheNeedMenu) VERIFY( m_ShareOnlyTheNeedMenu.DestroyMenu() );
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle

	if (m_CRC32Menu) VERIFY( m_CRC32Menu.DestroyMenu() ); // gomez82 >>> CRC - [MorphCRCTag] 
	if (m_CollectionsMenu) VERIFY( m_CollectionsMenu.DestroyMenu() );
	if (m_SharedFilesMenu) VERIFY( m_SharedFilesMenu.DestroyMenu() );

	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	m_HideOSMenu.CreateMenu();
	m_HideOSMenu.AppendMenu(MF_STRING,MP_HIDEOS_DEFAULT, GetResString(IDS_DEFAULT));
	m_HideOSMenu.AppendMenu(MF_STRING,MP_HIDEOS_SET, GetResString(IDS_DISABLED));
	m_SelectiveChunkMenu.CreateMenu();
	m_SelectiveChunkMenu.AppendMenu(MF_STRING,MP_SELECTIVE_CHUNK,	GetResString(IDS_DEFAULT));
	m_SelectiveChunkMenu.AppendMenu(MF_STRING,MP_SELECTIVE_CHUNK_0,	GetResString(IDS_DISABLED));
	m_SelectiveChunkMenu.AppendMenu(MF_STRING,MP_SELECTIVE_CHUNK_1,	GetResString(IDS_ENABLED));

	m_ShareOnlyTheNeedMenu.CreateMenu();
	m_ShareOnlyTheNeedMenu.AppendMenu(MF_STRING,MP_SHAREONLYTHENEED,	GetResString(IDS_DEFAULT));
	m_ShareOnlyTheNeedMenu.AppendMenu(MF_STRING,MP_SHAREONLYTHENEED_0,	GetResString(IDS_DISABLED));
	m_ShareOnlyTheNeedMenu.AppendMenu(MF_STRING,MP_SHAREONLYTHENEED_1,	GetResString(IDS_ENABLED));
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle

	m_PrioMenu.CreateMenu();
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIOVERYLOW,GetResString(IDS_PRIOVERYLOW));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIOLOW,GetResString(IDS_PRIOLOW));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIONORMAL,GetResString(IDS_PRIONORMAL));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIOHIGH, GetResString(IDS_PRIOHIGH));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIOVERYHIGH, GetResString(IDS_PRIORELEASE));

    m_PrioMenu.AppendMenu(MF_STRING,MP_PRIO_POWERSHARE_VERYLOW,GetResString(IDS_POWERSHARE) + _T(" ") + GetResString(IDS_PRIOVERYLOW));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIO_POWERSHARE_LOW,GetResString(IDS_POWERSHARE) + _T(" ") + GetResString(IDS_PRIOLOW));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIO_POWERSHARE_NORMAL,GetResString(IDS_POWERSHARE) + _T(" ") + GetResString(IDS_PRIONORMAL));
	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIO_POWERSHARE_HIGH, GetResString(IDS_POWERSHARE) + _T(" ") + GetResString(IDS_PRIOHIGH));
    m_PrioMenu.AppendMenu(MF_STRING,MP_PRIO_POWERSHARE_VERYHIGH, GetResString(IDS_POWERSHARE) + _T(" ") + GetResString(IDS_PRIORELEASE));

	m_PrioMenu.AppendMenu(MF_STRING,MP_PRIOAUTO, GetResString(IDS_PRIOAUTO));//UAP
	// gomez82 >>> CRC - [MorphCRCTag]
	m_CRC32Menu.CreateMenu();
	m_CRC32Menu.AddMenuTitle(NULL, true);
	m_CRC32Menu.AppendMenu(MF_STRING,MP_CRC32_CALCULATE,GetResString(IDS_X_CRC32_CALCULATE),_T("FILECRC32_CALC"));
	m_CRC32Menu.AppendMenu(MF_STRING,MP_CRC32_RECALCULATE,GetResString(IDS_X_CRC32_RECALCULATE),_T("FILECRC32_RECALC"));
	m_CRC32Menu.AppendMenu(MF_STRING,MP_CRC32_TAG,GetResString(IDS_X_CRC32_TAG),_T("FILECRC32_ADD"));
	m_CRC32Menu.AppendMenu(MF_STRING,MP_CRC32_ABORT,GetResString(IDS_CRC32_ABORT),_T("FILECRC32_ABBORT"));
	// gomez82 >>> CRC END
	m_CollectionsMenu.CreateMenu();
	m_CollectionsMenu.AddMenuTitle(NULL, true);
	m_CollectionsMenu.AppendMenu(MF_STRING,MP_CREATECOLLECTION, GetResString(IDS_CREATECOLLECTION), _T("COLLECTION_ADD"));
	m_CollectionsMenu.AppendMenu(MF_STRING,MP_MODIFYCOLLECTION, GetResString(IDS_MODIFYCOLLECTION), _T("COLLECTION_EDIT"));
	m_CollectionsMenu.AppendMenu(MF_STRING,MP_VIEWCOLLECTION, GetResString(IDS_VIEWCOLLECTION), _T("COLLECTION_VIEW"));
	m_CollectionsMenu.AppendMenu(MF_STRING,MP_SEARCHAUTHOR, GetResString(IDS_SEARCHAUTHORCOLLECTION), _T("COLLECTION_SEARCH"));

	m_SharedFilesMenu.CreatePopupMenu();
	m_SharedFilesMenu.AddMenuTitle(GetResString(IDS_SHAREDFILES), true);

	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_OPEN, GetResString(IDS_OPENFILE), _T("OPENFILE"));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_OPENFOLDER, GetResString(IDS_OPENFOLDER), _T("OPENFOLDER"));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_RENAME, GetResString(IDS_RENAME) + _T("..."), _T("FILERENAME"));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_REMOVE, GetResString(IDS_DELETE), _T("DELETE"));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_UNSHARE_FILE, GetResString(IDS_X_UNSHARE_FILE), _T("UNSHARE")); // gomez82 >>> SSF - [ShareSingleFiles] 
	if (thePrefs.IsExtControlsEnabled())
		m_SharedFilesMenu.AppendMenu(MF_STRING,Irc_SetSendLink,GetResString(IDS_IRC_ADDLINKTOIRC), _T("IRCCLIPBOARD"));

	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR);
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_PrioMenu.m_hMenu, GetResString(IDS_PRIORITY) + _T(" (") + GetResString(IDS_PW_CON_UPLBL) + _T(")"), _T("FILEPRIORITY"));
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR);

	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_CollectionsMenu.m_hMenu, GetResString(IDS_META_COLLECTION), _T("COLLECTION"));
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_CRC32Menu.m_hMenu, GetResString(IDS_X_CRC32), _T("FILECRC32")); // gomez82 >>> CRC - [MorphCRCTag] 
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR); 	

	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_DETAIL, GetResString(IDS_SHOWDETAILS), _T("FILEINFO"));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_CMT, GetResString(IDS_CMT_ADD), _T("FILECOMMENTS"));
	if (thePrefs.GetShowCopyEd2kLinkCmd())
		m_SharedFilesMenu.AppendMenu(MF_STRING,MP_GETED2KLINK, GetResString(IDS_DL_LINK1), _T("ED2KLINK") );
	else
		m_SharedFilesMenu.AppendMenu(MF_STRING,MP_SHOWED2KLINK, GetResString(IDS_DL_SHOWED2KLINK), _T("ED2KLINK") );
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_FIND, GetResString(IDS_FIND), _T("Search"));
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR);
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_HideOSMenu.m_hMenu, GetResString(IDS_HIDEOS), _T("FILEHIDEOS"));
	m_HideOSMenu.AppendMenu(MF_STRING|MF_SEPARATOR);
	m_HideOSMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_SelectiveChunkMenu.m_hMenu, GetResString(IDS_SELECTIVESHARE));

	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_ShareOnlyTheNeedMenu.m_hMenu, GetResString(IDS_SHAREONLYTHENEED), _T("FILESHAREONLYTHENEED"));
	// gomez82 >>> HideOS & SOTN [Slugfiller/ MorphXT] - Stulle
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_SPREADBAR_RESET, GetResString(IDS_SPREAD_RESET), _T("METADATA")); // Spread bars [Slugfiller/MorphXT] - Stulle

#if defined(_DEBUG)
	if (thePrefs.IsExtControlsEnabled()){
		//JOHNTODO: Not for release as we need kad lowID users in the network to see how well this work work. Also, we do not support these links yet.
		m_SharedFilesMenu.AppendMenu(MF_STRING,MP_GETKADSOURCELINK, _T("Copy eD2K Links To Clipboard (Kad)"));
		m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR);
	}
#endif
}

void CSharedFilesCtrl::ShowComments(CKnownFile* file)
{
	if (file)
	{
		CTypedPtrList<CPtrList, CKnownFile*> aFiles;
		aFiles.AddHead(file);
		ShowFileDialog(aFiles, IDD_COMMENT);
	}
}

void CSharedFilesCtrl::OnGetDispInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);

	if (theApp.emuledlg->IsRunning()){
		// Although we have an owner drawn listview control we store the text for the primary item in the listview, to be
		// capable of quick searching those items via the keyboard. Because our listview items may change their contents,
		// we do this via a text callback function. The listview control will send us the LVN_DISPINFO notification if
		// it needs to know the contents of the primary item.
		//
		// But, the listview control sends this notification all the time, even if we do not search for an item. At least
		// this notification is only sent for the visible items and not for all items in the list. Though, because this
		// function is invoked *very* often, no *NOT* put any time consuming code here in.

		if (pDispInfo->item.mask & LVIF_TEXT){
			// gomez82 >>> SP - [SharedParts] 
			const CSharedItem* pItem = reinterpret_cast<CSharedItem*>(pDispInfo->item.lParam);
			const CKnownFile* pFile = pItem->KnownFile;
			// gomez82 >>> SP END 
			//const CKnownFile* pFile = reinterpret_cast<CKnownFile*>(pDispInfo->item.lParam);
			if (pFile != NULL){
				switch (pDispInfo->item.iSubItem){
					case 0:
						if (pDispInfo->item.cchTextMax > 0){
							_tcsncpy(pDispInfo->item.pszText, pFile->GetFileName(), pDispInfo->item.cchTextMax);
							pDispInfo->item.pszText[pDispInfo->item.cchTextMax-1] = _T('\0');
						}
						break;
					default:
						// shouldn't happen
						pDispInfo->item.pszText[0] = _T('\0');
						break;
				}
			}
		}
	}
	*pResult = 0;
}

void CSharedFilesCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (nChar == 'C' && (GetKeyState(VK_CONTROL) & 0x8000))
	{
		// Ctrl+C: Copy listview items to clipboard
		SendMessage(WM_COMMAND, MP_GETED2KLINK);
		return;
	}
	else if (nChar == VK_F5)
		ReloadFileList();

	CMuleListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CSharedFilesCtrl::ShowFileDialog(CTypedPtrList<CPtrList, CKnownFile*>& aFiles, UINT uPshInvokePage)
{
	if (aFiles.GetSize() > 0)
	{

		CSharedFileDetailsSheet dialog(aFiles, uPshInvokePage, this);
		dialog.DoModal();
	}
}

void CSharedFilesCtrl::SetDirectoryFilter(CDirectoryItem* pNewFilter, bool bRefresh){
	if (m_pDirectoryFilter == pNewFilter)
		return;
	m_pDirectoryFilter = pNewFilter;
	if (bRefresh)
		ReloadFileList();
}

void CSharedFilesCtrl::OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);
	if (pGetInfoTip->iSubItem == 0)
	{
		LVHITTESTINFO hti = {0};
		::GetCursorPos(&hti.pt);
		ScreenToClient(&hti.pt);
		if (SubItemHitTest(&hti) == -1 || hti.iItem != pGetInfoTip->iItem || hti.iSubItem != 0){
			// don' show the default label tip for the main item, if the mouse is not over the main item
			if ((pGetInfoTip->dwFlags & LVGIT_UNFOLDED) == 0 && pGetInfoTip->cchTextMax > 0 && pGetInfoTip->pszText[0] != _T('\0'))
				pGetInfoTip->pszText[0] = _T('\0');
			return;
		}

		
		// gomez82 >>> SP - [SharedParts] 
		const CSharedItem* pItem = (CSharedItem*)GetItemData(pGetInfoTip->iItem);
		if(pItem->isFile == false)
			return;
		const CKnownFile* pFile = pItem->KnownFile;
		// gomez82 >>> SP END 
		//const CKnownFile* pFile = (CKnownFile*)GetItemData(pGetInfoTip->iItem);
		if (pFile && pGetInfoTip->pszText && pGetInfoTip->cchTextMax > 0)
		{
			CString strInfo = pFile->GetInfoSummary();
			strInfo += TOOLTIP_AUTOFORMAT_SUFFIX_CH;
			_tcsncpy(pGetInfoTip->pszText, strInfo, pGetInfoTip->cchTextMax);
			pGetInfoTip->pszText[pGetInfoTip->cchTextMax-1] = _T('\0');
		}
	}
	*pResult = 0;
}

// gomez82 >>> SP - [SharedParts] 
void CSharedFilesCtrl::ExpandCollapseItem(int Item)
{
	if (Item == -1)
		return;

	CSharedItem *ItemDataParent=(CSharedItem*)GetItemData(Item);

	if(!ItemDataParent->isFile)
		return;

	CKnownFile *File=ItemDataParent->KnownFile;

	if(ItemDataParent->isOpen==true)
	{
		SetRedraw(false);

		ItemDataParent->isOpen=false;
		for(uint16 Part=0; Part<ItemDataParent->Parts; Part++)
		{
			CSharedItem *ItemData=(CSharedItem*)GetItemData(Item+1);
			if (ItemData->isFile)
				break;
			SetItemData(Item+1, NULL);
			DeleteItem(Item+1);
			if(ItemData) 
				delete ItemData;
		}

		SetRedraw(true);
	}
	else
	{
		if(!(File->GetHashCount() == File->GetED2KPartHashCount()) || File->GetPartCount() == 1)
			return; // we dont have the hashset!
		//if(IsAlternate()) // gomez82 >>> SEa - [SortAltExtension] // only one file at the time
		//	return;

		SetRedraw(false);

		CString	Buffer;
		uint16	Parts=0;
		for(uint16 Part=0; Part<File->GetPartCount(); Part++)
		{
			Parts++;

			CSharedItem	*ItemData=new CSharedItem;
			ItemData->isFile=false;
			ItemData->isOpen=false;
			ItemData->KnownFile=File;
			ItemData->Part=Part;
			ItemData->Parts=0;

			Buffer.Format(_T("%i"), Part);
			InsertItem(LVIF_TEXT|LVIF_PARAM, Item+Parts, Buffer, 0, 0, 0, (LPARAM)ItemData);
		}

		SetRedraw(true);

		ItemDataParent->Parts=Parts;
		if(Parts==0){
			ItemDataParent->isOpen=false;
			//SetAlternate(FALSE); // gomez82 >>> SEa - [SortAltExtension]
		}else{
			ItemDataParent->isOpen=true;
		}
	}


}

BOOL CSharedFilesCtrl::DeleteAllItems()
{
	CSharedItem *ItemData;
	for(int i=GetItemCount(); i>0; i--){
		ItemData=(CSharedItem *)GetItemData(i-1);
		SetItemData(i-1, NULL);
		if(ItemData){

			delete ItemData;
		}
	}
	return CListCtrl::DeleteAllItems();
}

CSharedFilesListCtrlItemWalk::CSharedFilesListCtrlItemWalk(CSharedFilesCtrl* pListCtrl)
	: CListCtrlItemWalk(pListCtrl)
{
	m_pSharedFilesListCtrl = pListCtrl;
	m_iParts = false;
}

CObject* CSharedFilesListCtrlItemWalk::GetPrevSelectableItem()
{
	ASSERT( m_pSharedFilesListCtrl != NULL );
	if (m_pSharedFilesListCtrl == NULL)
		return NULL;

	int iItemCount = m_pSharedFilesListCtrl->GetItemCount();
	if (iItemCount >= 2)
	{
		POSITION pos = m_pSharedFilesListCtrl->GetFirstSelectedItemPosition();
		if (pos)
		{
			int iItem = m_pSharedFilesListCtrl->GetNextSelectedItem(pos);
			int iCurSelItem = iItem;
			while (iItem-1 >= 0)
			{
				iItem--;

				const CSharedItem* SharedItem = (CSharedItem*)m_pSharedFilesListCtrl->GetItemData(iItem);
				if (SharedItem->isFile == !m_iParts)
				{
					m_pSharedFilesListCtrl->SetItemState(iCurSelItem, 0, LVIS_SELECTED | LVIS_FOCUSED);
					m_pSharedFilesListCtrl->SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
					m_pSharedFilesListCtrl->SetSelectionMark(iItem);
					m_pSharedFilesListCtrl->EnsureVisible(iItem, FALSE);
					return STATIC_DOWNCAST(CObject, (CObject*)SharedItem->KnownFile);
				}
			}
		}
	}
	return NULL;
}

CObject* CSharedFilesListCtrlItemWalk::GetNextSelectableItem()
{
	ASSERT( m_pSharedFilesListCtrl != NULL );
	if (m_pSharedFilesListCtrl == NULL)
		return NULL;

	int iItemCount =m_pSharedFilesListCtrl->GetItemCount();
	if (iItemCount >= 2)
	{
		POSITION pos = m_pSharedFilesListCtrl->GetFirstSelectedItemPosition();
		if (pos)
		{
			int iItem = m_pSharedFilesListCtrl->GetNextSelectedItem(pos);
			int iCurSelItem = iItem;
			while (iItem+1 < iItemCount)
			{
				iItem++;

				const CSharedItem* SharedItem = (CSharedItem*)m_pSharedFilesListCtrl->GetItemData(iItem);
				if (SharedItem->isFile == !m_iParts)
				{
					m_pSharedFilesListCtrl->SetItemState(iCurSelItem, 0, LVIS_SELECTED | LVIS_FOCUSED);
					m_pSharedFilesListCtrl->SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
					m_pSharedFilesListCtrl->SetSelectionMark(iItem);
					m_pSharedFilesListCtrl->EnsureVisible(iItem, FALSE);
					return STATIC_DOWNCAST(CObject, (CObject*)SharedItem->KnownFile);
				}
			}
		}
	}
	return NULL;
}
// gomez82 >>> SP END 

// gomez82 >>> SDD - [ShareDargAndDrop] 
CLIPFORMAT g_uCustomClipbrdFormat = (CLIPFORMAT)RegisterClipboardFormat ( _T("MULE_3BCFE9D1_6D61_4cb6_9D0B_3BB3F643CA82") );
bool g_bNT = (0 == (GetVersion() & 0x80000000) );
void CSharedFilesCtrl::OnBegindragFilelist(NMHDR* /*pNMHDR*/, LRESULT* pResult)
{
	COleDataSource datasrc;
	HGLOBAL        hgDrop;
	DROPFILES*     pDrop;
	CStringList    lsDraggedFiles;
	POSITION       pos;
	CString        sFile;
	UINT           uBuffSize = 0;
	TCHAR*         pszBuff;
	FORMATETC      etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

	*pResult = 0;   // return value ignored

	// For every selected item in the list, put the filename into lsDraggedFiles.

	pos = GetFirstSelectedItemPosition();
	while (pos)
	{
		// gomez82 >>> SP - [SharedParts]
		const CSharedItem* pItem = (CSharedItem*)GetItemData(GetNextSelectedItem(pos));

		if(!pItem->isFile)
			continue;

		const CKnownFile* pFile = pItem->KnownFile;
		// gomez82 >>> SP END

		if(pFile->IsPartFile() || pFile->GetPath().IsEmpty())
			continue;

		// get the file path
		sFile.Format(_T("%s\\%s"),pFile->GetPath(),pFile->GetFileName());

		lsDraggedFiles.AddTail ( sFile );

		// Calculate the # of chars required to hold this string.

		uBuffSize += lstrlen ( sFile ) + 1;
	}

	// Add 1 extra for the final null char, and the size of the DROPFILES struct.

	uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);

	// Allocate memory from the heap for the DROPFILES struct.

	hgDrop = GlobalAlloc ( GHND | GMEM_SHARE, uBuffSize );

	if ( NULL == hgDrop )
		return;

	pDrop = (DROPFILES*) GlobalLock ( hgDrop );

	if ( NULL == pDrop )
	{
		GlobalFree ( hgDrop );
		return;
	}

	// Fill in the DROPFILES struct.

	pDrop->pFiles = sizeof(DROPFILES);

#ifdef _UNICODE
	// If we're compiling for Unicode, set the Unicode flag in the struct to
	// indicate it contains Unicode strings.
	pDrop->fWide = TRUE;
#endif;

	// Copy all the filenames into memory after the end of the DROPFILES struct.

	pos = lsDraggedFiles.GetHeadPosition();
	pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));

	while ( NULL != pos )
	{
		lstrcpy ( pszBuff, (LPCTSTR) lsDraggedFiles.GetNext ( pos ) );
		pszBuff = 1 + _tcschr ( pszBuff, '\0' );
	}

	GlobalUnlock ( hgDrop );

	// Put the data in the data source.

	datasrc.CacheGlobalData ( CF_HDROP, hgDrop, &etc );

	// Add in our own custom data, so we know that the drag originated from our 
	// window.  CMyDropTarget::DragEnter() checks for this custom format, and
	// doesn't allow the drop if it's present.  This is how we prevent the user
	// from dragging and then dropping in our own window.
	// The data will just be a dummy bool.
	HGLOBAL hgBool;

	hgBool = GlobalAlloc ( GHND | GMEM_SHARE, sizeof(bool) );

	if ( NULL == hgBool )
	{
		GlobalFree ( hgDrop );
		return;
	}

	// Put the data in the data source.

	etc.cfFormat = g_uCustomClipbrdFormat;

	datasrc.CacheGlobalData ( g_uCustomClipbrdFormat, hgBool, &etc );


	// Start the drag 'n' drop!

	DROPEFFECT dwEffect = datasrc.DoDragDrop ( DROPEFFECT_COPY | DROPEFFECT_MOVE );

	// If the DnD completed OK, we remove all of the dragged items from our
	// list.

	
	switch ( dwEffect )
	{
	case DROPEFFECT_MOVE:
		{
			theApp.emuledlg->sharedfileswnd->Reload();
		}
	case DROPEFFECT_COPY:
		{	
			// Note: Don't call GlobalFree() because the data will be freed by the drop target.
		}
		break;

	case DROPEFFECT_NONE:
		{
			// This needs special handling, because on NT, DROPEFFECT_NONE
			// is returned for move operations, instead of DROPEFFECT_MOVE.
			// See Q182219 for the details.
			// So if we're on NT, we check each selected item, and if the
			// file no longer exists, it was moved successfully and we can
			// remove it from the list.

			if ( g_bNT )
			{
				bool bDeletedAnything = false;

				pos = lsDraggedFiles.GetHeadPosition();
				while ( NULL != pos )
				{
					
					if ( GetFileAttributes ( lsDraggedFiles.GetNext ( pos ) ) == INVALID_FILE_ATTRIBUTES
					 && GetLastError() == ERROR_FILE_NOT_FOUND )
					{
						// We couldn't read the file's attributes, and GetLastError()
						// says the file doesn't exist, so remove the corresponding 
						// item from the list.

						bDeletedAnything = true;
						break;
					}
				}

				if ( bDeletedAnything )
				{
					theApp.emuledlg->sharedfileswnd->Reload();

					// Note: Don't call GlobalFree() because the data belongs to 
					// the caller.
				}
				else
				{
					// The DnD operation wasn't accepted, or was canceled, so we 
					// should call GlobalFree() to clean up.

					GlobalFree ( hgDrop );
					GlobalFree ( hgBool );
				}
			}   // end if (NT)
			else
			{
				// We're on 9x, and a return of DROPEFFECT_NONE always means
				// that the DnD operation was aborted.  We need to free the
				// allocated memory.

				GlobalFree ( hgDrop );
				GlobalFree ( hgBool );
			}
		}
		break;  // end case DROPEFFECT_NONE
	}   // end switch
}

/*ON_WM_DROPFILES()
void CSharedFilesCtrl::OnDropFiles(HDROP hdrop) 
{
	TCHAR       szNextFile [MAX_PATH];
    UINT		uNumFiles = DragQueryFile ( hdrop, (UINT)-1, NULL, 0 ); // Get the # of files being dropped.
    for ( UINT uFile = 0; uFile < uNumFiles; uFile++ )
    {
        if ( DragQueryFile ( hdrop, uFile, szNextFile, MAX_PATH ) > 0 ) // Get the next filename from the HDROP info.
        {
			TRACE(_T("\n\n%s\n\n"),CStringA(szNextFile));
            
        } // end if
    } // end for
}
*/
// gomez82 >>> SDD END 

// gomez82 >>> CRC - [MorphCRCTag] 
// File will be renamed in this method at the time it can be renamed.
// Might be that the CRC had to be calculated before so the thread will inform
// this window when the CRC is ok and the file can be renamed...
afx_msg LRESULT CSharedFilesCtrl::OnCRC32RenameFile	(WPARAM /*wParam*/, LPARAM lParam) {
	// Get the worker thread
	CCRC32RenameWorker* worker = (CCRC32RenameWorker*) lParam;
	// In this case the worker thread is a helper thread for this routine !

	// We are in the "main" thread, so we can be sure that the filelist is not
	// deleted while we access it - so we try to get a pointer to the desired file
	// directly without worker->ValidateKnownFile !
	// This of course avoids possible deadlocks because we don't lock the list;
	// and we don't need to do an worker->UnlockSharedFilesList...
	CKnownFile* f = theApp.sharedfiles->GetFileByID (worker->GetFileHashToProcess ());
	if (f==NULL) {
		// File doesn't exist in the list; deleted and reloaded the shared files list in
		// the meantime ?
		// Let's hope the creator of this Worker thread has set the filename so we can
		// display it...
		if (worker->GetFilePath () == "") {
			AddLogLine(false,GetResString(IDS_X_CRC_TAGING_WRN1));
		} else {
			AddLogLine(false,GetResString(IDS_X_CRC_TAGING_WRN2),
				worker->GetFilePath ());
		}
		return 0;         
	}
	if (f->IsPartFile () && !worker->m_DontAddCRCAndSuffix) {     
		// We can't add a CRC suffix to files which are not complete
		AddLogLine(false,GetResString(IDS_X_CRC_TAGING_PARTFILE),
						   f->GetFileName ());
		return 0;
	}
	if (!worker->m_DontAddCRCAndSuffix && !f->IsCRC32Calculated ()) {
		// The CRC must have been calculate, otherwise we can't add it.
		// Normally this mesage is not shown because if the CRC is not calculated
		// the main thread creates a worker thread before to calculate it...
		AddLogLine(false,GetResString(IDS_X_CRC_TAGING_MISSING),
						   f->GetFileName ());
		return 0;
	}

	// Declare the variables we'll need
	CString p3,p4;
	CString NewFn;

	CString buffer;
	buffer.Format(_T("%02X%02X%02X%02X"),	(int) f->GetCalculatedCRC32() [3],
											(int) f->GetCalculatedCRC32() [2],
											(int) f->GetCalculatedCRC32() [1],
											(int) f->GetCalculatedCRC32() [0]);

	// Split the old filename to name and extension
	CString fn = f->GetFileName ();
	// test if the file name already contained the CRC tag
	CString fnup = fn;
	fnup.MakeUpper();
	if( f->IsCRC32Calculated() && 
		(fnup.Find(buffer) != -1) &&
		(!worker->m_CRC32ForceAdding) ){
		// Ok, the filename already contains the CRC. Normally we won't rename it, except for
		// we have to make sure it's uppercase
		if ((!worker->m_CRC32ForceUppercase) || (fn.Find(buffer) != -1)) {
			AddLogLine(false,GetResString(IDS_X_CRC_TAGING_ALREADY_TAGED), fn);
			return 0;
		} else {
			// This file contains a valid CRC, but not in uppercase - replace it!
			int i=fnup.Find(buffer);
			NewFn = fn;
			p3 = f->GetCalculatedCRC32();
			NewFn.Delete (i,p3.GetLength ());
			NewFn.Insert (i,p3);
		}
	} else {
		// We have to add the CRC32/Releaser tag to the filename.
		_tsplitpath (fn,NULL,NULL,p3.GetBuffer (MAX_PATH),p4.GetBuffer (MAX_PATH));
		p3.ReleaseBuffer();
		p4.ReleaseBuffer();

		// Create the new filename
		NewFn = p3;
		NewFn = NewFn + worker->m_FilenamePrefix;
		if (!worker->m_DontAddCRCAndSuffix) {
			NewFn = NewFn + buffer + worker->m_FilenameSuffix;
		}
		NewFn = NewFn + p4;
	}

	AddLogLine(false,GetResString(IDS_X_CRC_TAGING_RENAME),fn,NewFn);

	// Add the path of the old filename to the new one
	CString NewPath; 
	PathCombine(NewPath.GetBuffer(MAX_PATH), f->GetPath (), NewFn);
	NewPath.ReleaseBuffer();

	bool bPartFile = f->IsPartFile();
	bool bShareFile = theApp.sharedfiles->IsFilePtrInList(f); // gomez82 >>> AKF - [AllKnownFiles]
	// Try to rename
	if (!bPartFile && bShareFile && (_trename(f->GetFilePath (), NewPath) != 0)) { // gomez82 >>> AKF - [AllKnownFiles]
		AddLogLine(false,GetResString(IDS_X_CRC_TAGING_RENAME_ERROR),fn,_tcserror(errno));
	} else {
		if (!bPartFile) {
			// Use the "Format"-Syntax of AddLogLine here instead of
			// CString.Format+AddLogLine, because if "%"-characters are
			// in the string they would be misinterpreted as control sequences!
			AddLogLine(false,_T("Successfully renamed file '%s' to '%s'"), f->GetFileName(), NewPath);

			f->SetFileName(NewFn);
			if(bShareFile) // gomez82 >>> AKF - [AllKnownFiles]
				f->SetFilePath(NewPath);

			UpdateFile (f);
		} else {
			// Use the "Format"-Syntax of AddLogLine here instead of
			// CString.Format+AddLogLine, because if "%"-characters are
			// in the string they would be misinterpreted as control sequences!
			AddLogLine(false,_T("Successfully renamed .part file '%s' to '%s'"), f->GetFileName(), NewFn);

			f->SetFileName(NewFn, true); 
			((CPartFile*) f)->UpdateDisplayedInfo();
			((CPartFile*) f)->SavePartFile(); 
			UpdateFile(f);
		}
	}
	
	return 0;
}

// Update the file which CRC was just calculated.
// The LPARAM parameter is a pointer to the hash of the file to be updated.
LRESULT CSharedFilesCtrl::OnCRC32UpdateFile	(WPARAM /*wParam*/, LPARAM lParam) {
	uchar* filehash = (uchar*) lParam;
	// We are in the "main" thread, so we can be sure that the filelist is not
	// deleted while we access it - so we try to get a pointer to the desired file
	// directly without worker->ValidateKnownFile !
	// This of course avoids possible deadlocks because we don't lock the list;
	// and we don't need to do an worker->UnlockSharedFilesList...
	CKnownFile* file = theApp.sharedfiles->GetFileByID (filehash);
	if (file != NULL)		// Update the file if it exists
		UpdateFile (file);
	return 0;
}
// gomez82 >>> CRC END 
