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

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "UploadListCtrl.h"

#	include "ChatWnd.h"
#include "ClientCredits.h"                  // CClientCredits
#	include "ClientDetailDialog.h"
#	include "FriendList.h"
#	include "KnownFile.h"
#	include "muuli_wdr.h"
#	include "opcodes.h"
#	include "otherfunctions.h"
#include "Preferences.h"                    // CPreferences::List Settings
#	include "SharedFileList.h"
#	include "TransferWnd.h"
#include "updownclient.h"                   // Needed for CUpDownClient - audited 5 Nov 2004
#	include "wintypes.h"
#	include "xmule.h"
#	include "xmuleDlg.h"
#endif

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

BEGIN_EVENT_TABLE(CUploadListCtrl, CMuleListCtrl)
EVT_RIGHT_DOWN(CUploadListCtrl::OnNMRclick)
EVT_LIST_COL_CLICK(ID_UPLOADLIST, CUploadListCtrl::OnColumnClick)
END_EVENT_TABLE()

// images
#include "pixmaps/neutral.ico.xpm"
#include "pixmaps/compatible.ICO.xpm"
#include "pixmaps/plus.ICO.xpm"
#include "pixmaps/pluscompa.ICO.xpm"
#include "pixmaps/Friend.ico.xpm"
#include "pixmaps/mldonk.ico.xpm"
#include "pixmaps/plusmldonk.ico.xpm"
#include "pixmaps/eDonkeyHybrid.ico.xpm"
#include "pixmaps/pluseDonkeyHybrid.ico.xpm"
#include "pixmaps/thief.ico.xpm"

//IMPLEMENT_DYNAMIC(CUploadListCtrl, CMuleListCtrl)
CUploadListCtrl::CUploadListCtrl()
{
}

CUploadListCtrl::CUploadListCtrl(wxWindow *&parent, int id, const wxPoint &pos, wxSize siz, int flags)
: CMuleListCtrl(parent, id, pos, siz, flags |wxLC_OWNERDRAW)
{
    m_ClientMenu = NULL;
    wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
    wxColour newcol = wxColour(G_BLEND(col.Red(), 125),
    G_BLEND(col.Green(), 125),
    G_BLEND(col.Blue(), 125));
    m_hilightBrush = new wxBrush(newcol, wxSOLID);
    col = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
    newcol = wxColour(G_BLEND(col.Red(), 125),
    G_BLEND(col.Green(), 125),
    G_BLEND(col.Blue(), 125));
    m_hilightUnfocusBrush = new wxBrush(newcol, wxSOLID);
    Init();
    // load images
    imagelist.Add(wxBitmap(neutral_ico));
    imagelist.Add(wxBitmap(compatible_ICO));
    imagelist.Add(wxBitmap(plus_ICO));
    imagelist.Add(wxBitmap(pluscompa_ICO));
    imagelist.Add(wxBitmap(Friend_ico));
    imagelist.Add(wxBitmap(mldonk_ico));
    imagelist.Add(wxBitmap(plusmldonk_ico));
    imagelist.Add(wxBitmap(eDonkeyHybrid_ico));
    imagelist.Add(wxBitmap(pluseDonkeyHybrid_ico));
    // Added a Thief icon [BlackRat]
    imagelist.Add(wxBitmap(thief_ico));
}

void CUploadListCtrl::Init()
{
    //,0);:
    InsertColumn(0, GetResString(IDS_QL_USERNAME), wxLIST_FORMAT_LEFT, 150);
    //,1);:
    InsertColumn(1, GetResString(IDS_FILE), wxLIST_FORMAT_LEFT, 275);
    //,2);:
    InsertColumn(2, GetResString(IDS_DL_SPEED), wxLIST_FORMAT_LEFT, 60);
    //,3);:
    InsertColumn(3, GetResString(IDS_DL_TRANSF), wxLIST_FORMAT_LEFT, 65);
    //,4);:
    InsertColumn(4, GetResString(IDS_WAITED), wxLIST_FORMAT_LEFT, 60);
    //,6);:
    InsertColumn(5, GetResString(IDS_UPLOADTIME), wxLIST_FORMAT_LEFT, 60);
    //,5);:
    InsertColumn(6, GetResString(IDS_STATUS), wxLIST_FORMAT_LEFT, 110);
    InsertColumn(7, GetResString(IDS_UPSTATUS), wxLIST_FORMAT_LEFT, 100);
    // not here.. no preferences yet
    //LoadSettings(CPreferences::tableUpload);
}

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

