// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-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.

// ServerListCtrl.cpp : implementation file

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "ServerListCtrl.h"
#	include "DownloadQueue.h"
#	include "muuli_wdr.h"
#include "opcodes.h"                        // MP_PRIOLOW
#	include "otherfunctions.h"
#include "PartFile.h"                       // Needed for SRV_PR_HIGH - audited 5 Nov 2004
#include "Preferences.h"                    // CPreferences::List Settings
#include "server.h"                         // Needed for CServer - audited 5 Nov 2004
#include "ServerList.h"                     // CServerList
#	include "ServerWnd.h"
#	include "sockets.h"
#	include "xmule.h"
#	include "xmuleDlg.h"
#endif

#include <DynPrefs/DynPrefs.h>              // Needed for DynamicPreferences

#include <wx/stattext.h>                    // wxStaticText

#define SYSCOLOR(x) (wxSystemSettings::GetColour(x))

#include <wx/event.h>
BEGIN_EVENT_TABLE(CServerListCtrl, CMuleListCtrl)
EVT_LIST_ITEM_RIGHT_CLICK(ID_SERVERLIST, CServerListCtrl::OnRclickServlist)
EVT_LIST_COL_CLICK(ID_SERVERLIST, CServerListCtrl::OnLvnColumnclickServlist)
EVT_LEFT_DCLICK(CServerListCtrl::OnLDclick)
END_EVENT_TABLE()

// implemented by processevent():
//  EVT_MENU(MP_CONNECTTO,CServerListCtrl::OnConnectTo)
//EVT_MENU(MP_REMOVE,CServerListCtrl::OnRemove)
//EVT_MENU(MP_GETED2KLINK,CServerListCtrl::OnCopyLink)

//IMPLEMENT_DYNAMIC(CServerListCtrl, CMuleListCtrl/*CTreeCtrl*/)
CServerListCtrl::CServerListCtrl()
{
    memset( &asc_sort, 0, 8);
}

CServerListCtrl::CServerListCtrl(wxWindow *&parent, int id, const wxPoint &pos, wxSize siz, int flags)
: CMuleListCtrl(parent, id, pos, siz, flags)
{
    memset( &asc_sort, 0, 8);
    m_ServerPrioMenu = NULL;
    m_ServerMenu = NULL;
}

