/////////////////////////////////////////////////////////////////////////////
// Name:        dependencydlg.cpp
// Purpose:     wxPackageDependencyDlg
// Author:      Francesco Montorsi
// Modified by:
// Created:     29/07/2006 09:48:04
// RCS-ID:      $Id: dependencydlg.cpp,v 1.2 2007/01/01 20:06:21 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/statline.h>

#include "guipm/dependencydlg.h"
#include "guipm/smartmsgdlg.h"
#include "guipm/taskpanel.h"

#include "wxp/packagedep.h"
#include "wxp/package.h"



// ----------------------------------------------------------------------------
// wxPackageDependencyDlg
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS( wxPackageDependencyDlg, wxDialog )
BEGIN_EVENT_TABLE( wxPackageDependencyDlg, wxDialog )
    EVT_BUTTON(wxID_ANY, wxPackageDependencyDlg::OnButton)
END_EVENT_TABLE()

wxPackageDependencyDlg::wxPackageDependencyDlg( )
{
}

bool wxPackageDependencyDlg::Create( wxWindow* parent, wxWindowID id, const wxString& caption,
                                     const wxPoint& pos, const wxSize& size, long style )
{
////@begin wxPackageDependencyDlg member initialisation
    m_pMainMsg = NULL;
    m_pRequiredCheckList = NULL;
    m_pSuggestedCheckList = NULL;
    m_pQuestionMsg = NULL;
////@end wxPackageDependencyDlg member initialisation

////@begin wxPackageDependencyDlg creation
    SetExtraStyle(GetExtraStyle()|wxWS_EX_BLOCK_EVENTS);
    wxDialog::Create( parent, id, caption, pos, size, style );

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

void wxPackageDependencyDlg::CreateControls()
{
    wxASSERT_MSG(!IsEmpty(), wxT("Cannot build an empty dialog!"));

////@NOREGENbegin wxPackageDependencyDlg content construction
    wxPackageDependencyDlg* itemDialog1 = this;

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


    if (m_required.GetCount() > 0)
    {
        wxString msg;

        if (m_bSelectedPackagesAreDownloaded)
            msg = _("In order to be able to successfully build the selected package(s),\nyou should download and install also the following REQUIRED packages:");
        else
            msg = _("In order to be able to successfully build the selected package(s), after the download,\nyou should download and install also the following REQUIRED packages:");

        m_pMainMsg = new wxStaticText( itemDialog1, wxID_STATIC,
            msg, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE );
        itemBoxSizer2->Add(m_pMainMsg, 0, wxGROW|wxALL|wxADJUST_MINSIZE, 5);

        wxString* m_pRequiredCheckListStrings = NULL;
        m_pRequiredCheckList = new wxCheckListBox( itemDialog1, ID_DEPENDENCY_REQUIRED_LIST, wxDefaultPosition, wxDefaultSize, 0, m_pRequiredCheckListStrings, wxLB_SINGLE );
        itemBoxSizer2->Add(m_pRequiredCheckList, 0, wxGROW|wxALL, 5);
    }

    if (m_suggested.GetCount() > 0)
    {
        wxStaticText* itemStaticText5 = new wxStaticText( itemDialog1, wxID_STATIC,
            _("The selected package(s) indicate, as SUGGESTED dependencies, the following package(s), too:"), wxDefaultPosition, wxDefaultSize, 0 );
        itemBoxSizer2->Add(itemStaticText5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxADJUST_MINSIZE, 5);

        wxString* m_pSuggestedCheckListStrings = NULL;
        m_pSuggestedCheckList = new wxCheckListBox( itemDialog1, ID_DEPENDENCY_SUGGESTED_LIST, wxDefaultPosition, wxDefaultSize, 0, m_pSuggestedCheckListStrings, wxLB_SINGLE );
        itemBoxSizer2->Add(m_pSuggestedCheckList, 0, wxGROW|wxALL, 5);
    }

    if (m_notfound.GetCount() > 0)
    {
        itemBoxSizer2->Add(new wxStaticLine(this, wxID_ANY), 0, wxGROW|wxALL, 5);

        wxStaticText* itemStaticText7 = new wxStaticText( itemDialog1, wxID_STATIC,
            _("WARNING: the selected package(s) indicate the following REQUIRED or SUGGESTED dependencies \nwhich could not be found in the repository:"), wxDefaultPosition, wxDefaultSize, 0 );
        itemBoxSizer2->Add(itemStaticText7, 0, wxGROW|wxALL|wxADJUST_MINSIZE, 5);

        wxString* itemListBox8Strings = NULL;
        m_pNotFoundList = new wxListBox( itemDialog1, ID_DEPENDENCY_NOTINREPO, wxDefaultPosition, wxDefaultSize, 0, itemListBox8Strings, wxLB_SINGLE );
        itemBoxSizer2->Add(m_pNotFoundList, 0, wxGROW|wxALL, 5);
    }

    m_pQuestionMsg = new wxStaticText( itemDialog1, wxID_STATIC, _("Proceed with the download of the checked package(s) ?"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer2->Add(m_pQuestionMsg, 0, wxALIGN_LEFT|wxALL|wxADJUST_MINSIZE, 5);

    itemBoxSizer2->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    wxStdDialogButtonSizer* itemStdDialogButtonSizer11 = new wxStdDialogButtonSizer;

    itemBoxSizer2->Add(itemStdDialogButtonSizer11, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
    wxButton* itemButton12 = new wxButton( itemDialog1, wxID_YES, _("&Yes"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStdDialogButtonSizer11->AddButton(itemButton12);

    wxButton* itemButton13 = new wxButton( itemDialog1, wxID_NO, _("&No"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStdDialogButtonSizer11->AddButton(itemButton13);

    itemStdDialogButtonSizer11->Realize();

////@NOREGENend wxPackageDependencyDlg content construction

    // init listboxes
    FillListbox(m_pRequiredCheckList, m_required);
    FillListbox(m_pSuggestedCheckList, m_suggested);
    FillListbox(m_pNotFoundList, m_notfound, true);
}

void wxPackageDependencyDlg::FillListbox(wxListBox *box,
                                         const wxPackageDependencyArray &arr,
                                         bool useversionrange)
{
    for (size_t i=0; i<arr.GetCount(); i++)
    {
        wxString ver;

        if (useversionrange)
            ver = arr[i].GetVersion().GetAsString();
        else
        {
            int n = arr[i].GetBestMatch(*m_pRemote);
            wxASSERT(n != wxNOT_FOUND);
            ver = m_pRemote->Item(n).GetVersion().GetAsString();
        }

        int last =
            box->Append(wxString::Format(wxT("%s %s (required by %s)"),
                                         arr[i].GetName().c_str(),
                                         ver.c_str(),
                                         arr[i].GetOwnersIdStr().c_str()));

        wxCheckListBox *cb = wxDynamicCast(box, wxCheckListBox);
        if (cb)
            cb->Check(last, true);
    }
}

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

bool wxPackageDependencyDlg::SetPackageArray(const wxPackageArray &arr,
                                             const wxPackageArray &installed,
                                             const wxPackageArray &remote)
{
    // these info are required later by other
    // functions of wxPackageDependencyDlg:
    m_pRemote = &remote;

    m_bSelectedPackagesAreDownloaded = true;
    for (size_t i=0; i < arr.GetCount(); i++)
    {
        if (arr[i].GetStatus() == wxPS_REMOTE)
        {
            m_bSelectedPackagesAreDownloaded = false;
            break;
        }
    }

    m_required.Clear();
    m_suggested.Clear();
    m_notfound.Clear();

    // build the complete list of packages that we can use
    // for dependency resolution:
    wxPackageArray total(installed);
    WX_APPEND_ARRAY(total, remote);

    // FIXME: it would be better to use a AppendWithoutDuplicates()
    //        instead of WX_APPEND_ARRAY
    total.RemoveDuplicates();

    // get info about dependencies of selected packages
    wxPackageDependencyArray dep;
    arr.GetRecursiveDependencies(&dep, total, wxPDT_INVALID, &m_notfound);
    //dep.Dump();

    // are there conflicting dep ?
    wxPackageDependencyArray temp(dep.GetConflictingDependencies());
    if (temp.GetCount() > 0)
    {
        wxString list;
        for (size_t i=0; i<temp.GetCount(); i++)
            list += wxString::Format(wxT("%s requires version %s of %s\n"),
                        temp[i].GetOwnersIdStr().c_str(),
                        temp[i].GetVersion().GetAsString().c_str(),
                        temp[i].GetName().c_str());

        if (wxSmartLogYesNoQuestion(
                wxT("depconflict"),
                _("There are conflicting dependencies:\n\n%s\nShould I ignore them and proceed ?"),
                list.c_str()) == wxID_NO)
            return false;
    }

    dep = dep.GetDependenciesNotAvailableIn(installed);
    m_required = dep.GetDependenciesOfType(wxPDT_REQUIRED);
    m_suggested = dep.GetDependenciesOfType(wxPDT_SUGGESTED);

    if (!m_notfound.IsEmpty() && m_required.IsEmpty() && m_suggested.IsEmpty())
    {
        // building a wxPackageDependencyDlg does not make much sense in this
        // case (since it contains yes/no buttons and in this case there are
        // no sensed questions!)

        wxString list;
        for (size_t i=0; i<m_notfound.GetCount(); i++)
            list += m_notfound[i].GetName() + wxT(",");
        list.RemoveLast();

        wxString msg;
        if (arr.GetCount() > 1)
            msg = _("The selected packages, or the packages they depend from, have dependencies from the\n\n     %s\n\npackages, which are not in the repository!\nShould I ignore them and proceed ?");
        else
            msg = _("The selected package, or the packages it depends from, has dependencies from the\n\n     %s\n\npackages, which are not in the repository!\nShould I ignore them and proceed ?");

        if (wxSmartLogYesNoQuestion(
                wxT("ignoredep"),
                msg,
                list.c_str()) == wxID_NO)
            return false;

        // ignore missing packages (and make IsEmpty() return true
        // so that the Create() function of this dialog cannot be called)
        m_notfound.Clear();
    }

    return true;
}

bool wxPackageDependencyDlg::SetPackage(const wxPackage &pkg,
                                        const wxPackageArray &installed,
                                        const wxPackageArray &remote)
{
    wxPackageArray temp;
    temp.Add(pkg);
    return SetPackageArray(temp, installed, remote);
}

void wxPackageDependencyDlg::QueueAdditionalPackages(wxPackageDependencyType type,
                                                     wxPackageDownloadQueuePanel *panel)
{
    wxPackageArray arr = GetAdditionalPackages(type);
    panel->QueueDownloadOf(arr);
}

wxPackageArray wxPackageDependencyDlg::GetAdditionalPackages(wxPackageDependencyType t) const
{
    wxPackageArray req, sugg;

    switch (t)
    {
    case wxPDT_REQUIRED:
        return GetPackagesFromCheckListbox(m_pRequiredCheckList, m_required);

    case wxPDT_SUGGESTED:
        return GetPackagesFromCheckListbox(m_pSuggestedCheckList, m_suggested);

    default:
        req = GetPackagesFromCheckListbox(m_pRequiredCheckList, m_required);
        sugg = GetPackagesFromCheckListbox(m_pSuggestedCheckList, m_suggested);
        WX_APPEND_ARRAY(req, sugg);
        return req;
    }
}

wxPackageArray wxPackageDependencyDlg::GetPackagesFromCheckListbox(wxCheckListBox *box,
                                           const wxPackageDependencyArray &arr) const
{
    wxPackageArray ret;

    for (size_t i=0; i<arr.GetCount(); i++)
    {
        if (box->IsChecked(i))
        {
            int n = arr[i].GetBestMatch(*m_pRemote);
            wxASSERT(n != wxNOT_FOUND);

            ret.Add(m_pRemote->Item(n));
        }
    }

    return ret;
}


// ----------------------------------------------------------------------------
// wxPackageDependencyDlg - event handlers
// ----------------------------------------------------------------------------

void wxPackageDependencyDlg::OnButton(wxCommandEvent &ev)
{
    // ev.GetId() should be wxID_YES or wxID_NO
    switch (ev.GetId())
    {
    case wxID_YES:
        {
            wxPackageArray arr = GetAdditionalPackages();
            if (wxWidgetsBuildArray::s_arrWxBuilds.GetCount() > 0)
            {
                // do wxWidgets dependency check without checking the compiler
                // as we are not in build stage yet

                for (size_t i=0; i < arr.GetCount(); i++)
                {
                    if (arr[i].GetSupportedWxBuilds(false).IsEmpty())
                    {
                        wxLogWarning(wxT("The package '%s' does not support any of the installed wxWidgets ports/versions!\nCannot proceed."),
                                    arr[i].GetName().c_str());
                        return;
                    }
                }
            }
            else
            {
                // DO NOT USE wxLogMessage here - it could be shown
                // *after* the download dialog!
                wxSmartLogWarning(
                    wxT("nowxbuilds"),
                    _("You have not defined any wxWidgets build installed on this system.\nThe wxWidgets ports/versions compatibility check will be skipped!\n\nNote: you can modify the list of installed wxWidgets builds in the Settings -> wxWidgets panel."));
            }
        }

        EndModal(wxID_YES);
        break;

    default:
        EndModal(wxID_NO);
        break;
    }
}


