//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


// SharedFilesCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "emule.h"
#include "SharedFilesCtrl.h"
#include "otherfunctions.h"
#include "CommentDialog.h"

// CSharedFilesCtrl

IMPLEMENT_DYNAMIC(CSharedFilesCtrl, CMuleListCtrl)
CSharedFilesCtrl::CSharedFilesCtrl() {
   sflist = 0;                // i_a 
   memset(&asc_sort, 0, sizeof(asc_sort));   // i_a 
   memset(&sortstat, 0, sizeof(sortstat));  // i_a 
}

CSharedFilesCtrl::~CSharedFilesCtrl(){
}

void CSharedFilesCtrl::Init(){
	SetExtendedStyle(LVS_EX_FULLROWSELECT);
	ModifyStyle(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_PERMISSION),LVCFMT_LEFT,100,4);
	InsertColumn(5,GetResString(IDS_FILEID),LVCFMT_LEFT,220,5);
	InsertColumn(6,GetResString(IDS_SF_REQUESTS),LVCFMT_LEFT,100,6);
	InsertColumn(7,GetResString(IDS_SF_ACCEPTS),LVCFMT_LEFT,100,7);
	InsertColumn(8,GetResString(IDS_SF_TRANSFERRED),LVCFMT_LEFT,120,8);

	m_SharedFilesMenu.CreatePopupMenu();
	m_SharedFilesMenu.AddMenuTitle(GetResString(IDS_SHAREDFILES));
	
	// add priority switcher
	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_PRIOAUTO, GetResString(IDS_PRIOAUTO));//UAP

	// add permission switcher
	m_PermMenu.CreateMenu();
	m_PermMenu.AppendMenu(MF_STRING,MP_PERMNONE,	GetResString(IDS_FSTATUS_LOCKED));
	m_PermMenu.AppendMenu(MF_STRING,MP_PERMFRIENDS,	GetResString(IDS_FSTATUS_FRIENDSONLY));
	m_PermMenu.AppendMenu(MF_STRING,MP_PERMALL,		GetResString(IDS_FSTATUS_PUBLIC));


	// todo enable when it works
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_PrioMenu.m_hMenu, GetResString(IDS_PRIORITY) );
	//m_SharedFilesMenu.AppendMenu(MF_STRING|MF_POPUP,(UINT_PTR)m_PermMenu.m_hMenu, (LPCTSTR)"Permissions");
	m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR);
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_OPEN, GetResString(IDS_OPENFILE));
	   //***Comments 11/27/03**// 
   m_SharedFilesMenu.AppendMenu(MF_STRING,MP_CMT, GetResString(IDS_CMT_ADD)); 
   m_SharedFilesMenu.AppendMenu(MF_STRING|MF_SEPARATOR); 
   //****end  comments***//
	m_SharedFilesMenu.AppendMenu(MF_STRING, MP_JIGLE_FAKECHECK, IDS_JIGLE_FAKECHECK); // Added by Tarod [deltaHF]
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_GETED2KLINK, GetResString(IDS_DL_LINK1));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_GETHTMLED2KLINK, GetResString(IDS_DL_LINK2));
	m_SharedFilesMenu.AppendMenu(MF_STRING,MP_GETSOURCEED2KLINK, GetResString(IDS_CREATESOURCELINK));
	
//	m_SharedFilesMenu.AppendMenu(MF_STRING,Irc_SetSendLink,GetResString(IDS_IRC_ADDLINKTOIRC)); 
	//This menu option is is for testing..

	LoadSettings(CPreferences::tableShared);

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

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

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

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

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

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

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

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

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

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

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

void CSharedFilesCtrl::ShowFileList(CSharedFileList* in_sflist){
	DeleteAllItems();
	sflist = in_sflist;
	CCKey bufKey;
	CKnownFile* cur_file;
	for (POSITION pos = sflist->m_Files_map.GetStartPosition();pos != 0;){
		sflist->m_Files_map.GetNextAssoc(pos,bufKey,cur_file);
		ShowFile(cur_file);
	}	
}

