/////////////////////////////////////////////////////////////////////////////
// Name:        taskpanel.cpp
// Purpose:     wxPackageTaskQueuePanel
// Author:      Francesco Montorsi
// Modified by:
// Created:     Fri 23 Jun 2006 14:45:00 CEST
// RCS-ID:      $Id: taskpanel.cpp,v 1.9 2007/02/01 22:00:54 frm Exp $
// Copyright:   (c) 2006 Francesco Montorsi
// Licence:     wxWidgets license
/////////////////////////////////////////////////////////////////////////////


// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/artprov.h>
#include <wx/image.h>

#include "guicmn/guiutils.h"
#include "guipm/taskpanel.h"
#include "guipm/extcmdprogresspanel.h"
#include "guipm/downloadprogresspanel.h"
#include "guipm/logdlg.h"

// NB: on GTK we will use some GTK stock icons
#include "bitmaps/play.xpm"
#include "bitmaps/stop.xpm"
#include "bitmaps/delete.xpm"


// ----------------------------------------------------------------------------
// wxPackageTaskQueuePanel
// ----------------------------------------------------------------------------

BEGIN_EVENT_TABLE( wxPackageTaskQueuePanel, wxPanel )
    EVT_IDLE(wxPackageTaskQueuePanel::OnIdle)

    // buttons for the queued build staticbox
    EVT_BUTTON(ID_TASK_START, wxPackageTaskQueuePanel::OnStart)
    EVT_BUTTON(ID_TASK_STOP, wxPackageTaskQueuePanel::OnStop)
    EVT_BUTTON(ID_TASK_DELETEQUEUED, wxPackageTaskQueuePanel::OnDeleteQueuedBuild)

    // buttons for the completed build staticbox
    EVT_BUTTON(ID_TASK_SHOWLOG, wxPackageTaskQueuePanel::OnShowLog)
    EVT_BUTTON(ID_TASK_DELETECOMPLETED, wxPackageTaskQueuePanel::OnDeleteCompletedBuild)

    EVT_UPDATE_UI( wxID_ANY, wxPackageTaskQueuePanel::OnUpdateUI )

    // messages from our subpanel:
    EVT_PROGRESS_FAILED(wxID_ANY, wxPackageTaskQueuePanel::OnProgressPanelFailed)
    EVT_PROGRESS_END(wxID_ANY, wxPackageTaskQueuePanel::OnProgressPanelEnd)

END_EVENT_TABLE()

wxPackageTaskQueuePanel::wxPackageTaskQueuePanel( )
{
}

wxPackageTaskQueuePanel::wxPackageTaskQueuePanel( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    Create(parent, id, caption, pos, size, style);
}

bool wxPackageTaskQueuePanel::Create( wxWindow* parent, wxWindowID id, const wxString&, const wxPoint& pos, const wxSize& size, long style )
{
////@begin wxPackageTaskQueuePanel member initialisation
    m_pQueuedList = NULL;
    m_pStartBtn = NULL;
    m_pStopBtn = NULL;
    m_pDeleteQueuedBtn = NULL;
    m_pCompletedList = NULL;
    m_pShowLogBtn = NULL;
    m_pDeleteCompletedBtn = NULL;
////@end wxPackageTaskQueuePanel member initialisation

////@begin wxPackageTaskQueuePanel creation
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
    wxPanel::Create( parent, id, pos, size, style );

    CreateControls();
    if (GetSizer())
    {
        GetSizer()->SetSizeHints(this);
    }
    Centre();
////@end wxPackageTaskQueuePanel creation
    return true;
}