void CServerListCtrl::OnLDclick(wxMouseEvent &event)
{
    int lips = 0;
    int index = HitTest(event.GetPosition(), lips);
    if (index >= 0) SetItemState(index, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
    wxCommandEvent nulEvt;
    OnConnectTo(nulEvt);
}

void CServerListCtrl::OnRclickServlist(wxListEvent &event)
{
    // Check if clicked item is selected. If not, unselect all and select it.
    long item = - 1;
    if (!GetItemState(event.GetIndex(), wxLIST_STATE_SELECTED))
    {
        for ( ; ;)
        {
            item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
            if (item == - 1) break;
            SetItemState(item, 0, wxLIST_STATE_SELECTED);
        }
        SetItemState(event.GetIndex(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
    }
    // Create up-to-date popupmenu
    if (m_ServerMenu == NULL)
    {
        m_ServerMenu = new wxMenu(_("Server"));
        m_ServerPrioMenu = new wxMenu();
        m_ServerPrioMenu->Append(MP_PRIOLOW, _("Low"));
        m_ServerPrioMenu->Append(MP_PRIONORMAL, _("Normal"));
        m_ServerPrioMenu->Append(MP_PRIOHIGH, _("High"));
        m_ServerMenu->Append(MP_CONNECTTO, _("Connect to this server"));
        m_ServerMenu->Append(999999, _("Priority"), m_ServerPrioMenu);
        m_ServerMenu->Append(MP_ADDTOSTATIC, _("Add to static"));
        m_ServerMenu->Append(MP_REMOVEFROMSTATIC, GetResString(IDS_REMOVEFROMSTATIC));
        m_ServerMenu->Enable(MP_ADDTOSTATIC, FALSE);
        m_ServerMenu->Enable(MP_REMOVEFROMSTATIC, FALSE);
        m_ServerMenu->AppendSeparator();
        m_ServerMenu->Append(MP_REMOVE, _("Remove server"));
        m_ServerMenu->Append(MP_REMOVEALL, _("Remove all servers"));
        m_ServerMenu->AppendSeparator();
        m_ServerMenu->Append(MP_GETED2KLINK, _("Copy ED2k &link to clipboard"));
    }
    // set states
    CServer *test = NULL;
    int selidx;
    selidx = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
    if (selidx != - 1)
    {
        m_ServerMenu->Enable(999999, TRUE);
    }
    else
    {
        m_ServerMenu->Enable(999999, FALSE);
    }
    if (selidx != - 1)
    {
        test = (CServer *) GetItemData(selidx);
        if (test)
        {
            if (test->IsStaticMember())
            {
                m_ServerMenu->Enable(MP_REMOVEFROMSTATIC, TRUE);
                m_ServerMenu->Enable(MP_ADDTOSTATIC, FALSE);
            }
            else
            {
                m_ServerMenu->Enable(MP_REMOVEFROMSTATIC, FALSE);
                m_ServerMenu->Enable(MP_ADDTOSTATIC, TRUE);
            }
        }
        else
        {
            m_ServerMenu->Enable(MP_REMOVEFROMSTATIC, FALSE);
            m_ServerMenu->Enable(MP_ADDTOSTATIC, FALSE);
        }
    }
    else
    {
        m_ServerMenu->Enable(MP_REMOVEFROMSTATIC, FALSE);
        m_ServerMenu->Enable(MP_ADDTOSTATIC, FALSE);
    }
    PopupMenu(m_ServerMenu, event.GetPoint());
}

void CServerListCtrl::OnConnectTo(wxCommandEvent &event)
{
    int connectcounter = 0;
    long item = - 1;
    if (this->GetSelectedItemCount() > 1)
    {
        theApp.serverconnect->Disconnect();
        item = - 1;
        do
        {
            item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
            if (item > - 1)
            {
                connectcounter++;
                theApp.serverconnect->ConnectToServer((CServer *) this->GetItemData(item), true);
            }
        }
        while (item != - 1 &&connectcounter < 10);
    }
    else
    {
        item = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if (item > - 1)
        {
            theApp.serverconnect->ConnectToServer((CServer *) GetItemData(item));
        }
    }
    theApp.xmuledlg->ShowConnectionState(false);
}

void CServerListCtrl::OnRemove(wxCommandEvent &event)
{
    long item = - 1;
    if (this->GetSelectedItemCount() > 1)
    {
        item = - 1;
        do
        {
            item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
            if (item > - 1)
            {
                theApp.xmuledlg->serverwnd->serverlistctrl->RemoveServer((CServer *) this->GetItemData(item));
            }
        }
        while (item != - 1);
    }
    else
    {
        item = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if (item > - 1)
        {
            theApp.xmuledlg->serverwnd->serverlistctrl->RemoveServer((CServer *) this->GetItemData(item));
        }
    }
}

void CServerListCtrl::OnCopyLink(wxCommandEvent &event)
{
    long item = - 1;
    wxString buffer, link;
    while ((item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != - 1)
    {
        CServer *change = (CServer *) this->GetItemData(item);
        buffer.Printf("ed2k:|server|%s|%d|", change->GetFullIP(), change->GetPort());
        if (link.Length() > 0)
        buffer = "\n" + buffer;
        link += buffer;
    }
    theApp.CopyTextToClipboard(link);
}

void CServerListCtrl::InitSort()
{
    LoadSettings(CPreferences::tableServer);
    // Barry - Use preferred sort order from preferences
    int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableServer);
    bool sortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableServer);
    SetSortArrow(sortItem, sortAscending);
    SortItems(SortProc, sortItem + (sortAscending ? 0: 100));
    ShowFilesCount();
}

bool CServerListCtrl::Init(CServerList *in_list)
{
#if defined(__DEBUG__)
    printf("Serverlist loaded.\n");
#endif
    server_list = in_list;
    InsertColumn(0, _("Server Name"), wxLIST_FORMAT_LEFT, 150);
    InsertColumn(1, _("IP"), wxLIST_FORMAT_LEFT, 140);
    InsertColumn(2, _("Description"), wxLIST_FORMAT_LEFT, 150);
    InsertColumn(3, _("Ping"), wxLIST_FORMAT_LEFT, 50);
    InsertColumn(4, _("Users"), wxLIST_FORMAT_LEFT, 50);
    InsertColumn(5, _("Files"), wxLIST_FORMAT_LEFT, 50);
    InsertColumn(6, _("Preference"), wxLIST_FORMAT_LEFT, 60);
    InsertColumn(7, _("Failed"), wxLIST_FORMAT_LEFT, 50);
    InsertColumn(8, _("Static"), wxLIST_FORMAT_LEFT, 50);
    asc_sort[3] = true;
    asc_sort[4] = true;
    asc_sort[5] = true;
    asc_sort[7] = true;
    // perhaps not yet
    //LoadSettings(CPreferences::tableServer);
#if 0
    this->ModifyStyle(0, TVS_HASLINES |TVS_LINESATROOT |TVS_HASBUTTONS);
    // Set Imagelist
    server_list = in_list;
    imagelist.Create(16, 16, ILC_COLOR |ILC_MASK, 0, 10);
    imagelist.SetBkColor(RGB(255, 255, 255));
    imagelist.Add(theApp.LoadIcon(IDI_ICON1));
    //TVSIL_NORMAL);:
    this->SetImageList( &imagelist, LVSIL_SMALL);
    //here the CListCtrl is set to report-style:
    this->ModifyStyle(LVS_SINGLESEL |LVS_LIST |LVS_ICON |LVS_SMALLICON, LVS_REPORT);
    InsertColumn(0, GetResString(IDS_SL_SERVERNAME), LVCFMT_LEFT, 150);
    InsertColumn(1, GetResString(IDS_IP), LVCFMT_LEFT, 140);
    InsertColumn(2, GetResString(IDS_DESCRIPTION), LVCFMT_LEFT, 150);
    InsertColumn(3, GetResString(IDS_PING), LVCFMT_LEFT, 50);
    InsertColumn(4, GetResString(IDS_UUSERS), LVCFMT_LEFT, 50);
    InsertColumn(5, GetResString(IDS_PW_FILES), LVCFMT_LEFT, 50);
    InsertColumn(6, GetResString(IDS_PREFERENCE), LVCFMT_LEFT, 60);
    InsertColumn(7, GetResString(IDS_UFAILED), LVCFMT_LEFT, 50);
    InsertColumn(8, GetResString(IDS_STATICSERVER), LVCFMT_LEFT, 50);
    asc_sort[3] = true;
    asc_sort[4] = true;
    asc_sort[5] = true;
    asc_sort[7] = true;
    LoadSettings(CPreferences::tableServer);
#endif
    return true;
}

CServerListCtrl::~CServerListCtrl()
{
}

void CServerListCtrl::Localize()
{
#if 0
    CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
    HDITEM hdi;
    hdi.mask = HDI_TEXT;
    wxString strRes;
    strRes = GetResString(IDS_SL_SERVERNAME);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(0, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_IP);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(1, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_DESCRIPTION);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(2, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_PING);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(3, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_UUSERS);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(4, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_PW_FILES);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(5, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_PREFERENCE);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(6, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_UFAILED);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(7, &hdi);
    strRes.ReleaseBuffer();
    strRes = GetResString(IDS_STATICSERVER);
    hdi.pszText = strRes.GetBuffer();
    pHeaderCtrl->SetItem(8, &hdi);
    strRes.ReleaseBuffer();
#endif
}

 /*void CServerListCtrl::ShowServers(){
 DeleteAllItems();
 int i=0;
 wxString temp;
 for(POSITION pos = server_list->list.GetHeadPosition(); pos != NULL;server_list->list.GetNext(pos)) {
 CServer* cur_server = server_list->list.GetAt(pos);
 InsertItem(LVIF_TEXT|LVIF_PARAM,i,cur_server->GetListName(),0,0,0,(LPARAM)cur_server);
 RefreshServer( cur_server );
 i++;
 }
 }
    */

void CServerListCtrl::RemoveServer(CServer *todel, bool bDelToList)
{
    //LVFINDINFO find;
    //find.flags = LVFI_PARAM;
    //find.lParam = (LPARAM)todel;
    int32_t result = FindItem( - 1, (long) todel);
    if (result != ( - 1))
    {
        server_list->RemoveServer((CServer *) GetItemData(result));
        DeleteItem(result);
    }
    return;
}

// Remove Dead Servers
void CServerListCtrl::RemoveDeadServer()
{
    if (theApp.dynprefs->Get<bool>("remove-dead-server") == true)
    {
        //ShowWindow(SW_HIDE);
        for (POSITION pos = server_list->list.GetHeadPosition() ; pos != NULL ; server_list->list.GetNext(pos))
        {
            CServer *cur_server = server_list->list.GetAt(pos);
            if (cur_server->GetFailedCount() > theApp.dynprefs->Get<long>("server-connect-tries"))
            {
                // MAX_SERVERFAILCOUNT
                RemoveServer(cur_server);
                pos = server_list->list.GetHeadPosition();
            }
        }
        //ShowWindow(SW_SHOW);
    }
}

bool CServerListCtrl::AddServer(CServer *toadd, bool bAddToList)
{
    if (!server_list->AddServer(toadd))
    return false;
    if (bAddToList)
    {
        uint32_t itemnr = GetItemCount();
        uint32_t newid = InsertItem(itemnr, toadd->GetListName());
        SetItemData(newid, (long) toadd);
        wxListItem myitem;
        myitem.m_itemId = newid;
        myitem.SetBackgroundColour(SYSCOLOR(wxSYS_COLOUR_LISTBOX));
        SetItem(myitem);
        RefreshServer(toadd);
        //uint32_t itemnr = GetItemCount();
        //InsertItem(LVIF_TEXT|LVIF_PARAM,itemnr,toadd->GetListName(),0,0,1,(LPARAM)toadd);
        //RefreshServer( toadd );
    }
    ShowFilesCount();
    return true;
}

void CServerListCtrl::RefreshServer(CServer *server)
{
    long itemnr = FindItem( - 1, (long) server);
    if (itemnr == ( - 1))
    return;
    wxString temp;
    if (!server)
    return;
    temp = wxString::Format("%s : %i", server->GetAddress(), server->GetPort());
    SetItem(itemnr, 1, temp);
    if (server->GetListName())
    {
        temp = server->GetListName();
        SetItem(itemnr, 0, temp);
    }
    if (server->GetDescription())
    {
        temp = server->GetDescription();
        SetItem(itemnr, 2, temp);
    }
    if (1)
    {
        //server->GetPing()){
        if (server->GetPing())
        temp = wxString::Format("%i", server->GetPing());
        else temp = "";
        SetItem(itemnr, 3, temp);
    }
    else
    {
#if defined(__DEBUG__)
        printf("%lx: ei ping\n", server);
#endif
        SetItem(itemnr, 3, "Ei ei");
    }
    if (server->GetUsers())
    {
        temp = wxString::Format("%i", server->GetUsers());
        SetItem(itemnr, 4, temp);
    }
    if (server->GetFiles())
    {
        temp = wxString::Format("%i", server->GetFiles());
        SetItem(itemnr, 5, temp);
    }
    if (server->GetPreferences())
    {
        temp = wxString::Format("%i", server->GetPreferences());
        SetItem(itemnr, 6, temp);
    }
    switch (server->GetPreferences())
    {
    case SRV_PR_LOW:
        temp.Printf(GetResString(IDS_PRIOLOW));
        SetItem(itemnr, 6, temp);
        break;
    case SRV_PR_NORMAL:
        temp.Printf(GetResString(IDS_PRIONORMAL));
        SetItem(itemnr, 6, temp);
        break;
    case SRV_PR_HIGH:
        temp.Printf(GetResString(IDS_PRIOHIGH));
        SetItem(itemnr, 6, temp);
        break;
    default:
        temp.Printf(GetResString(IDS_PRIONOPREF));
        SetItem(itemnr, 6, temp);
    }
    if (server->GetFailedCount() < 0)
    server->ResetFailedCount();
    temp = wxString::Format("%i", server->GetFailedCount());
    SetItem(itemnr, 7, temp);
    //GetResString(IDS_YES));:
    if (server->IsStaticMember()) SetItem(itemnr, 8, _("Yes"));
    //GetResString(IDS_NO));:
    else SetItem(itemnr, 8, _("No"));
}

#if 0
    BEGIN_MESSAGE_MAP(CServerListCtrl, CMuleListCtrl/*CTreeCtrl*/

)
ON_NOTIFY_REFLECT(NM_RCLICK, OnNMRclickServlist)
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnLvnColumnclickServlist)
//<-- mod bb 27.09.02:
ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMLdblclk)
END_MESSAGE_MAP()