void CSharedFilesCtrl::UpdateFile(CKnownFile* file,uint32 itemnr){
	char buffer[50];
	char buffer2[50];
	char buffer3[50];

	CastItoXBytes(file->GetFileSize(),buffer);
	SetItemText(itemnr,1,buffer);
	SetItemText(itemnr,2,GetFiletypeByName(file->GetFileName()));  // added by InterCeptor (show filetype) 11.11.02
	//UAP
	if ((file->IsAutoPrioritized())&&(theApp.glob_prefs->IsUAPEnabled()))
	{
		switch (file->GetPriority()) {
			case PR_NORMAL : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOAUTONORMAL ));
				break; }
			case PR_HIGH : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOAUTOHIGH ));
				break; }
			case PR_VERYHIGH : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOAUTORELEASE ));
				break; }
		}
	} else {
	//endUAP
		switch (file->GetPriority()) {
			case PR_VERYLOW : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOVERYLOW ));
				break; }
			case PR_LOW : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOLOW ));
				break; }
			case PR_NORMAL : {
				SetItemText(itemnr,3,GetResString(IDS_PRIONORMAL ));
				break; }
			case PR_HIGH : {
				SetItemText(itemnr,3,GetResString(IDS_PRIOHIGH ));
				break; }
			case PR_VERYHIGH : {
				SetItemText(itemnr,3,GetResString(IDS_PRIORELEASE ));
				break; }
		}
	}
	/*if (file->GetPermissions() == PERM_NOONE)
		SetItemText(itemnr,4,"Hidden");
	else if (file->GetPermissions() == PERM_FRIENDS)
		SetItemText(itemnr,4,"Friends Only");
	else
		SetItemText(itemnr,4,"Public Shared");*/
	SetItemText(itemnr,4,GetResString(IDS_FSTATUS_PUBLIC));
	
	// Added by Tarod -yes, there is a fucking standard function to do it, man!
	SetItemText(itemnr, 5, EncodeBase16(file->GetFileHash(), 16));

	sprintf(buffer,"%u (%u)",file->statistic.GetRequests(),file->statistic.GetAllTimeRequests());SetItemText(itemnr,6,buffer);
	sprintf(buffer,"%u (%u)",file->statistic.GetAccepts(),file->statistic.GetAllTimeAccepts());SetItemText(itemnr,7,buffer);
	
	CastItoXBytes(file->statistic.GetTransfered(),buffer);
	CastItoXBytes(file->statistic.GetAllTimeTransfered(),buffer2);
	sprintf(buffer3,"%s (%s)",buffer,buffer2 );SetItemText(itemnr,8,buffer3);

}

void CSharedFilesCtrl::ShowFile(CKnownFile* file){
	ShowFile(file,GetItemCount());
}

void CSharedFilesCtrl::ShowFile(CKnownFile* file,uint32 itemnr){
	itemnr = InsertItem(LVIF_TEXT|LVIF_PARAM,itemnr,file->GetFileName(),0,0,0,(LPARAM)file);
	UpdateFile(file,itemnr);
}

void CSharedFilesCtrl::RemoveFile(CKnownFile *toRemove) {
	LVFINDINFO info;
	info.flags = LVFI_PARAM;
	info.lParam = (LPARAM)toRemove;
	int nItem = FindItem(&info);
	if(nItem != -1)
		DeleteItem(nItem);
}

BEGIN_MESSAGE_MAP(CSharedFilesCtrl, CMuleListCtrl)
	ON_WM_CONTEXTMENU()
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
END_MESSAGE_MAP()



// CSharedFilesCtrl message handlers
void CSharedFilesCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
	int iSel = GetSelectionMark();
	if (iSel != (-1)) {
		CKnownFile* file = (CKnownFile*)GetItemData(iSel);
		m_PrioMenu.EnableMenuItem(MP_PRIOAUTO,((theApp.glob_prefs->IsUAPEnabled()) && (file->IsPartFile())) ? MF_ENABLED:MF_GRAYED); //Hunter
	}else
		m_PrioMenu.EnableMenuItem(MP_PRIOAUTO,(theApp.glob_prefs->IsUAPEnabled()) ? MF_ENABLED:MF_GRAYED); //Hunter
	m_SharedFilesMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x,point.y,this);
}



