/////////////////////////////////////////////////////////////////////////////
// Name:        extcmdoptionspanel.cpp
// Purpose:     wxExtCmdOptionsPanel
// Author:      Julian Smart, Francesco Montorsi
// Modified by:
// Created:     15/06/2006 21:21:22
// RCS-ID:      $Id: extcmdoptionspanel.cpp,v 1.7 2007/02/01 23:00:16 frm Exp $
// Copyright:   (c) 2004 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 "guipm/extcmdoptionspanel.h"
#include "guipm/opteditctrl.h"
#include "guipm/smartmsgdlg.h"
#include "guipm/wxbuildpropdlg.h"

#include "guicmn/commandlistbox.h"


// ----------------------------------------------------------------------------
// wxExtCmdOptionsPanel
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS( wxExtCmdOptionsPanel, wxPanel )
BEGIN_EVENT_TABLE( wxExtCmdOptionsPanel, wxPanel )
    EVT_OPTIONS_CHANGED(ID_EXTCMD_OPTIONS, wxExtCmdOptionsPanel::OnOptionChanged)
    EVT_CHOICE(ID_EXTCMD_WXBUILD, wxExtCmdOptionsPanel::OnWxBuildChanged)
    EVT_CHOICE(ID_EXTCMD_TARGET, wxExtCmdOptionsPanel::OnTargetChanged)
    EVT_CHECKBOX(ID_EXTCMD_ONLYCHANGED, wxExtCmdOptionsPanel::OnOnlyChanged)

    EVT_BUTTON(ID_EXTCMD_RESET, wxExtCmdOptionsPanel::OnReset)
    EVT_BUTTON(ID_EXTCMD_EDIT, wxExtCmdOptionsPanel::OnEditWxBuild)

    EVT_UPDATE_UI(wxID_ANY, wxExtCmdOptionsPanel::OnUpdateUI)
END_EVENT_TABLE()


wxExtCmdOptionsPanel::wxExtCmdOptionsPanel( )
{
}

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

bool wxExtCmdOptionsPanel::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos,
                                   const wxSize& size, long style, const wxString &name )
{
    wxPanel::Create( parent, id, pos, size, style, name );

    CreateControls();
    GetSizer()->SetSizeHints(this);
    //SetMinSize(wxSize(GetMinSize().GetWidth()*1.5, GetMinSize().GetHeight()*1.5));
    GetSizer()->Fit(this);
    Centre();

    return true;
}