void wxPackageTaskQueuePanel::CreateControls()
{
    m_pProgressEndHandler = NULL;
    CreateProgressPanel();

////@NOREGENbegin wxPackageTaskQueuePanel content construction
    wxPackageTaskQueuePanel* itemPanel1 = this;

    wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
    itemPanel1->SetSizer(itemBoxSizer2);

    wxBoxSizer* itemBoxSizer3 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer2->Add(itemBoxSizer3, 1, wxGROW, 5);

    wxStaticBox* itemStaticBoxSizer4Static = new wxStaticBox(itemPanel1, wxID_ANY, _("Queued operations"));
    wxStaticBoxSizer* itemStaticBoxSizer4 = new wxStaticBoxSizer(itemStaticBoxSizer4Static, wxHORIZONTAL);
    itemBoxSizer3->Add(itemStaticBoxSizer4, 1, wxGROW|wxALL, 5);

    m_pQueuedList = new wxTaskListBox( itemPanel1, ID_TASK_QUEUED, wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticBoxSizer4->Add(m_pQueuedList, 1, wxGROW|wxLEFT|wxTOP|wxBOTTOM, 5);

    wxBoxSizer* itemBoxSizer6 = new wxBoxSizer(wxVERTICAL);
    itemStaticBoxSizer4->Add(itemBoxSizer6, 0, wxGROW, 5);

    wxBitmap m_pStartBtnBitmap(itemPanel1->GetBitmapResource(wxT("play")));
    m_pStartBtn = new wxBitmapButton( itemPanel1, ID_TASK_START, m_pStartBtnBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
    if (ShowToolTips())
        m_pStartBtn->SetToolTip(_("Start building queued packages"));
    itemBoxSizer6->Add(m_pStartBtn, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    wxBitmap m_pStopBtnBitmap(itemPanel1->GetBitmapResource(wxT("stop")));
    m_pStopBtn = new wxBitmapButton( itemPanel1, ID_TASK_STOP, m_pStopBtnBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
    if (ShowToolTips())
        m_pStopBtn->SetToolTip(_("Stop building queued packages"));
    itemBoxSizer6->Add(m_pStopBtn, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxBitmap m_pDeleteQueuedBtnBitmap(itemPanel1->GetBitmapResource(wxT("delete")));
    m_pDeleteQueuedBtn = new wxBitmapButton( itemPanel1, ID_TASK_DELETEQUEUED, m_pDeleteQueuedBtnBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
    if (ShowToolTips())
        m_pDeleteQueuedBtn->SetToolTip(_("Delete selected build from queue"));
    itemBoxSizer6->Add(m_pDeleteQueuedBtn, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxStaticBox* itemStaticBoxSizer10Static = new wxStaticBox(itemPanel1, wxID_ANY, _("Completed operations"));
    wxStaticBoxSizer* itemStaticBoxSizer10 = new wxStaticBoxSizer(itemStaticBoxSizer10Static, wxHORIZONTAL);
    itemBoxSizer3->Add(itemStaticBoxSizer10, 1, wxGROW|wxALL, 5);

    m_pCompletedList = new wxTaskListBox( itemPanel1, ID_TASK_COMPLETED, wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticBoxSizer10->Add(m_pCompletedList, 1, wxGROW|wxLEFT|wxTOP|wxBOTTOM, 5);

    wxBoxSizer* itemBoxSizer12 = new wxBoxSizer(wxVERTICAL);
    itemStaticBoxSizer10->Add(itemBoxSizer12, 0, wxGROW, 5);

    wxBitmap m_pShowLogBtnBitmap(itemPanel1->GetBitmapResource(wxT("showlog")));
    m_pShowLogBtn = new wxBitmapButton( itemPanel1, ID_TASK_SHOWLOG, m_pShowLogBtnBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
    if (ShowToolTips())
        m_pShowLogBtn->SetToolTip(_("Show log of selected build"));
    itemBoxSizer12->Add(m_pShowLogBtn, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    wxBitmap m_pDeleteCompletedBtnBitmap(itemPanel1->GetBitmapResource(wxT("delete")));
    m_pDeleteCompletedBtn = new wxBitmapButton( itemPanel1, ID_TASK_DELETECOMPLETED, m_pDeleteCompletedBtnBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
    if (ShowToolTips())
        m_pDeleteCompletedBtn->SetToolTip(_("Delete selected build from list"));
    itemBoxSizer12->Add(m_pDeleteCompletedBtn, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT|wxBOTTOM, 5);

    wxStaticBox* itemStaticBoxSizer15Static = new wxStaticBox(itemPanel1, wxID_ANY, _("Current operation"));
    wxStaticBoxSizer* itemStaticBoxSizer15 = new wxStaticBoxSizer(itemStaticBoxSizer15Static, wxVERTICAL);

    // hand-edited GetCurrentOperationProportion()
    itemBoxSizer2->Add(itemStaticBoxSizer15, GetCurrentOperationProportion(), wxGROW|wxALL, 5);

    wxWindow* itemWindow16 = (wxWindow*) FindWindow(ID_TASK_CURRENT);
    wxASSERT( itemWindow16 != NULL );
    itemStaticBoxSizer15->Add(itemWindow16, 1, wxGROW, 5);

////@NOREGENend wxPackageTaskQueuePanel content construction

    m_bUserStopped = false;
}

void wxPackageTaskQueuePanel::RemoveFirstQueuedPackage()
{
    m_arrQueue.RemoveAt(0);

    m_pQueuedList->Delete(0);
    m_pQueuedList->RefreshAll();
}

void wxPackageTaskQueuePanel::Stop()
{
    m_pProgressPanel->Stop();

    // prepend an item to the completed list
    m_pCompletedList->Prepend(m_currentBuild,
                              m_pProgressPanel->GetLogData(),
                              m_pProgressPanel->GetLogLabel(),
                              m_pProgressPanel->IsSuccessful());
    m_pCompletedList->RefreshAll();

    m_pProgressPanel->ClearControls();
}

void wxPackageTaskQueuePanel::Start()
{
    if (m_arrQueue.GetCount() == 0 ||
        m_pProgressPanel->IsProcessing())
        return;

    // we have a queue but we are not building!
    m_pProgressPanel->SetPackage(m_arrQueue[0]);

    // before removing first queued package, save its name in m_currentBuild
    m_currentBuild = m_pQueuedList->GetString(0);
    m_pQueuedList->SetTaskInProgress(0);

    // go!
    m_pProgressPanel->Start();
}

bool wxPackageTaskQueuePanel::ShowToolTips()
{
    return true;
}

wxBitmap wxPackageTaskQueuePanel::GetBitmapResource( const wxString& name )
{
    wxImage bitmap;

    if (name == _T("play"))
        bitmap = wxGetImageFromXPM_or_GTK2Stock(play_xpm, "gtk-media-play");
    else if (name == _T("stop"))
        bitmap = wxGetImageFromXPM_or_GTK2Stock(stop_xpm, "gtk-media-stop");
    else if (name == _T("delete"))
        bitmap = wxGetImageFromXPM_or_GTK2Stock(delete_xpm, "gtk-stop");
    else if (name == _T("showlog"))
        bitmap = wxGetImageFromArtProvider_or_GTK2Stock(wxART_INFORMATION, "gtk-dialog-info");

    if (bitmap.IsOk())
    {
        bitmap.Rescale(ID_TASK_BITMAP_SIZE.GetWidth(), 
                       ID_TASK_BITMAP_SIZE.GetHeight(),
                       wxIMAGE_QUALITY_HIGH);
    }

    return wxBitmap(bitmap);
}

void wxPackageTaskQueuePanel::OnQueueTask()
{
    // clear the user stopped flag so that if some error blocked the previous
    // operations, the just-queued ones won't be blocked
    m_bUserStopped = false;
}



// ----------------------------------------------------------------------------
// wxPackageTaskQueuePanel - event handlers
// ----------------------------------------------------------------------------

void wxPackageTaskQueuePanel::OnProgressPanelEnd(wxCommandEvent &ev)
{
    RemoveFirstQueuedPackage();
    Stop();

    if (m_pProgressEndHandler)
        m_pProgressEndHandler->AddPendingEvent(ev);
}

void wxPackageTaskQueuePanel::OnProgressPanelFailed(wxCommandEvent &ev)
{
    OnProgressPanelEnd(ev);

    // IMPORTANT: mark this aborted operation as user-aborted
    //            otherwise on the next idle cycle we
    //            will try to start it again
    m_bUserStopped = true;
}

void wxPackageTaskQueuePanel::OnIdle(wxIdleEvent &WXUNUSED(ev))
{
    // try to start a build, if there's any...
    if (!m_bUserStopped) Start();
}

void wxPackageTaskQueuePanel::OnUpdateUI(wxUpdateUIEvent & WXUNUSED(ev))
{
    m_pStartBtn->Enable(m_arrQueue.GetCount() > 0 &&
                        !m_pProgressPanel->IsProcessing());
    m_pStopBtn->Enable(m_arrQueue.GetCount() > 0 &&
                    !m_pStartBtn->IsEnabled());

    m_pDeleteQueuedBtn->Enable(m_pQueuedList->GetSelection() != wxNOT_FOUND);
    m_pShowLogBtn->Enable(m_pCompletedList->GetSelection() != wxNOT_FOUND);
    m_pDeleteCompletedBtn->Enable(m_pCompletedList->GetSelection() != wxNOT_FOUND);
}

void wxPackageTaskQueuePanel::OnStart(wxCommandEvent &WXUNUSED(ev))
{
    Start();
    m_bUserStopped = false;
}

void wxPackageTaskQueuePanel::OnStop(wxCommandEvent &)
{
    Stop();
    m_bUserStopped = true;
}

void wxPackageTaskQueuePanel::OnDeleteQueuedBuild(wxCommandEvent &)
{
    int n = m_pQueuedList->GetSelection();
    wxASSERT(n != wxNOT_FOUND);
    m_pQueuedList->Delete(n);
    m_pQueuedList->RefreshAll();
}

void wxPackageTaskQueuePanel::OnShowLog(wxCommandEvent &)
{
    int n = m_pCompletedList->GetSelection();
    wxASSERT(n != wxNOT_FOUND);

    wxPackageLogDlg dlg(this, wxID_ANY,
                        wxT("Log for ") + m_pCompletedList->GetString(n));
    dlg.SetLog(m_pCompletedList->GetLog(n));
    dlg.SetLabel(m_pCompletedList->GetLogLabel(n));
    dlg.ShowModal();
}

void wxPackageTaskQueuePanel::OnDeleteCompletedBuild(wxCommandEvent &)
{
    int n = m_pCompletedList->GetSelection();
    wxASSERT(n != wxNOT_FOUND);
    m_pCompletedList->Delete(n);
    m_pCompletedList->RefreshAll();
}



// ----------------------------------------------------------------------------
// wxPackageDownloadQueuePanel
// ----------------------------------------------------------------------------

wxPackageDownloadQueuePanel::wxPackageDownloadQueuePanel( 
    wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, 
    const wxSize& size, long style )
{
    Create(parent, id, caption, pos, size, style);
}

bool wxPackageDownloadQueuePanel::CreateProgressPanel()
{
    m_pProgressPanel = new wxDownloadProgressPanel(this, ID_TASK_CURRENT);
    return true;
}

void wxPackageDownloadQueuePanel::QueueDownloadOf(const wxPackage &pkg)
{
    OnQueueTask();

    m_arrQueue.Add(pkg);
    m_pQueuedList->Append(wxT("Download of ") + pkg.GetName());
    m_pQueuedList->RefreshAll();
}

void wxPackageDownloadQueuePanel::QueueDownloadOf(const wxPackageArray &arr)
{
    OnQueueTask();

    for (size_t i=0; i<arr.GetCount(); i++)
    {
        m_arrQueue.Add(arr[i]);
        m_pQueuedList->Append(wxT("Download of ") + arr[i].GetName());
    }

    // we don't use QueueDownloadOf(const wxPackage &pkg) just to be able
    // to the following optimization: 1 single call to RefreshAll()
    m_pQueuedList->RefreshAll();
}



// ----------------------------------------------------------------------------
// wxPackageCommandQueuePanel
// ----------------------------------------------------------------------------

wxPackageCommandQueuePanel::wxPackageCommandQueuePanel( 
    wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, 
    const wxSize& size, long style )
{
    Create(parent, id, caption, pos, size, style);
}

bool wxPackageCommandQueuePanel::CreateProgressPanel()
{
    m_pProgressPanel = new wxExtCmdProgressPanel(this, ID_TASK_CURRENT);
    wxStaticCast(m_pProgressPanel, wxExtCmdProgressPanel)->SetStage(wxPBSS_BUILD);
    return true;
}

void wxPackageCommandQueuePanel::QueueBuildOf(const wxPackage &pkg)
{
    OnQueueTask();

    m_arrQueue.Add(pkg);
    m_pQueuedList->Append(
        wxString::Format(wxT("Build of %s <small>[%s]</small>"),
        pkg.GetName().c_str(), wxDateTime::Now().FormatTime().c_str()));
    m_pQueuedList->RefreshAll();
}


// ----------------------------------------------------------------------------
// wxTaskListBox
// ----------------------------------------------------------------------------

wxTaskListBox::wxTaskListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
                            const wxSize& size, long style, const wxString& name)
{
    // create base class
    wxHtmlListBox::Create(parent, id, pos, size, style|wxSUNKEN_BORDER, name);
    //SetSelectionBackground(wxColour(wxT("DARK GREEN")));
    SetMargins(1, 1);

    m_nInProgress = -1;
}
/*
void wxTaskListBox::OnDrawSeparator(wxDC& dc, wxRect& rect, size_t) const
{
    dc.SetPen(*wxBLACK_PEN);
    dc.DrawLine(rect.GetLeft(), rect.GetBottom(), rect.GetRight(), rect.GetBottom());
}*/

wxString wxTaskListBox::OnGetItem(size_t n) const
{
    if (m_success[n] == -1)
    {
        if ((size_t)m_nInProgress == n)
            return wxT("<b>=&gt; ") + m_items[n] + wxT(" &lt;=</b>");
        return wxString::Format(wxT("#%d:&nbsp;&nbsp;"), n+1) + m_items[n];
    }

    // we know if this task was successful or not
    wxString img = m_success[n] == 1 ? wxT("memory:tickmark") : wxT("memory:crossmark");
    return wxString::Format(wxT("<img src='%s'/>&nbsp;&nbsp;&nbsp;%s"),
                            img.c_str(), m_items[n].c_str());
}

wxString wxTaskListBox::OnGetItemMarkup(size_t n) const
{
    wxString str(OnGetItem(n));
    if (m_success[n] == -1)
        return str;

    // NB: to set the background colour of this item we should
    //     use the <table><tr><td> tags and the result would not
    //     be very good so we prefer to mark the success using the
    //     colour of the text (and the icon next to it)
    return wxString::Format(wxT("<font color='%s'><b>%s</b></font>"),
        m_success[n] == 1 ? wxT("#00AA00") : wxT("red"),
        str.c_str());
}

/*
wxColour wxTaskListBox::GetSelectedTextColour(const wxColour& colFg) const
{
    return wxHtmlListBox::GetSelectedTextColour(colFg);
}*/
void wxTaskListBox::Delete(unsigned int n)
{
    m_items.RemoveAt(n);
    m_logs.RemoveAt(n);
    m_success.RemoveAt(n);

    if (n == (unsigned)m_nInProgress)
        m_nInProgress = -1;

    SetItemCount(m_items.GetCount());
}