// CServerListCtrl message handlers

void CServerListCtrl::OnNMRclickServlist(NMHDR *pNMHDR, LRESULT *pResult)
{
    POINT point;
    ::GetCursorPos( &point);
    // tecxx 0609 2002
    // fix - on right click, we also want to change the current selection like the left click does
    CPoint p = point;
    ScreenToClient( &p);
    int it = HitTest(p);
    if (it != - 1)
    // display selection mark correctly!:
    SetSelectionMark(it);
    // fix end
    // Create up-to-date popupmenu
    UINT flags;
    CTitleMenu m_ServerMenu;
    CMenu m_ServerPrioMenu;
    // set state of selection-dependent menuitems
    flags = MF_STRING || MF_DISABLED;
    if (this->GetSelectionMark() != - 1) if(((CServer *) GetItemData(GetSelectionMark())) != NULL) flags = MF_STRING;
    // add priority switcher
    m_ServerPrioMenu.CreateMenu();
    m_ServerPrioMenu.AppendMenu(MF_STRING, MP_PRIOLOW, GetResString(IDS_PRIOLOW));
    m_ServerPrioMenu.AppendMenu(MF_STRING, MP_PRIONORMAL, GetResString(IDS_PRIONORMAL));
    m_ServerPrioMenu.AppendMenu(MF_STRING, MP_PRIOHIGH, GetResString(IDS_PRIOHIGH));
    m_ServerMenu.CreatePopupMenu();
    m_ServerMenu.AddMenuTitle(GetResString(IDS_EM_SERVER));
    m_ServerMenu.AppendMenu(flags, MP_CONNECTTO, GetResString(IDS_CONNECTTHIS));
    m_ServerMenu.AppendMenu(flags |MF_POPUP, (UINT_PTR) m_ServerPrioMenu.m_hMenu, GetResString(IDS_PRIORITY));
    m_ServerMenu.AppendMenu(flags, MP_ADDTOSTATIC, GetResString(IDS_ADDTOSTATIC));
    m_ServerMenu.AppendMenu(MF_STRING |MF_SEPARATOR);
    m_ServerMenu.AppendMenu(flags, MP_REMOVE, GetResString(IDS_REMOVETHIS));
    m_ServerMenu.AppendMenu(MF_STRING, MP_REMOVEALL, GetResString(IDS_REMOVEALL));
    m_ServerMenu.AppendMenu(MF_SEPARATOR);
    m_ServerMenu.AppendMenu(MF_STRING, MP_GETED2KLINK, GetResString(IDS_DL_LINK1));
    m_ServerMenu.SetDefaultItem(MP_CONNECTTO);
    m_ServerMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON, point.x, point.y, this);
    m_ServerMenu.DestroyMenu();
    *pResult = 0;
}