void wxExtCmdOptionsPanel::CreateControls()
{
    // custom controls
    m_pOptionsList = new wxOptionEditorCtrl(this, ID_EXTCMD_OPTIONS);
    m_pCommandList = new wxCommandListBox(this, ID_EXTCMD_COMMANDS);

////@begin wxExtCmdOptionsPanel content construction
    wxExtCmdOptionsPanel* itemPanel1 = this;

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

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

    m_pLabel1 = new wxStaticText( itemPanel1, wxID_STATIC, _("%STAGE% options:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer3->Add(m_pLabel1, 1, wxALIGN_BOTTOM|wxALL|wxADJUST_MINSIZE, 5);

    wxButton* itemButton5 = new wxButton( itemPanel1, ID_EXTCMD_RESET, _("Reset to defaults"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer3->Add(itemButton5, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5);

    wxWindow* itemWindow6 = (wxWindow*) FindWindow(ID_EXTCMD_OPTIONS);
    wxASSERT( itemWindow6 != NULL );
    itemBoxSizer2->Add(itemWindow6, 5, wxGROW|wxALL, 5);

    wxBoxSizer* itemBoxSizer7 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer2->Add(itemBoxSizer7, 0, wxGROW, 5);

    wxStaticText* itemStaticText8 = new wxStaticText( itemPanel1, wxID_STATIC, _("wxWidgets build to use:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer7->Add(itemStaticText8, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);

    wxString* m_pSelBuildStrings = NULL;
    m_pSelBuild = new wxChoice( itemPanel1, ID_EXTCMD_WXBUILD, wxDefaultPosition, wxDefaultSize, 0, m_pSelBuildStrings, 0 );
    itemBoxSizer7->Add(m_pSelBuild, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxButton* itemButton10 = new wxButton( itemPanel1, ID_EXTCMD_EDIT, _("Edit..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer7->Add(itemButton10, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer2->Add(itemBoxSizer11, 0, wxGROW|wxTOP, 5);

    wxStaticText* itemStaticText12 = new wxStaticText( itemPanel1, wxID_STATIC, _("Target:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer11->Add(itemStaticText12, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);

    wxString* m_pTargetListStrings = NULL;
    m_pTargetList = new wxChoice( itemPanel1, ID_EXTCMD_TARGET, wxDefaultPosition, wxDefaultSize, 0, m_pTargetListStrings, 0 );
    itemBoxSizer11->Add(m_pTargetList, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxBoxSizer* itemBoxSizer14 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer2->Add(itemBoxSizer14, 0, wxGROW|wxTOP, 5);

    m_pLabel2 = new wxStaticText( itemPanel1, wxID_STATIC, _("%STAGE% commands:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer14->Add(m_pLabel2, 1, wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);

    m_pOnlyChangedBox = new wxCheckBox( itemPanel1, ID_EXTCMD_ONLYCHANGED, _("Show only options with non-default values"), wxDefaultPosition, wxDefaultSize, 0 );
    m_pOnlyChangedBox->SetValue(true);
    itemBoxSizer14->Add(m_pOnlyChangedBox, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    m_pCommandList = (wxCommandListBox*) FindWindow(ID_EXTCMD_COMMANDS);
    wxASSERT( m_pCommandList != NULL );
    itemBoxSizer2->Add(m_pCommandList, 4, wxGROW|wxALL, 5);

////@end wxExtCmdOptionsPanel content construction

    m_stage = wxPBSS_INVALID;

    // init the command list
    wxFont fnt(*wxNORMAL_FONT);
    fnt.SetWeight( wxFONTWEIGHT_BOLD);
    m_pCommandList->SetFont(fnt);

    // init the wxbuild list
    InitWxBuildList();

    if (m_pSelBuild->GetCount() == 0)
        m_pSelBuild->Append(_T("No wxWidgets builds defined!"), (void*)1);

    m_pSelBuild->Select(0);
    SelectWxBuild(0);
}

void wxExtCmdOptionsPanel::InitWxBuildList()
{
    m_pSelBuild->Clear();
    for (size_t i=0; i<wxWidgetsBuildArray::s_arrWxBuilds.GetCount(); i++)
        m_pSelBuild->Append(wxWidgetsBuildArray::s_arrWxBuilds[i].GetUserFriendlyName(), (void*)2);
}

void wxExtCmdOptionsPanel::SetPackage(const wxPackage &p,
                                      wxPackageBuildSystemStage stage)
{
    // copy the given array
    m_pkg = p;
    m_stage = stage;

    // set labels
    m_pLabel1->SetLabel(wxPackageBuildSystemStage2String(m_stage) + wxT(" options:"));
    m_pLabel2->SetLabel(wxPackageBuildSystemStage2String(m_stage) + wxT(" commands:"));

    // add substituted options:
    m_pOptionsList->SetOptions(m_pkg.GetSubstBuildSysOptions());
    m_pOptionsList->SetCompilerFormats(m_pkg.GetCompilerSettings().GetSelFormat());
    m_pOptionsList->SetBuildSystemType(m_pkg.GetBuildSystemType());
    m_pOptionsList->SetStages(m_stage);
    RefreshOptions();       // necessary every time m_pOptionsList is modified!

    // add substituted commands:
    UpdateCommands();

    // _after_ updating commands (and thus m_cmd) we can add the list of targets
    m_pTargetList->Clear();
    for (size_t i=0; i<m_cmd.GetTargets().GetCount(); i++)
        m_pTargetList->Append(m_cmd.GetTargets().Item(i));

    // select the first target
    if (m_pTargetList->GetCount() > 0)
        m_pTargetList->Select(0);

    // update options related to the wx builds
    SelectWxBuild(0);
}

void wxExtCmdOptionsPanel::UpdateCommands()
{
    if (m_stage == wxPBSS_INVALID)
        return;

    wxPackageCondition cond;
    long flags = 0;
    if (m_pOnlyChangedBox->GetValue())
        flags |= wxPKGCMD_ONLY_CHANGED;
    else
    {
        // in any case, we don't want to show options related to other 
        // build systems / platforms, so, use a wxPackageCondition to filter
        // them out:
        cond.SetBuildSystems(m_pkg.GetBuildSystemType());
        cond.SetPlatforms(wxPackageCondition::GetCurrentPlatform());
        cond.SetStages(m_stage);
        cond.SetFormats(m_pkg.GetCompilerSettings().GetSelFormat());

        flags |= wxPKGCMD_ONLY_MATCHING_CONDITION;
    }

    // IMPORTANT: the values to substitute may have changed; force update:
    m_pkg.InvalidateCachedSubstHashMap();

    // cache the array of substituted commands:
    m_cmd = m_pkg.GetSubstCmdForStage(m_stage, flags, cond);

    // now filter out the invalid commands for current package:
    m_cmd = m_cmd.GetValidCommandsFor(m_pkg);

    // pass all string commands through the substitution filter
    m_pCommandList->Clear();
    for (size_t j=0, i=0; i<m_cmd.GetCount(); i++)
        m_pCommandList->Append(m_cmd[i]);
    m_pCommandList->RefreshAll();
}

bool wxExtCmdOptionsPanel::TransferDataFromWindow()
{
    // update package options
    m_pkg.SetBuildSysOptions(m_pOptionsList->GetOptions());

    return wxPanel::TransferDataFromWindow();
}

void wxExtCmdOptionsPanel::SelectWxBuild(size_t sel)
{
    m_selWxBuild = sel;

    if ((int)m_pSelBuild->GetClientData(m_selWxBuild) == 1)
        return;

    wxWidgetsBuildArray::s_arrWxBuilds[m_selWxBuild].
                UpdateOptions(m_pkg.GetBuildSysOptions());
    m_pOptionsList->SetOptions(m_pkg.GetSubstBuildSysOptions());
    RefreshOptions();   // m_pOptionsList has been modified
    UpdateCommands();
}





// ----------------------------------------------------------------------------
// wxExtCmdOptionsPanel - event handlers
// ----------------------------------------------------------------------------

void wxExtCmdOptionsPanel::OnOptionChanged(wxCommandEvent &WXUNUSED(ev))
{
    TransferDataFromWindow();

    // update commands
    UpdateCommands();
}

void wxExtCmdOptionsPanel::OnWxBuildChanged(wxCommandEvent &WXUNUSED(ev))
{
    int newsel = m_pSelBuild->GetSelection();
    if (newsel == m_selWxBuild)
        return;

    wxArrayString specialopt = wxWidgetsBuild::GetSpecialOptionNames();

    // save user changes to options
    TransferDataFromWindow();

    // warn the user we are going to change some specific options
    int reply = 
        wxSmartLogYesNoQuestion(
            wxT("changewxbuild"),
            wxT("You have changed the wxWidgets build to use. This requires to change the values of the following options:\n\n%s\n\ndiscarding any previous value. Proceed?"),
            wxArray2String(specialopt).c_str());

    if (reply == wxID_NO)
    {
        // reselect old item
        m_pSelBuild->Select(m_selWxBuild);
        return;
    }

    // change the option values:
    SelectWxBuild(newsel);
}

void wxExtCmdOptionsPanel::OnTargetChanged(wxCommandEvent &ev)
{
    wxPackageCommandArray &cmd = m_pkg.GetCmdForStage(m_stage);
    cmd.SetSelectedTarget(ev.GetSelection());
}

void wxExtCmdOptionsPanel::OnOnlyChanged(wxCommandEvent &WXUNUSED(ev))
{
    UpdateCommands();
}

void wxExtCmdOptionsPanel::OnReset(wxCommandEvent &WXUNUSED(ev))
{
    int reply = wxMessageBox(
        wxString::Format(_T("Are you sure you want to reset to the default values all the options for the '%s' package ?"),
                         m_pkg.GetName().c_str()), _T("Warning"), wxYES_NO|wxICON_QUESTION);

    if (reply == wxYES)
    {
        m_pkg.GetBuildSysOptions().ResetToDefaults();
        m_pOptionsList->SetOptions(m_pkg.GetSubstBuildSysOptions());
        RefreshOptions();   // m_pOptionsList has been modified

        TransferDataFromWindow();
        UpdateCommands();

        m_pSelBuild->Select(0);
        SelectWxBuild(0);
    }
}

void wxExtCmdOptionsPanel::OnEditWxBuild(wxCommandEvent &WXUNUSED(ev))
{
    wxPackageWXBuildPropDlg dlg(this);
    size_t n = m_pSelBuild->GetSelection();

    bool editExisting = (int)m_pSelBuild->GetClientData(n) != 1;
    if (editExisting)
        dlg.SetBuild(wxWidgetsBuildArray::s_arrWxBuilds[n]);

    if (dlg.ShowModal() == wxID_OK)
    {
        int toselect;
        if (editExisting)
        {
            wxWidgetsBuildArray::s_arrWxBuilds[n] = dlg.GetBuild();
            toselect = n;
        }
        else
        {
            wxWidgetsBuildArray::s_arrWxBuilds.Add(dlg.GetBuild());
            toselect = wxWidgetsBuildArray::s_arrWxBuilds.GetCount() - 1;
        }
        
        InitWxBuildList();
        m_pSelBuild->Select(toselect);
        SelectWxBuild(toselect);
    }
}

void wxExtCmdOptionsPanel::OnUpdateUI(wxUpdateUIEvent &)
{
    FindWindowById(ID_EXTCMD_EDIT, this)->Enable(m_pSelBuild->GetSelection() != wxNOT_FOUND);
}

