/////////////////////////////////////////////////////////////////////////////
// Name:        proppanel_dependencies.cpp
// Purpose:     wxPackagePropertiesPanel
//              (stuff for handling the "depedencies" page)
// Author:      Francesco Montorsi
// Modified by:
// Created:     28/06/2006 19:22:47
// RCS-ID:      $Id: proppanel_dependencies.cpp,v 1.10 2007/01/29 23:26:51 frm Exp $
// Copyright:   (c) 2006 Julian Smart, 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/splitter.h>

#include "guipkg/proppanel.h"
#include "guipkg/depeditdlg.h"

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

#include "wx/miscutils.h"



// ----------------------------------------------------------------------------
// Global helpers
// ----------------------------------------------------------------------------

// some globals wxListCtrl helpers

wxPackageDependency &wxGetPackageDependencyFromListctrl(wxListCtrl *lc, unsigned int idx)
{ return *((wxPackageDependency *)lc->GetItemData(idx)); }

void wxUpdatePackageDependencyInListctrl(wxListCtrl *lc, unsigned int idx,
                                         const wxPackageDependency &dep)
{ wxGetPackageDependencyFromListctrl(lc, idx) = dep; }

void wxDeletePackageDependencyFromListctrl(wxListCtrl *lc, int idx)
{
    if (idx == -1)
    {
        while (lc->GetItemCount() > 0)
            wxDeletePackageDependencyFromListctrl(lc, 0);
    }
    else
    {
        // don't leak memory!
        delete ((wxPackageDependency*)lc->GetItemData(idx));
        lc->DeleteItem(idx);
    }
}