#endif

bool CServerListCtrl::ProcessEvent(wxEvent &evt)
{
    if (evt.GetEventType() != wxEVT_COMMAND_MENU_SELECTED)
    {
        return CMuleListCtrl::ProcessEvent(evt);
    }

    wxCommandEvent& event = static_cast<wxCommandEvent &>(evt);
    //int item= this->GetSelectionMark();
    int item = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
    if (event.GetId() == MP_REMOVEALL)
    {
        if (theApp.serverconnect->IsConnecting())
        {
            theApp.downloadqueue->StopUDPRequests();
            theApp.serverconnect->StopConnectionTry();
            theApp.serverconnect->Disconnect();
            theApp.xmuledlg->ShowConnectionState(false);
        }
        //ShowWindow(SW_HIDE);
        server_list->RemoveAllServers();
        DeleteAllItems();
        //ShowWindow(SW_SHOW);
        ShowFilesCount();
        return true;
    }
    if (item != - 1)
    {
        if (((CServer *) GetItemData(item)) != NULL)
        {
            switch (event.GetId())
            {
            case MP_CONNECTTO:
                {
                    if (this->GetSelectedItemCount() > 1)
                    {
                        CServer *aServer;
                        theApp.serverconnect->Disconnect();
                        int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                        while (pos != - 1)
                        {
                            //this->GetNextSelectedItem(pos);:
                            item = pos;
                            if (item > - 1)
                            {
                                aServer = (CServer *) this->GetItemData(item);
                                theApp.serverlist->MoveServerDown(aServer);
                            }
                            pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                        }
                        theApp.serverconnect->ConnectToAnyServer(theApp.serverlist->GetServerCount() - this->GetSelectedItemCount(), false, false);
                    }
                    else
                    {
                        theApp.serverconnect->ConnectToServer((CServer *) GetItemData(item));
                    }
                    theApp.xmuledlg->ShowConnectionState(false);
                    break;
                }
            case MP_REMOVE:
                {
                    //POSITION pos;
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    //GetFirstSelectedItemPosition()!=NULL) //(pos != NULL):
                    while (pos != - 1)
                    {
                        //pos=GetFirstSelectedItemPosition();
                        //this->GetNextSelectedItem(pos);:
                        item = pos;
                        server_list->RemoveServer((CServer *) this->GetItemData(item));
                        DeleteItem(item);
                        pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    ShowFilesCount();
                    //ShowWindow(SW_SHOW);
                    break;
                }
            case MP_ADDTOSTATIC:
                {
                    //POSITION pos=GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        if (!StaticServerFileAppend(change))
                        return false;
                        change->SetIsStaticMember(true);
                        theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(change);
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    break;
                }
                // Remove Static Servers [Barry]
            case MP_REMOVEFROMSTATIC:
                {
                    //POSITION pos=GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        if (!StaticServerFileRemove(change))
                        return false;
                        change->SetIsStaticMember(false);
                        theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(change);
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    break;
                }
            case MP_PRIOLOW:
                {
                    //POSITION pos = this->GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        change->SetPreference(SRV_PR_LOW);
                        //					if (change->IsStaticMember())
                        //						StaticServerFileAppend(change); //Why are you adding to static when changing prioity? If I want it static I set it static.. I set server to LOW because I HATE this server, not because I like it!!!
                        theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(change);
                        //POSITION pos = this->GetFirstSelectedItemPosition();
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    break;
                }
            case MP_PRIONORMAL:
                {
                    //POSITION pos = this->GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        change->SetPreference(SRV_PR_NORMAL);
                        //					if (change->IsStaticMember())
                        //						StaticServerFileAppend(change);
                        theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(change);
                        //POSITION pos = this->GetFirstSelectedItemPosition();
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    break;
                }
            case MP_PRIOHIGH:
                {
                    //POSITION pos = this->GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        change->SetPreference(SRV_PR_HIGH);
                        //					if (change->IsStaticMember())
                        //						StaticServerFileAppend(change);
                        theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(change);
                        //POSITION pos = this->GetFirstSelectedItemPosition();
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    break;
                }
            case MP_GETED2KLINK:
                {
                    //POSITION pos = this->GetFirstSelectedItemPosition();
                    int pos = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    wxString buffer, link;
                    while (pos != - 1)
                    {
                        CServer *change = (CServer *) this->GetItemData(pos);
                        buffer.Printf("ed2k://|server|%s|%d|/", change->GetFullIP(), change->GetPort());
                        if (link.Length() > 0) buffer = "\n" + buffer;
                        link += buffer;
                        //POSITION pos = this->GetFirstSelectedItemPosition();
                        pos = GetNextItem(pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                    }
                    theApp.CopyTextToClipboard(link);
                    break;
                }
#if 0
            case Irc_SetSendLink:
                {
                    POSITION pos = this->GetFirstSelectedItemPosition();
                    wxString buffer, link;
                    while (pos != NULL)
                    {
                        CServer *change = (CServer *) this->GetItemData(this->GetNextSelectedItem(pos));
                        buffer.Printf("ed2k://|server|%s|%d|/", change->GetFullIP(), change->GetPort());
                        if (link.GetLength() > 0) buffer = "\n" + buffer;
                        link += buffer;
                        POSITION pos = this->GetFirstSelectedItemPosition();
                    }
                    theApp.xmuledlg->ircwnd.SetSendFileString(link);
                    break;
                }
#endif
            }
        }
    }
    return CMuleListCtrl::ProcessEvent(evt);
}

#if 0
void CServerListCtrl::OnNMLdblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
    // mod bb 27.09.02
    if (GetSelectionMark() != ( - 1))
    {
        theApp.serverconnect->ConnectToServer((CServer *) GetItemData(GetSelectionMark()));
        theApp.xmuledlg->ShowConnectionState(false);
    }
}

bool CServerListCtrl::AddServermetToList(wxString strFile)
{
    bool flag = server_list->AddServermetToList(strFile);
    RemoveDeadServer();
    return flag;
}

#endif

bool CServerListCtrl::AddServermetToList(wxString strFile)
{
    Freeze();
    bool flag = server_list->AddServermetToList(wxString(strFile.GetData()));
    RemoveDeadServer();
    ShowFilesCount();
    Thaw();
    return flag;
}

//NMHDR *pNMHDR, LRESULT *pResult):
void CServerListCtrl::OnLvnColumnclickServlist(wxListEvent &evt)
{
    // Barry - Store sort order in preferences
    // Determine ascending based on whether already sorted on this column
    int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableServer);
    bool m_oldSortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableServer);
    bool sortAscending = (sortItem != evt.GetColumn()) ? true: !m_oldSortAscending;
    // Item is column clicked
    sortItem = evt.GetColumn();
    // Save new preferences
    theApp.glob_prefs->SetColumnSortItem(CPreferences::tableServer, sortItem);
    theApp.glob_prefs->SetColumnSortAscending(CPreferences::tableServer, sortAscending);
    // Sort table
    SetSortArrow(sortItem, sortAscending);
    SortItems(SortProc, sortItem + (sortAscending ? 0: 100));
}