CUploadListCtrl::~CUploadListCtrl()
{
    delete m_hilightBrush;
    delete m_hilightUnfocusBrush;
}

void CUploadListCtrl::Localize()
{
}

void CUploadListCtrl::OnNMRclick(wxMouseEvent &evt)
{
    // Check if clicked item is selected. If not, unselect all and select it.
    long item = - 1;
    int lips = 0;
    int index = HitTest(evt.GetPosition(), lips);
    if (!GetItemState(index, wxLIST_STATE_SELECTED))
    {
        for ( ; ;)
        {
            item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
            if (item == - 1) break;
            SetItemState(item, 0, wxLIST_STATE_SELECTED);
        }
        SetItemState(index, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
    }
    if (m_ClientMenu == NULL)
    {
        wxMenu *menu = new wxMenu(GetResString(IDS_CLIENTS));
        menu->Append(MP_DETAIL, GetResString(IDS_SHOWDETAILS));
        menu->Append(MP_ADDFRIEND, GetResString(IDS_ADDFRIEND));
        menu->Append(MP_MESSAGE, GetResString(IDS_SEND_MSG));
        menu->Append(MP_SHOWLIST, GetResString(IDS_VIEWFILES));
        menu->AppendSeparator();
        menu->Append(MP_SWITCHCTRL, GetResString(IDS_VIEWQUEUE));
        m_ClientMenu = menu;
    }
    PopupMenu(m_ClientMenu, evt.GetPosition());
}

void CUploadListCtrl::AddClient(CUpDownClient *client)
{
    uint32_t itemnr = GetItemCount();
    char buffer[100];
    //itemnr = InsertItem(LVIF_TEXT|LVIF_PARAM,itemnr,client->GetUserName(),0,0,1,(LPARAM)client);
    itemnr = InsertItem(itemnr, client->GetUserName());
    SetItemData(itemnr, (long) client);
    wxListItem myitem;
    myitem.m_itemId = itemnr;
    // FIXME
    myitem.SetBackgroundColour(SYSCOLOR(wxSYS_COLOUR_LISTBOX));
    SetItem(myitem);
    RefreshClient(client);
}

void CUploadListCtrl::RemoveClient(CUpDownClient *client)
{
    //LVFINDINFO find;
    //find.flags = LVFI_PARAM;
    //find.lParam = (LPARAM)client;
    //int32_t result = FindItem(&find);
    int32_t result = FindItem( - 1, (long) client);
    if (result != ( - 1))
    DeleteItem(result);
}

void CUploadListCtrl::RefreshClient(CUpDownClient *client)
{
    //LVFINDINFO find;
    //find.flags = LVFI_PARAM;
    //find.lParam = (LPARAM)client;
    //int32_t itemnr = FindItem(&find);
    int32_t itemnr = FindItem( - 1, (long) client);
    if (itemnr == ( - 1))
    return;
    uint8_t image;
    if (client->ExtProtocolAvailable())
    {
        if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
        image = 3;
        else
        image = 1;
    }
    else
    {
        if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
        image = 2;
        else
        image = 0;
    }
    // no images yet
    //SetItem(itemnr,0,LVIF_IMAGE,0,image,0,0,0,0);
    char buffer[100];
    CKnownFile *file = theApp.sharedfiles->GetFileByID(client->GetUploadFileID());
    if (file)
    SetItem(itemnr, 1, file->GetFileName());
    else
    SetItem(itemnr, 1, "?");
    sprintf(buffer, "%.1f kB/s", (float) client->GetDatarate() /1024);
    SetItem(itemnr, 2, buffer);
    SetItem(itemnr, 3, CastItoXBytes(client->GetTransferedUp()));
    SetItem(itemnr, 5, CastSecondsToHM((client->GetUpStartTimeDelay()) /1000));
    wxString status;
    switch (client->GetUploadState())
    {
    case US_CONNECTING:
        status = GetResString(IDS_CONNECTING);
        break;
    case US_WAITCALLBACK:
        status = GetResString(IDS_CONNVIASERVER);
        break;
    case US_UPLOADING:
        status = GetResString(IDS_TRANSFERRING);
        break;
    default:
        status = GetResString(IDS_UNKNOWN);
    }
    SetItem(itemnr, 6, status);
    SetItem(itemnr, 7, "Bar is missing :)");
}

bool CUploadListCtrl::ProcessEvent(wxEvent &evt)
{
    if (evt.GetEventType() != wxEVT_COMMAND_MENU_SELECTED)
    return CMuleListCtrl::ProcessEvent(evt);
    wxCommandEvent &event = (wxCommandEvent &) evt;
    int cursel = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
    if (cursel != ( - 1))
    {
        CUpDownClient *client = (CUpDownClient *) GetItemData(cursel);
        switch (event.GetId())
        {
        case MP_SHOWLIST:
            client->RequestSharedFileList();
            break;
        case MP_MESSAGE:
            {
                theApp.xmuledlg->chatwnd->StartSession(client);
                break;
            }
        case MP_ADDFRIEND:
            {
                //      int pos;
                //      while (pos!=-1) {
                theApp.friendlist->AddFriend(client);
                //	pos=GetNextItem(pos,wxLIST_NEXT_ALL,wxLIST_STATE_SELECTED);
                //      }
                break;
            }
        case MP_DETAIL:
            {
                CClientDetailDialog *dialog = new CClientDetailDialog(this, client);
                dialog->ShowModal();
                delete dialog;
                return TRUE;
                break;
            }
        }
    }
    switch (event.GetId())
    {
    case MP_SWITCHCTRL:
        {
            //((CTransferWnd*)GetParent())->SwitchUploadList(event);
            theApp.xmuledlg->transferwnd->SwitchUploadList(event);
        }
    }
    return CMuleListCtrl::ProcessEvent(evt);
}

void CUploadListCtrl::OnColumnClick(wxListEvent &evt)
{
    //NMHDR* pNMHDR, LRESULT* pResult){
    //NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    // if it's a second click on the same column then reverse the sort order,
    // Barry - Store sort order in preferences
    // Determine ascending based on whether already sorted on this column
    int sortItem = theApp.glob_prefs->GetColumnSortItem(CPreferences::tableUpload);
    bool m_oldSortAscending = theApp.glob_prefs->GetColumnSortAscending(CPreferences::tableUpload);
    bool sortAscending = (sortItem != evt.GetColumn()) ? true: !m_oldSortAscending;
    // Item is column clicked
    sortItem = evt.GetColumn();
    // Save new preferences
    theApp.glob_prefs->SetColumnSortItem(CPreferences::tableUpload, sortItem);
    theApp.glob_prefs->SetColumnSortAscending(CPreferences::tableUpload, sortAscending);
    // Sort table
    SetSortArrow(sortItem, sortAscending);
    SortItems(SortProc, sortItem + (sortAscending ? 0: 100));
    // otherwise sort the new column in ascending order.
    //*pResult = 0;
}

int CUploadListCtrl::SortProc(long lParam1, long lParam2, long lParamSort)
{
    CUpDownClient *item1 = (CUpDownClient *) lParam1;
    CUpDownClient *item2 = (CUpDownClient *) lParam2;
    CKnownFile *file1 = theApp.sharedfiles->GetFileByID(item1->GetUploadFileID());
    CKnownFile *file2 = theApp.sharedfiles->GetFileByID(item2->GetUploadFileID());
    switch (lParamSort)
    {
    case 0:
        return wxString(item1->GetUserName()) .CmpNoCase(item2->GetUserName());
    case 100:
        return wxString(item2->GetUserName()) .CmpNoCase(item1->GetUserName());
    case 1:
        if ((file1 != NULL) && (file2 != NULL))
        return wxString(file1->GetFileName()) .CmpNoCase(file2->GetFileName());
        else if(file1 == NULL)
        return 1;
        else
        return 0;
    case 101:
        if ((file1 != NULL) && (file2 != NULL))
        return wxString(file2->GetFileName()) .CmpNoCase(file1->GetFileName());
        else if(file1 == NULL)
        return 1;
        else
        return 0;
    case 2:
        return int((float) item1->GetDatarate() - (float) item2->GetDatarate());
    case 102:
        return int((float) item2->GetDatarate() - (float) item1->GetDatarate());
    case 3:
        return item1->GetTransferedUp() - item2->GetTransferedUp();
    case 103:
        return item2->GetTransferedUp() - item1->GetTransferedUp();
    case 4:
        return item1->GetWaitTime() - item2->GetWaitTime();
    case 104:
        return item2->GetWaitTime() - item1->GetWaitTime();
    case 5:
        return item1->GetUpStartTimeDelay() - item2->GetUpStartTimeDelay();
    case 105:
        return item2->GetUpStartTimeDelay() - item1->GetUpStartTimeDelay();
    case 6:
        return item1->GetUploadState() - item2->GetUploadState();
    case 106:
        return item2->GetUploadState() - item1->GetUploadState();
    case 7:
        return item1->GetUpPartCount() - item2->GetUpPartCount();
    case 107:
        return item2->GetUpPartCount() - item1->GetUpPartCount();
    default:
        return 0;
    }
}

void CUploadListCtrl::OnDrawItem(int item, wxDC *dc, const wxRect &rect, const wxRect &rectHL, bool highlighted)
{
    /* Don't do any drawing if we not being watched. */
    if (!theApp.xmuledlg->IsRunning() || (theApp.xmuledlg->transferwnd->windowtransferstate) || (theApp.xmuledlg->GetActiveDialog() != 2))
    {
        return;
    }
    if (highlighted)
    {
        if (GetFocus())
        {
            dc->SetBackground( *m_hilightBrush);
            dc->SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
        }
        else
        {
            dc->SetBackground( *m_hilightUnfocusBrush);
            dc->SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
        }
    }
    else
    {
        dc->SetBackground( * (wxTheBrushList->FindOrCreateBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX), wxSOLID)));
        dc->SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
    }
    // fill it
    wxPen mypen;
    if (highlighted)
    {
        // set pen so that we'll get nice border
        wxColour old = GetFocus() ?m_hilightBrush->GetColour(): m_hilightUnfocusBrush->GetColour();
        wxColour newcol = wxColour(((int) old.Red() *65) /100,
        ((int) old.Green() *65) /100,
        ((int) old.Blue() *65) /100);
        mypen = wxPen(newcol, 1, wxSOLID);
        dc->SetPen(mypen);
    }
    else
    {
        dc->SetPen( *wxTRANSPARENT_PEN);
    }
    dc->SetBrush(dc->GetBackground());
    dc->DrawRectangle(rectHL);
    dc->SetPen( *wxTRANSPARENT_PEN);
    // then stuff from original xmule
    //lpDrawItemStruct->itemData;:
    CUpDownClient *client = (CUpDownClient *) GetItemData(item);
    //CMemDC dc(CDC::FromHandle(lpDrawItemStruct->hDC),&CRect(lpDrawItemStruct->rcItem));
    //dc.SelectObject(GetFont());
    //COLORREF crOldTextColor = dc->GetTextColor();
    //COLORREF crOldBkColor = dc->GetBkColor();
    RECT cur_rec;
    //memcpy(&cur_rec,&lpDrawItemStruct->rcItem,sizeof(RECT));
    cur_rec.left = rect.x;
    cur_rec.top = rect.y;
    cur_rec.right = rect.x + rect.width;
    cur_rec.bottom = rect.y + rect.height;
    // lagloose
    wxString rbuffer;
    // end lagloose
    wxString Sbuffer;
    CKnownFile *file = theApp.sharedfiles->GetFileByID(client->GetUploadFileID());
    //CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
    //pHeaderCtrl->GetItemCount();:
    int iCount = GetColumnCount();
    cur_rec.right = cur_rec.left - 8;
    cur_rec.left += 4;
    for (int iCurrent = 0 ; iCurrent < iCount ; iCurrent++)
    {
        //pHeaderCtrl->OrderToIndex(iCurrent);:
        int iColumn = iCurrent;
        if (1)
        {
            // !IsColumnHidden(iColumn) ){ (column's can't be hidden :)
            wxListItem listitem;
            GetColumn(iColumn, listitem);
            int cx = listitem.GetWidth();
            //GetColumnWidth(iColumn);:
            cur_rec.right += cx;
            wxDCClipper *clipper = new wxDCClipper( *dc, cur_rec.left, cur_rec.top, cur_rec.right - cur_rec.left,
            cur_rec.bottom - cur_rec.top);
            switch (iColumn)
            {
            case 0:
                {
                    uint8_t image;
                    if (client->IsFriend())
                    image = 4;
                    else if(client->ExtProtocolAvailable())
                    {
                        if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
                        image = 3;
                        else
                        image = 1;
                    }
                    else
                    {
                        if (client->GetClientSoft() == SO_MLDONKEY)
                        {
                            if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
                            image = 6;
                            else
                            image = 5;
                        }
                        else if(client->GetClientSoft() == SO_EDONKEYHYBRID)
                        {
                            if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
                            image = 8;
                            else
                            image = 7;
                        }
                        else
                        {
                            if (client->Credits()->GetScoreRatio(client->GetIP()) > 1)
                            image = 2;
                            else
                            image = 0;
                        }
                    }
                    // Added Thief icon [BlackRat]
                    if (client->thief)
                    image = 9;
                    POINT point =
                    {
                        cur_rec.left, cur_rec.top + 1
                                        };
                    imagelist.Draw(image, *dc, cur_rec.left, cur_rec.top + 1, wxIMAGELIST_DRAW_TRANSPARENT);
                    //imagelist.Draw(dc,image, point, ILD_NORMAL);
                    Sbuffer.Printf("%s", client->GetUserName());
                    cur_rec.left += 20;
                    //dc->DrawText(Sbuffer,Sbuffer.GetLength(),&cur_rec,DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS);
                    dc->DrawText(Sbuffer, cur_rec.left, cur_rec.top + 3);
                    cur_rec.left -= 20;
                    break;
                }
            case 1:
                if (file)
                Sbuffer.Printf("%s", file->GetFileName());
                else
                Sbuffer = "?";
                break;
            case 2:
                // lagloose
                if (client->GetDownloadState() == DS_DOWNLOADING)
                {
                    Sbuffer = "";
                    rbuffer.Printf("%.1f", (float) client->GetDatarate() /1024);
                    Sbuffer.Append(rbuffer);
                    Sbuffer.Append("/");
                    rbuffer.Printf("%.1f %s", (float) client->GetDownloadDatarate() /1024, GetResString(IDS_KBYTESEC) .GetData());
                    Sbuffer.Append(rbuffer);
                }
                else
                {
                    Sbuffer.Printf("%.1f %s", (float) client->GetDatarate() /1024, GetResString(IDS_KBYTESEC) .GetData());
                }
                // end lagloose
                break;
            case 3:
                Sbuffer.Printf("%s", CastItoXBytes(client->GetSessionUp()) .GetData());
                break;
            case 4:
                Sbuffer.Printf("%s", CastSecondsToHM((client->GetWaitTime()) /1000) .GetData());
                break;
            case 5:
                Sbuffer.Printf("%s", CastSecondsToHM((client->GetUpStartTimeDelay()) /1000) .GetData());
                break;
            case 6:
                switch (client->GetUploadState())
                {
                case US_CONNECTING:
                    Sbuffer = GetResString(IDS_CONNECTING);
                    break;
                case US_WAITCALLBACK:
                    Sbuffer = GetResString(IDS_CONNVIASERVER);
                    break;
                case US_UPLOADING:
                    // lagloose
                    Sbuffer = "<-- ";
                    Sbuffer.Append(GetResString(IDS_TRANSFERRING));
                    if (client->GetDownloadState() == DS_DOWNLOADING)
                    {
                        Sbuffer.Append(" -->");
                    }
                    // Sbuffer = GetResString(IDS_TRANSFERRING);
                    // end lagloose
                    break;
                default:
                    Sbuffer = GetResString(IDS_UNKNOWN);
                }
                break;
            case 7:
                if (client->GetUpPartCount())
                {
                    wxMemoryDC memdc;
                    cur_rec.bottom--;
                    cur_rec.top++;
                    int iWidth = cur_rec.right - cur_rec.left;
                    int iHeight = cur_rec.bottom - cur_rec.top;
                    if (iWidth > 0 &&iHeight > 0)
                    {
                        // don't draw if it is too narrow
                        wxBitmap memBmp(iWidth, iHeight);
                        memdc.SelectObject(memBmp);
                        memdc.SetPen( *wxTRANSPARENT_PEN);
                        memdc.SetBrush( *wxWHITE_BRUSH);
                        memdc.DrawRectangle(wxRect(0, 0, iWidth, iHeight));
                        client->DrawUpStatusBar( &memdc, wxRect(0, 0, iWidth, iHeight), false, false);
                        dc->Blit(cur_rec.left, cur_rec.top, iWidth, iHeight, &memdc, 0, 0);
                        memdc.SelectObject(wxNullBitmap);
                    }
                    cur_rec.bottom++;
                    cur_rec.top--;
                }
                else
                {
                }
                break;
            }
            if (iColumn != 7 &&iColumn != 0)
            {
                //dc->DrawText(Sbuffer,Sbuffer.GetLength(),&cur_rec,DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS);
                dc->DrawText(Sbuffer, cur_rec.left, cur_rec.top + 3);
            }
            //GetColumnWidth(iColumn);:
            cur_rec.left += cx;
            delete clipper;
        }
    }
}

void CUploadListCtrl::ShowSelectedUserDetails()
{
    if (GetSelectedItemCount() > 0)
    {
        int sel = GetNextItem( - 1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        CUpDownClient *client = (CUpDownClient *) GetItemData(sel);
        if (client)
        {
            CClientDetailDialog dialog(this, client);
            dialog.ShowModal();
        }
    }
}