bool IsSelected(wxListCtrl *lc, int i)
{
    if (lc->GetItemState(i, wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED)
        return true;
    return false;
}

int GetSelection(wxListCtrl *lc)
{
    for (size_t i=0; i<(size_t)lc->GetItemCount(); i++)
        if (IsSelected(lc, i))
            return i;
    return wxNOT_FOUND;
}



// ----------------------------------------------------------------------------
// wxPackagePropertiesPanel - dependencies stuff - I/O
// ----------------------------------------------------------------------------

void wxPackagePropertiesPanel::InitDependenciesPage()
{
    m_pDepList->InsertColumn(0, wxT("Package name"), wxLIST_FORMAT_LEFT, 150);
    m_pDepList->InsertColumn(1, wxT("Version range"), wxLIST_FORMAT_LEFT, 150);
    m_pDepList->InsertColumn(2, wxT("Type"), wxLIST_FORMAT_LEFT, 150);

    // init supported/tested checklistboxes with a default version range
    for (size_t i=0; i<wxPORT_MAX; i++)
    {
        wxString name = wxPlatformInfo::GetPortIdName((wxPortId)(1 << i), false);
        m_pSupportedPorts->Append(name);
        m_pTestedPorts->Append(name);
    }

    // we don't need to call UpdatePortVersions() because we already added
    // to m_pSupportedPorts and m_pTestedPorts all strings correctly
}

void wxPackagePropertiesPanel::GetDependenciesPackageInfo(wxPackageInfo &ret) const
{
    // DEPENDENCIES info
    for (size_t i=0; i<m_pSupportedPorts->GetCount(); i++)
        if (m_pSupportedPorts->IsChecked(i))
            ret.AddSupportedPort((wxPortId)(1 << i), m_supportedVer[i]);
    for (size_t i=0; i<m_pTestedPorts->GetCount(); i++)
        if (m_pTestedPorts->IsChecked(i))
            ret.AddTestedPort((wxPortId)(1 << i), m_testedVer[i]);

    for (size_t i=0; i<(size_t)m_pDepList->GetItemCount(); i++)
        ret.AddDependency(wxGetPackageDependencyFromListctrl(m_pDepList, i));
}

void wxPackagePropertiesPanel::DoSetDependenciesPackageInfo(const wxPackageInfo &p)
{
    // DEPENDENCIES info
    wxFlags2CheckListBox(m_pSupportedPorts, p.GetSupportedPortFlag(), wxPORT_MAX);
    wxFlags2CheckListBox(m_pTestedPorts, p.GetTestedPortFlag(), wxPORT_MAX);
    for (size_t i=0,j=0; i<wxPORT_MAX; i++)
    {
        if (m_pSupportedPorts->IsChecked(i))
            m_supportedVer[i] = p.GetSupportedVersions().Item(j++);
        else
            m_supportedVer[i].Set(wxEmptyString);
    }
    for (size_t i=0,j=0; i<wxPORT_MAX; i++)
    {
        if (m_pTestedPorts->IsChecked(i))
            m_testedVer[i] = p.GetTestedVersions().Item(j++);
        else
            m_testedVer[i].Set(wxEmptyString);
    }
    UpdatePortVersions();

    // delete all existing dependency items before adding the new ones
    wxDeletePackageDependencyFromListctrl(m_pDepList, -1);
    for (size_t i=0; i<p.GetDependencies().GetCount(); i++)
    {
        wxPackageDependency dep = p.GetDependencies().Item(i);
        m_pDepList->InsertItem(i, dep.GetName());
        m_pDepList->SetItem(i, 1, dep.GetVersion().GetAsString());
        m_pDepList->SetItem(i, 2, dep.GetTypeStr());
        m_pDepList->SetItemData(i, (long)new wxPackageDependency(dep));
    }
}

bool wxPackagePropertiesPanel::IsDependenciesPageOk() const
{
    bool isok = true;

    if (wxCheckListBox2Flags(m_pSupportedPorts) == 0)
    {
        wxLogWarning(wxT("Please check at least one wxWidgets port as supported"));
        isok = false;
    }

    return isok;
}



// ----------------------------------------------------------------------------
// wxPackagePropertiesPanel - dependencies stuff
// ----------------------------------------------------------------------------

bool wxPackagePropertiesPanel::GetSupportedOrTestedVersionRange(bool issupported,
                                                                wxString *ret,
                                                                const wxString &portname,
                                                                const wxString &initial)
{
    wxString newver(initial);

    do
    {
        newver = wxGetTextFromUser(
                wxString::Format(_("Please enter the %s version range for %s."),
                                 issupported ? wxT("supported") : wxT("tested"),
                                 portname.c_str()),
                _("Edit version range"),
                newver,
                this);
        if (newver.IsEmpty())
            return false;     // user hit cancel

        // is the version valid ?
        if (!wxVersionRange(newver).IsOk())
            wxLogError(wxT("Invalid version range '%s'."), newver.c_str());
        else
            break;

    } while (1);

    if (ret) *ret = newver;
    return true;
}

bool wxPackagePropertiesPanel::GetDep(wxPackageDependency *ret,
                                      const wxPackageDependency &initial)
{
    wxPackageDependencyEditDlg dlg(this);
    dlg.SetDependency(initial);
    if (dlg.ShowModal() == wxID_OK)
    {
        if (ret) *ret = dlg.GetDependency();
        return true;
    }

    return false;
}

void wxPackagePropertiesPanel::UpdatePortVersions()
{
    // save currently checked ports
    long suppchecks = wxCheckListBox2Flags(m_pSupportedPorts);
    long testedchecks = wxCheckListBox2Flags(m_pTestedPorts);

    for (size_t i=0; i<wxPORT_MAX; i++)
    {
        wxString name = wxPlatformInfo::GetPortIdName((wxPortId)(1 << i), false);

        if (m_supportedVer[i].IsOk())
            m_pSupportedPorts->SetString(i, name + wxT(", ") + m_supportedVer[i].GetAsString());
        else
            m_pSupportedPorts->SetString(i, name);

        if (m_testedVer[i].IsOk())
            m_pTestedPorts->SetString(i, name + wxT(", ") + m_testedVer[i].GetAsString());
        else
            m_pTestedPorts->SetString(i, name);
    }

    // restore checked ports
    wxFlags2CheckListBox(m_pSupportedPorts, suppchecks, wxPORT_MAX);
    wxFlags2CheckListBox(m_pTestedPorts, testedchecks, wxPORT_MAX);
}

void wxPackagePropertiesPanel::SetPortVersion(int id)
{
    bool issupported = id == ID_PROP_SUPPORTEDPORTS ||
                       id == ID_PROP_QUICKSET_SUPPORTED_VERSIONS;
    wxCheckListBox *p = issupported ? m_pSupportedPorts : m_pTestedPorts;
    wxVersionRange *r = issupported ? m_supportedVer : m_testedVer;

    wxArrayInt sel;
    int n = p->GetSelections(sel);
    if (n == 0)
    {
        // this may happen on wxMSW's listboxes when they have > 0 items
        // and the user clicks on the empty space
        
        // if nothing is selected, consider all items selected:
        for (size_t i=0; i<p->GetCount(); i++)
            sel.Add(i);
    }

    wxString portname;
    wxString newver;

    // create the list of the ports where we need to set the version:
    if (p->GetCount() == sel.GetCount())
    {
        portname = wxT("all ports");
    }
    else
    {
        for (size_t i=0; i<sel.GetCount(); i++)
            portname += p->GetString(sel[i]).BeforeFirst(wxT(',')) + wxT(", ");
        portname.RemoveLast();
        portname.RemoveLast();

        portname = wxT("the ") + portname + 
                    (const wxChar*)(sel.GetCount() > 0 ? wxT("ports") : wxT("port"));
    }

    // get the initial version range to use from the first selected string
    wxString initialVer = r[sel[0]].GetAsString();

    if (GetSupportedOrTestedVersionRange(issupported, &newver, portname,
                                         initialVer))
    {
        wxASSERT(wxVersionRange(newver).IsOk());

        for (size_t i=0; i<sel.GetCount(); i++)
            r[sel[i]].Set(newver);
        UpdatePortVersions();
    }
}



// ----------------------------------------------------------------------------
// wxPackagePropertiesPanel - event handlers
// ----------------------------------------------------------------------------

void wxPackagePropertiesPanel::OnDependenciesListBoxDClick(wxCommandEvent &ev)
{
    OnUserChange();

    wxLogDebug(wxT("the top panel min size is: %d;%d\n"), 
                m_pTopPanel->GetMinSize().GetWidth(),
                m_pTopPanel->GetMinSize().GetHeight());


    switch (ev.GetId())
    {
        case ID_PROP_SUPPORTEDPORTS:
        case ID_PROP_TESTEDPORTS:
        {
            SetPortVersion(ev.GetId());
        }
        break;
    }
}

void wxPackagePropertiesPanel::OnDependenciesButton(wxCommandEvent &ev)
{
    OnUserChange();

    switch (ev.GetId())
    {
    case ID_PROP_NEW_DEP:
        {
            wxPackageDependency dep;
            if (GetDep(&dep))
            {
                int idx = m_pDepList->GetItemCount();
                m_pDepList->InsertItem(idx, dep.GetName());
                m_pDepList->SetItem(idx, 1, dep.GetVersion().GetAsString());
                m_pDepList->SetItem(idx, 2, dep.GetTypeStr());
                m_pDepList->SetItemData(idx, (long)new wxPackageDependency(dep));
            }
        }
        break;

    case ID_PROP_DELETE_DEP:
        wxDeletePackageDependencyFromListctrl(m_pDepList, GetSelection(m_pDepList));
        break;

    case ID_PROP_QUICKSET_SUPPORTED_VERSIONS:
    case ID_PROP_QUICKSET_TESTED_VERSIONS:
        SetPortVersion(ev.GetId());
        break;
    }
}

void wxPackagePropertiesPanel::OnDepDClick(wxListEvent &WXUNUSED(ev))
{
    int idx = GetSelection(m_pDepList);
    wxPackageDependency dep;
    if (GetDep(&dep, wxGetPackageDependencyFromListctrl(m_pDepList, idx)))
    {
        m_pDepList->SetItem(idx, 0, dep.GetName());
        m_pDepList->SetItem(idx, 1, dep.GetVersion().GetAsString());
        m_pDepList->SetItem(idx, 2, dep.GetTypeStr());
        wxUpdatePackageDependencyInListctrl(m_pDepList, idx, dep);
    }

    OnUserChange();
}

void wxPackagePropertiesPanel::OnDependenciesPageUpdateUI(wxUpdateUIEvent &WXUNUSED(ev))
{
    // controls with an interface which does not provide a wxControlWithItems::GetSelection()
    FindWindowById(ID_PROP_DELETE_DEP)->Enable(GetSelection(m_pDepList) != wxNOT_FOUND);
}