BOOL CSharedFilesCtrl::OnCommand(WPARAM wParam, LPARAM lParam)
{
	int iSel = GetSelectionMark();
	if (iSel != (-1)){
		CKnownFile* file = (CKnownFile*)GetItemData(iSel);
		switch (wParam){
			case Irc_SetSendLink:
				{
					theApp.emuledlg->ircwnd.SetSendFileString(theApp.CreateED2kLink(file));
					break;
				}
			case MP_GETED2KLINK:
				{
					theApp.CopyTextToClipboard(theApp.CreateED2kLink(file));
					break;
				}
			case MP_GETHTMLED2KLINK:
				{
					theApp.CopyTextToClipboard(theApp.CreateHTMLED2kLink(file));
					break;
				}
			case MP_GETSOURCEED2KLINK:
				{
					CString strLink = theApp.CreateED2kSourceLink(file);
					if (!strLink.IsEmpty())
						theApp.CopyTextToClipboard(strLink);
					break;
				}
			case MP_OPEN:
				{
					char* buffer = new char[250];
					sprintf(buffer,"%s\\%s",file->GetPath(),file->GetFileName());
					theApp.emuledlg->AddLogLine( false, "%s\\%s",file->GetPath(),file->GetFileName());
					ShellOpenFile(buffer);
					delete buffer;
					break; 

				}
			//For Comments 
			case MP_CMT: 
            { 
               CCommentDialog dialog(file); 
               dialog.DoModal(); 
               break; 

            } 
            //*END Comments*//
			case MP_JIGLE_FAKECHECK: {
				theApp.Action(file, NULL, NULL);
				break;
			}
			case MP_PRIOVERYLOW:
			case MP_PRIOLOW:
			case MP_PRIONORMAL:
			case MP_PRIOHIGH:
			case MP_PRIOVERYHIGH:
			case MP_PRIOAUTO:
				{
					POSITION pos = this->GetFirstSelectedItemPosition();
					bool no_partfile_selected = false;
					while( pos != NULL )
					{
						int iSel=this->GetNextSelectedItem(pos);
						file = (CKnownFile*)this->GetItemData(iSel);
						file->SetAutoPriority(false); //UAP
						switch (wParam) {
							case MP_PRIOVERYLOW:
								{	file->SetPriority(PR_VERYLOW);SetItemText(iSel,3,GetResString(IDS_PRIOVERYLOW ));break;	}
							case MP_PRIOLOW:
								{	file->SetPriority(PR_LOW);SetItemText(iSel,3,GetResString(IDS_PRIOLOW ));break;	}
							case MP_PRIONORMAL:
								{	file->SetPriority(PR_NORMAL);SetItemText(iSel,3,GetResString(IDS_PRIONORMAL ));break;	}
							case MP_PRIOHIGH:
								{	file->SetPriority(PR_HIGH);SetItemText(iSel,3,GetResString(IDS_PRIOHIGH ));break;	}
							case MP_PRIOVERYHIGH:
								{	file->SetPriority(PR_VERYHIGH);SetItemText(iSel,3,GetResString(IDS_PRIORELEASE ));break;	}//Hunter
							case MP_PRIOAUTO:
								{
									if (file->IsPartFile()) {
										file->SetAutoPriority(true) ;
										file->UpdateUploadAutoPriority() ;
										if (file->GetPriority() == PR_VERYHIGH)
											SetItemText(iSel,3,GetResString(IDS_PRIOAUTORELEASE));
										else if (file->GetPriority() == PR_HIGH)
											SetItemText(iSel,3,GetResString(IDS_PRIOAUTOHIGH));
										else if (file->GetPriority() == PR_NORMAL)
											SetItemText(iSel,3,GetResString(IDS_PRIOAUTONORMAL));
									}
									else no_partfile_selected = true;
								}
						}

					}
					break;
				}
			case MP_PERMNONE:
				{
					if (((CPartFile*)file)->IsPartFile())
						AfxMessageBox(GetResString(IDS_ERR_NOPRIMCHANGE));
					else
					{	
						file->SetPermissions(PERM_NOONE);
						SetItemText(iSel,4,GetResString(IDS_HIDDEN));
					}
					break;
				}
			case MP_PERMFRIENDS:
				{
					if (((CPartFile*)file)->IsPartFile())
						AfxMessageBox(GetResString(IDS_ERR_NOPRIMCHANGE));
					else
					{	
						file->SetPermissions(PERM_FRIENDS);
						SetItemText(iSel,4,GetResString(IDS_FSTATUS_FRIENDSONLY ));	
					}
					break;
				}
			case MP_PERMALL:
				{	file->SetPermissions(PERM_ALL);SetItemText(iSel,4,GetResString(IDS_FSTATUS_PUBLIC));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
	int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableShared);
	bool m_oldSortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableShared);
	bool sortAscending = (sortItem != pNMListView->iSubItem) ? true : !m_oldSortAscending;

	// Item is column clicked
	sortItem = pNMListView->iSubItem;

	// Save new preferences
	theApp.glob_prefs->SetColumnSortItem(CPreferences::tableShared, sortItem);
	theApp.glob_prefs->SetColumnSortAscending(CPreferences::tableShared, sortAscending);

	// Ornis 4-way-sorting
	int adder=0;
	if (pNMListView->iSubItem>5 && pNMListView->iSubItem<9) {
		if (!sortAscending) sortstat[pNMListView->iSubItem-6]=!sortstat[pNMListView->iSubItem-6];
		adder=sortstat[pNMListView->iSubItem-6] ? 0:100;
	}

	// Sort table
	if (adder==0)	
		SetSortArrow(sortItem, sortAscending); 
	else
		SetSortArrow(sortItem, sortAscending ? arrowDoubleUp : arrowDoubleDown);
	SortItems(SortProc, sortItem + adder + (sortAscending ? 0:10));

	*pResult = 0;
}

int CSharedFilesCtrl::SortProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort){
	CKnownFile* item1 = (CKnownFile*)lParam1;
	CKnownFile* item2 = (CKnownFile*)lParam2;	
	switch(lParamSort){
		case 0: //filename asc
			return strcmpi(item1->GetFileName(),item2->GetFileName());
		case 10: //filename desc
			return strcmpi(item2->GetFileName(),item1->GetFileName());

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

		case 11: //filesize desc
			return item1->GetFileSize()==item2->GetFileSize()?0:(item2->GetFileSize()>item1->GetFileSize()?1:-1);


		case 2: //filetype asc
			return strcmpi( GetFiletypeByName(item1->GetFileName()),GetFiletypeByName( item2->GetFileName()) );
		case 12: //filetype desc
			return strcmpi( GetFiletypeByName(item2->GetFileName()),GetFiletypeByName( item1->GetFileName()) );

		case 3: //prio asc
			if(item1->GetPriority() == PR_VERYLOW )
				return 1;
			else if (item2->GetPriority() == PR_VERYLOW)
				return 0;
			else
				return item2->GetPriority()-item1->GetPriority();
		case 13: //prio desc
			if(item1->GetPriority() == PR_VERYLOW )
				return 0;
			else if (item2->GetPriority() == PR_VERYLOW)
				return 1;
			else
				return item1->GetPriority()-item2->GetPriority();

		case 4: //permission asc
			return item2->GetPermissions()-item1->GetPermissions();
		case 14: //permission desc
			return item1->GetPermissions()-item2->GetPermissions();

		case 5: //fileID asc
			return strcmpi((CString)item1->GetFileHash(),(CString)item2->GetFileHash());
		case 15: //fileID desc
			return strcmpi((CString)item2->GetFileHash(),(CString)item1->GetFileHash());

		case 6: //requests asc
			return item1->statistic.GetRequests() - item2->statistic.GetRequests();
		case 16: //requests desc
			return item2->statistic.GetRequests() - item1->statistic.GetRequests();
		case 7: //acc requests asc
			return item1->statistic.GetAccepts() - item2->statistic.GetAccepts();
		case 17: //acc requests desc
			return item2->statistic.GetAccepts() - item1->statistic.GetAccepts();
		case 8: //all transferred asc
			return item1->statistic.GetTransfered()==item2->statistic.GetTransfered()?0:(item1->statistic.GetTransfered()>item2->statistic.GetTransfered()?1:-1);
		case 18: //all transferred desc
			return item1->statistic.GetTransfered()==item2->statistic.GetTransfered()?0:(item2->statistic.GetTransfered()>item1->statistic.GetTransfered()?1:-1);


		case 106: //all requests asc
			return item1->statistic.GetAllTimeRequests() - item2->statistic.GetAllTimeRequests();
		case 116: //all requests desc
			return item2->statistic.GetAllTimeRequests() - item1->statistic.GetAllTimeRequests();
		case 107: //all acc requests asc
			return item1->statistic.GetAllTimeAccepts() - item2->statistic.GetAllTimeAccepts();
		case 117: //all acc requests desc
			return item2->statistic.GetAllTimeAccepts() - item1->statistic.GetAllTimeAccepts();
		case 108: //all transferred asc
			return item1->statistic.GetAllTimeTransfered()==item2->statistic.GetAllTimeTransfered()?0:(item1->statistic.GetAllTimeTransfered()>item2->statistic.GetAllTimeTransfered()?1:-1);
		case 118: //all transferred desc
			return item1->statistic.GetAllTimeTransfered()==item2->statistic.GetAllTimeTransfered()?0:(item2->statistic.GetAllTimeTransfered()>item1->statistic.GetAllTimeTransfered()?1:-1);

		default: 
			return 0;
	}
}

void CSharedFilesCtrl::UpdateItem(CKnownFile* toupdate){
	LVFINDINFO find;
	find.flags = LVFI_PARAM;
	find.lParam = (LPARAM)toupdate;
	sint16 result = FindItem(&find);
	if (result != -1) {
		UpdateFile(toupdate,result);
		Update(result) ;   // Added by Tarod to real time refresh - DonGato - 11/11/2002
		theApp.emuledlg->sharedfileswnd.Check4StatUpdate(toupdate);
	}
}