int CServerListCtrl::SortProc(long lParam1, long lParam2, long lParamSort)
{
    CServer *item1 = (CServer *) lParam1;
    CServer *item2 = (CServer *) lParam2;
    if ((item1 == NULL) || (item2 == NULL)) return 0;
    int iTemp = 0;
    int counter1;
    int counter2;
    switch (lParamSort)
    {
        //(List) Server-name asc:
    case 0:
        return wxString(item1->GetListName()) .CmpNoCase(item2->GetListName());
        //(List) Server-name desc:
    case 100:
        return wxString(item2->GetListName()) .CmpNoCase(item1->GetListName());
    case 1:
        {
            //IP asc
            if (item1->HasDynIP() &&item2->HasDynIP())
            return wxString(item1->GetDynIP()) .CmpNoCase(item2->GetDynIP());
            else if(item1->HasDynIP())
            return 1;
            else if(item2->HasDynIP())
            return 0;
            else
            {
                wxString sIP1, sIP2, sTemp1, sTemp2;
                counter1 = counter2 = iTemp = 0;
                sIP1 = item2->GetFullIP();
                sIP2 = item1->GetFullIP();
                int a[4], b[4];
                sscanf(sIP1.GetData(), "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
                sscanf(sIP2.GetData(), "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]);
                for (int i = 0 ; iTemp == 0 ; i++)
                {
                    iTemp = b[i] - a[i];
                    if (i > 3)
                    {
                        return item1->GetPort() - item2->GetPort();
                    }
                }
#if 0
                for (int i = 0 ; iTemp == 0 ; i++)
                {
                    sTemp1 = sIP1.Tokenize(".", counter1);
                    sTemp2 = sIP2.Tokenize(".", counter2);
                    iTemp = atoi(sTemp2) - atoi(sTemp1);
                    if (i > 2)
                    {
                        return item1->GetPort() - item2->GetPort();
                    }
                }
#endif
                return iTemp;
            }
        }
    case 101:
        {
            //IP desc
            if (item1->HasDynIP() &&item2->HasDynIP())
            return wxString(item2->GetDynIP()) .CmpNoCase(item1->GetDynIP());
            else if(item1->HasDynIP())
            return 0;
            else if(item2->HasDynIP())
            return 1;
            else
            {
                wxString s2IP1, s2IP2, s2Temp1, s2Temp2;
                counter1 = counter2 = iTemp = 0;
                s2IP1 = item2->GetFullIP();
                s2IP2 = item1->GetFullIP();
                int a[4], b[4];
                sscanf(s2IP1.GetData(), "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
                sscanf(s2IP2.GetData(), "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]);
                for (int i = 0 ; iTemp == 0 ; i++)
                {
                    iTemp = a[i] - b[i];
                    if (i > 3)
                    {
                        return item2->GetPort() - item1->GetPort();
                    }
                }
#if 0
                for (int i = 0 ; iTemp == 0 ; i++)
                {
                    s2Temp1 = s2IP1.Tokenize(".", counter1);
                    s2Temp2 = s2IP2.Tokenize(".", counter2);
                    iTemp = atoi(s2Temp1) - atoi(s2Temp2);
                    if (i > 2)
                    {
                        return item2->GetPort() - item1->GetPort();
                    }
                }
#endif
                return iTemp;
            }
        }
        //Description asc:
    case 2:
        if ((item1->GetDescription() != NULL) && (item2->GetDescription() != NULL))
        //the 'if' is necessary, because the Description-String is not
        //always initialisized in server.cpp
        return wxString(item2->GetDescription()) .CmpNoCase(item1->GetDescription());
        else if(item1->GetDescription() == NULL)
        return 1;
        else
        return 0;
        //Desciption desc:
    case 102:
        if ((item1->GetDescription() != NULL) && (item2->GetDescription() != NULL))
        return wxString(item1->GetDescription()) .CmpNoCase(item2->GetDescription());
        else if(item1->GetDescription() == NULL)
        return 1;
        else
        return 0;
        //Ping asc:
    case 3:
        return item1->GetPing() - item2->GetPing();
        //Ping desc:
    case 103:
        return item2->GetPing() - item1->GetPing();
        //Users asc:
    case 4:
        return item1->GetUsers() - item2->GetUsers();
        //Users desc:
    case 104:
        return item2->GetUsers() - item1->GetUsers();
        //Files asc:
    case 5:
        return item1->GetFiles() - item2->GetFiles();
        //Files desc:
    case 105:
        return item2->GetFiles() - item1->GetFiles();
        //Preferences asc:
    case 6:
        return item2->GetPreferences() - item1->GetPreferences();
        //Preferences desc:
    case 106:
        return item1->GetPreferences() - item2->GetPreferences();
        //failed asc:
    case 7:
        return item1->GetFailedCount() - item2->GetFailedCount();
        //failed desc:
    case 107:
        return item2->GetFailedCount() - item1->GetFailedCount();
        //staticservers:
    case 8:
        return item2->IsStaticMember() - item1->IsStaticMember();
        //staticservers-:
    case 108:
        return item1->IsStaticMember() - item2->IsStaticMember();
    default:
        return 0;
    }
}

bool CServerListCtrl::StaticServerFileAppend(CServer *server)
{
    try
    {
        // Remove any entry before writing to avoid duplicates
        StaticServerFileRemove(server);
        FILE* staticservers = fopen(static_cast<const char *>(wxString(theApp.dynprefs->Get<wxString>("app-directory") + wxT("staticservers.dat")).c_str()), "a");
        if (staticservers == NULL)
        {
            theApp.xmuledlg->AddLogLine(false, GetResString(IDS_ERROR_SSF));
            return false;
        }
        if (fprintf(staticservers,
        "%s:%i,%i,%s\n",
        server->GetAddress(),
        server->GetPort(),
        server->GetPreferences(),
        server->GetListName()) != EOF)
        {
            theApp.xmuledlg->AddLogLine(false, "'%s:%i,%s' %s", server->GetAddress(), server->GetPort(), server->GetListName(), GetResString(IDS_ADDED2SSF) .GetData());
            server->SetIsStaticMember(true);
            theApp.xmuledlg->serverwnd->serverlistctrl->RefreshServer(server);
        }
        fclose(staticservers);
    }
    catch(...)
    {
        return false;
    }
    return true;
}

bool CServerListCtrl::StaticServerFileRemove(CServer *server)
{
    try
    {
        if (!server->IsStaticMember())
        return true;
        wxString strLine;
        wxString strTest;
        char buffer[1024];
        int lenBuf = 1024;
        int pos;
        wxString StaticFilePath = theApp.dynprefs->Get<wxString>("app-directory") + wxT("staticservers.dat");
        wxString StaticTempPath = theApp.dynprefs->Get<wxString>("app-directory") + wxT("statictemp.dat");
        FILE *staticservers = fopen(StaticFilePath, "r");
        FILE *statictemp = fopen(StaticTempPath, "w");
        if ((staticservers == NULL) || (statictemp == NULL))
        {
            theApp.xmuledlg->AddLogLine(false, GetResString(IDS_ERROR_SSF));
            return false;
        }
        while (!feof(staticservers))
        {
            if (fgets(buffer, lenBuf, staticservers) == 0)
            break;
            strLine = buffer;
            // ignore comments or invalid lines
            if (strLine.GetChar(0) == '#' || strLine.GetChar(0) == '/')
            continue;
            if (strLine.Length() < 5)
            continue;
            // Only interested in "host:port"
            pos = strLine.Find(",");
            if (pos == - 1)
            continue;
            strLine = strLine.Left(pos);
            // Get host and port from given server
            strTest.Printf("%s:%i", server->GetAddress(), server->GetPort());
            // Compare, if not the same server write original line to temp file
            if (strLine.Cmp(strTest) != 0)
            fprintf(statictemp, "%s", buffer);
        }
        fclose(staticservers);
        fclose(statictemp);
        // All ok, remove the existing file and replace with the new one
        wxRemoveFile(StaticFilePath);
        wxRenameFile(StaticTempPath, StaticFilePath);
    }
    catch(...)
    {
        return false;
    }
    return true;
}

void CServerListCtrl::ShowFilesCount()
{
    wxString fmtstr = wxString::Format(_("Servers (%i)"), GetItemCount());
    wxStaticCast(FindWindowByName(wxT("serverListLabel")), wxStaticText)->SetLabel(fmtstr);
}

