// This file is part of fityk program. Copyright (C) Marcin Wojdyr
// Licence: GNU General Public License version 2
// $Id: setdlg.cpp 296 2007-05-24 20:04:00Z wojdyr $

/// In this file:
///  Settings Dialog (SettingsDlg)

#include <wx/wxprec.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/statline.h>
#include <wx/notebook.h>
#include <wx/config.h>

#include "setdlg.h"
#include "../settings.h" 
#include "../ui.h"  //startup_commands_filename
#include "../logic.h"  
#include "gui.h"  //ftk

using namespace std;


enum {
    ID_SET_LDBUT           = 26400,
    ID_SET_XSBUT                  ,
    ID_SET_EXBUT                  ,
};


BEGIN_EVENT_TABLE(SettingsDlg, wxDialog)
    EVT_BUTTON (ID_SET_LDBUT, SettingsDlg::OnChangeButton)
    EVT_BUTTON (ID_SET_XSBUT, SettingsDlg::OnChangeButton)
    EVT_BUTTON (ID_SET_EXBUT, SettingsDlg::OnChangeButton)
    EVT_BUTTON (wxID_OK, SettingsDlg::OnOK)
END_EVENT_TABLE()

namespace {

RealNumberCtrl *addRealNumberCtrl(wxWindow *parent, wxString const& label,
                                  string const& value, wxSizer *sizer,
                                  wxString const& label_after=wxString())
{
    wxStaticText *st = new wxStaticText(parent, -1, label);
    RealNumberCtrl *ctrl = new RealNumberCtrl(parent, -1, value);
    wxBoxSizer *hsizer = new wxBoxSizer(wxHORIZONTAL);
    hsizer->Add(st, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    hsizer->Add(ctrl, 0, wxALL, 5);
    if (!label_after.IsEmpty()) {
        wxStaticText *sta = new wxStaticText(parent, -1, label_after);
        hsizer->Add(sta, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    }
    sizer->Add(hsizer, 0, wxEXPAND);
    return ctrl;
}

wxCheckBox *addCheckbox(wxWindow *parent, wxString const& label, 
                        bool value, wxSizer *sizer)
{
    wxCheckBox *ctrl = new wxCheckBox(parent, -1, label);
    ctrl->SetValue(value);
    if (sizer)
        sizer->Add(ctrl, 0, wxEXPAND|wxALL, 5);
    return ctrl;
}
                              
wxChoice *addEnumSetting(wxWindow *parent, wxString const& label, 
                         string const& option, wxSizer* sizer)
{
    wxBoxSizer *siz = new wxBoxSizer(wxHORIZONTAL);
    wxStaticText *st = new wxStaticText(parent, -1, label);
    siz->Add(st, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    wxChoice *ctrl = new wxChoice(parent, -1, 
                                  wxDefaultPosition, wxDefaultSize,
                                  stl2wxArrayString(
                                    ftk->get_settings()->expand_enum(option)));
    ctrl->SetStringSelection(s2wx(ftk->get_settings()->getp(option)));
    siz->Add(ctrl, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer->Add(siz, 0, wxEXPAND);
    return ctrl;
}

} //anonymous namespace
    
SettingsDlg::SettingsDlg(wxWindow* parent, const wxWindowID id)
    : wxDialog(parent, id, wxT("Settings"),
               wxDefaultPosition, wxDefaultSize, 
               wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) 
{
    Settings const* settings = ftk->get_settings();
    wxNotebook *nb = new wxNotebook(this, -1);
    wxPanel *page_general = new wxPanel(nb, -1);
    nb->AddPage(page_general, wxT("general"));
    wxPanel *page_peakfind = new wxPanel(nb, -1);
    nb->AddPage(page_peakfind, wxT("peak-finding"));
    wxNotebook *page_fitting = new wxNotebook(nb, -1);
    nb->AddPage(page_fitting, wxT("fitting"));
    wxPanel *page_dirs = new wxPanel(nb, -1);
    nb->AddPage(page_dirs, wxT("directories"));

    // page general
    wxBoxSizer *sizer_general = new wxBoxSizer(wxVERTICAL);

    sigma_ch = addEnumSetting(page_general, wxT("default std. dev. of data y:"),
                              "data-default-sigma", sizer_general);
    cut_func = addRealNumberCtrl(page_general, 
                                 wxT("f(x) can be assumed 0, if |f(x)|<"),
                                 settings->getp("cut-function-level"),
                                 sizer_general);

    verbosity_ch = addEnumSetting(page_general, 
                                  wxT("verbosity (in output pane)"), 
                                  "verbosity", sizer_general);
    exit_cb = addCheckbox(page_general, 
                          wxT("quit if error or warning was generated"),
                          settings->get_b("exit-on-warning"),
                          sizer_general);

    wxStaticText *seed_st = new wxStaticText(page_general, -1,
                        wxT("pseudo-random generator seed (0 = time-based)"));
    seed_sp = new SpinCtrl(page_general, -1, 
                         settings->get_i("pseudo-random-seed"), 0, 999999,
                         70);
    wxBoxSizer *sizer_general_seed = new wxBoxSizer(wxHORIZONTAL);
    sizer_general_seed->Add(seed_st, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_general_seed->Add(seed_sp, 0, wxTOP|wxBOTTOM|wxRIGHT, 5);
    sizer_general->Add(sizer_general_seed, 0, wxEXPAND);

    export_f_ch = addEnumSetting(page_general, wxT("style of formula export"), 
                                "formula-export-style", sizer_general);

    eps_rc = addRealNumberCtrl(page_general, 
                               wxT("epsilon for floating-point comparison"),
                               settings->getp("epsilon"),
                               sizer_general);
    add_persistence_note(page_general, sizer_general);
    page_general->SetSizerAndFit(sizer_general);

    // page peak-finding
    wxBoxSizer *sizer_pf = new wxBoxSizer(wxVERTICAL);

    height_correction = addRealNumberCtrl(page_peakfind, 
                           wxT("factor used to correct detected peak height"),
                           settings->getp("height-correction"),
                           sizer_pf);
    width_correction = addRealNumberCtrl(page_peakfind, 
                           wxT("factor used to correct detected peak width"),
                           settings->getp("width-correction"),
                           sizer_pf);

    cancel_poos = addCheckbox(page_peakfind, 
                          wxT("cancel peak guess, if the result is doubtful"),
                          settings->get_b("can-cancel-guess"), 
                          sizer_pf);
    //sizer_pf->Add(cancel_poos, 0, wxALL, 5);

    add_persistence_note(page_peakfind, sizer_pf);
    page_peakfind->SetSizerAndFit(sizer_pf);

    // page fitting 
    wxPanel *page_fit_common = new wxPanel(page_fitting, -1);
    page_fitting->AddPage(page_fit_common, wxT("common"));
    wxPanel *page_fit_LM = new wxPanel(page_fitting, -1);
    page_fitting->AddPage(page_fit_LM, wxT("Lev-Mar"));
    wxPanel *page_fit_NM = new wxPanel(page_fitting, -1);
    page_fitting->AddPage(page_fit_NM, wxT("Nelder-Mead"));
    wxPanel *page_fit_GA = new wxPanel(page_fitting, -1);
    page_fitting->AddPage(page_fit_GA, wxT("GA"));

    // sub-page common
    wxBoxSizer *sizer_fcmn = new wxBoxSizer(wxVERTICAL);
    wxStaticBoxSizer *sizer_fcstop = new wxStaticBoxSizer(wxHORIZONTAL,
                                page_fit_common, wxT("termination criteria"));
    wxStaticText *mwssre_st = new wxStaticText(page_fit_common, -1,
                                               wxT("max. WSSR evaluations"));
    mwssre_sp = new SpinCtrl(page_fit_common, -1, 
                       settings->get_i("max-wssr-evaluations"), 0, 999999,
                       70);
    sizer_fcstop->Add(mwssre_st, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_fcstop->Add(mwssre_sp, 0, wxALL, 5);
    sizer_fcmn->Add(sizer_fcstop, 0, wxEXPAND|wxALL, 5);
    domain_p = addRealNumberCtrl(page_fit_common, 
                                 wxT("default domain of variable is +/-"), 
                                 settings->getp("variable-domain-percent"),
                                 sizer_fcmn,
                                 wxT("%"));

    bool autop = (settings->getp("autoplot") == "on-fit-iteration");
    autoplot_cb = addCheckbox(page_fit_common,  
                              wxT("refresh plot after each iteration"),
                              autop, sizer_fcmn);

    add_persistence_note(page_fit_common, sizer_fcmn);
    page_fit_common->SetSizerAndFit(sizer_fcmn);

    // sub-page Lev-Mar
    wxBoxSizer *sizer_flm = new wxBoxSizer(wxVERTICAL);
    wxStaticBoxSizer *sizer_flmlambda = new wxStaticBoxSizer(wxVERTICAL,
                                page_fit_LM, wxT("lambda parameter"));
    lm_lambda_ini = addRealNumberCtrl(page_fit_LM, wxT("initial value"), 
                      settings->getp("lm-lambda-start"), sizer_flmlambda);
    lm_lambda_up = addRealNumberCtrl(page_fit_LM, wxT("increasing factor"), 
                 settings->getp("lm-lambda-up-factor"), sizer_flmlambda);
    lm_lambda_down = addRealNumberCtrl(page_fit_LM, wxT("decreasing factor"), 
                settings->getp("lm-lambda-down-factor"), sizer_flmlambda);
    sizer_flm->Add(sizer_flmlambda, 0, wxEXPAND|wxALL, 5);
    wxStaticBoxSizer *sizer_flmstop = new wxStaticBoxSizer(wxVERTICAL,
                                page_fit_LM, wxT("termination criteria"));
    lm_stop = addRealNumberCtrl(page_fit_LM, wxT("WSSR relative change <"), 
                     settings->getp("lm-stop-rel-change"), sizer_flmstop);
    lm_max_lambda = addRealNumberCtrl(page_fit_LM, wxT("max. value of lambda"),
                     settings->getp("lm-max-lambda"), sizer_flmstop);
    sizer_flm->Add(sizer_flmstop, 0, wxEXPAND|wxALL, 5);
    add_persistence_note(page_fit_LM, sizer_flm);
    page_fit_LM->SetSizerAndFit(sizer_flm);

    
    // sub-page N-M
    wxBoxSizer *sizer_fnm = new wxBoxSizer(wxVERTICAL);

    wxStaticBoxSizer *sizer_fnmini = new wxStaticBoxSizer(wxVERTICAL,
                              page_fit_NM, wxT("simplex initialization"));

    nm_move_all = addCheckbox(page_fit_NM, 
                           wxT("randomize all vertices (otherwise on is left)"),
                           settings->get_b("nm-move-all"), sizer_fnmini);
    nm_distrib = addEnumSetting(page_fit_NM, wxT("distribution type"), 
                                "nm-distribution", sizer_fnmini);
    nm_move_factor = addRealNumberCtrl(page_fit_NM, 
                         wxT("factor by which domain is expanded"), 
                         settings->getp("nm-move-factor"), sizer_fnmini);
    sizer_fnm->Add(sizer_fnmini, 0, wxEXPAND|wxALL, 5);

    wxStaticBoxSizer *sizer_fnmstop = new wxStaticBoxSizer(wxVERTICAL,
                                page_fit_NM, wxT("termination criteria"));
    nm_convergence = addRealNumberCtrl(page_fit_NM, 
                         wxT("worst and best relative difference"), 
                         settings->getp("nm-convergence"), sizer_fnmstop);
    sizer_fnm->Add(sizer_fnmstop, 0, wxEXPAND|wxALL, 5);
    add_persistence_note(page_fit_NM, sizer_fnm);
    page_fit_NM->SetSizerAndFit(sizer_fnm);
    
    // sub-page GA
    // TODO

    // page directories
    wxBoxSizer *sizer_dirs = new wxBoxSizer(wxVERTICAL);
    wxStaticBoxSizer *sizer_dirs_data = new wxStaticBoxSizer(wxHORIZONTAL,
                     page_dirs, wxT("default directory for load data dialog"));
    dir_ld_tc = new wxTextCtrl(page_dirs, -1, 
                           wxConfig::Get()->Read(wxT("/loadDataDir"), wxT("")));
    sizer_dirs_data->Add(dir_ld_tc, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs_data->Add(new wxButton(page_dirs, ID_SET_LDBUT, wxT("Change")),
                         0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs->Add(sizer_dirs_data, 0, wxEXPAND|wxALL, 5);

    wxStaticBoxSizer *sizer_dirs_script = new wxStaticBoxSizer(wxHORIZONTAL,
                page_dirs, wxT("default directory for execute script dialog"));
    dir_xs_tc = new wxTextCtrl(page_dirs, -1, 
                         wxConfig::Get()->Read(wxT("/execScriptDir"), wxT("")));
    sizer_dirs_script->Add(dir_xs_tc, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs_script->Add(new wxButton(page_dirs, ID_SET_XSBUT, wxT("Change")),
                           0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs->Add(sizer_dirs_script, 0, wxEXPAND|wxALL, 5);

    wxStaticBoxSizer *sizer_dirs_export = new wxStaticBoxSizer(wxHORIZONTAL,
                page_dirs, wxT("default directory for save/export dialogs"));
    dir_ex_tc = new wxTextCtrl(page_dirs, -1, 
                         wxConfig::Get()->Read(wxT("/exportDir"), wxT("")));
    sizer_dirs_export->Add(dir_ex_tc, 1, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs_export->Add(new wxButton(page_dirs, ID_SET_EXBUT, wxT("Change")),
                           0, wxALL|wxALIGN_CENTER_VERTICAL, 5);
    sizer_dirs->Add(sizer_dirs_export, 0, wxEXPAND|wxALL, 5);

    sizer_dirs->Add(new wxStaticText(page_dirs, -1, 
                 wxT("Directories given above are used when the dialogs\n")
                 wxT("are displayed first time after launching the program.")),
                 0, wxALL|wxEXPAND, 5);
    page_dirs->SetSizerAndFit(sizer_dirs);

    //finish layout
    wxBoxSizer *top_sizer = new wxBoxSizer (wxVERTICAL);
    top_sizer->Add(nb, 1, wxALL|wxEXPAND, 10);
    top_sizer->Add (new wxStaticLine(this, -1), 0, wxEXPAND|wxLEFT|wxRIGHT, 5);
    top_sizer->Add (CreateButtonSizer (wxOK|wxCANCEL), 
                    0, wxALL|wxALIGN_CENTER, 5);
    SetSizerAndFit(top_sizer);
}

void SettingsDlg::add_persistence_note(wxWindow *parent, wxSizer *sizer)
{
    wxStaticBoxSizer *persistence = new wxStaticBoxSizer(wxHORIZONTAL,
                                           parent, wxT("persistance note"));
    persistence->Add(new wxStaticText(parent, -1,
                       wxT("To have values above remained after restart, ")
                       wxT("put proper\ncommands into init file:")
                       + get_user_conffile(startup_commands_filename)),
                     0, wxALL|wxALIGN_CENTER, 5);
    sizer->AddStretchSpacer();
    sizer->Add(persistence, 0, wxEXPAND|wxALL, 5);
}

void SettingsDlg::OnChangeButton(wxCommandEvent& event)
{
    wxTextCtrl *tc = 0;
    if (event.GetId() == ID_SET_LDBUT)
        tc = dir_ld_tc;
    else if (event.GetId() == ID_SET_XSBUT)
        tc = dir_xs_tc;
    else if (event.GetId() == ID_SET_EXBUT)
        tc = dir_ex_tc;
    wxString dir = wxDirSelector(wxT("Choose a folder"), tc->GetValue());
    if (!dir.empty())
        tc->SetValue(dir);
}

SettingsDlg::pair_vec SettingsDlg::get_changed_items()
{
    pair_vec result;
    map<string, string> m;
    m["data-default-sigma"] = wx2s(sigma_ch->GetStringSelection());
    m["cut-function-level"] = wx2s(cut_func->GetValue());
    m["verbosity"] = wx2s(verbosity_ch->GetStringSelection());
    m["exit-on-warning"] = exit_cb->GetValue() ? "1" : "0";
    m["pseudo-random-seed"] = S(seed_sp->GetValue());
    m["formula-export-style"] = wx2s(export_f_ch->GetStringSelection());
    m["epsilon"] = wx2s(eps_rc->GetValue());
    m["height-correction"] = wx2s(height_correction->GetValue());
    m["width-correction"] = wx2s(width_correction->GetValue());
    m["can-cancel-guess"] = cancel_poos->GetValue() ? "1" : "0";
    m["max-wssr-evaluations"] = S(mwssre_sp->GetValue());
    m["variable-domain-percent"] = wx2s(domain_p->GetValue());
    m["autoplot"] = autoplot_cb->GetValue() ? "on-fit-iteration" 
                                            : "on-plot-change";
    m["lm-lambda-start"] = wx2s(lm_lambda_ini->GetValue());
    m["lm-lambda-up-factor"] = wx2s(lm_lambda_up->GetValue());
    m["lm-lambda-down-factor"] = wx2s(lm_lambda_down->GetValue());
    m["lm-stop-rel-change"] = wx2s(lm_stop->GetValue());
    m["lm-max-lambda"] = wx2s(lm_max_lambda->GetValue());
    m["nm-move-all"] = nm_move_all->GetValue() ? "1" : "0";
    m["nm-distribution"] = wx2s(nm_distrib->GetStringSelection());
    m["nm-move-factor"] = wx2s(nm_move_factor->GetValue());
    m["nm-convergence"] = wx2s(nm_convergence->GetValue());
    vector<string> kk = ftk->get_settings()->expanp();
    for (vector<string>::const_iterator i = kk.begin(); i != kk.end(); ++i)
        if (m.count(*i) && m[*i] != ftk->get_settings()->getp(*i))
            result.push_back(make_pair(*i, m[*i]));
    return result;
}

void SettingsDlg::OnOK(wxCommandEvent&)
{
    vector<pair<string, string> > p = get_changed_items();
    if (!p.empty()) {
        vector<string> eqs;
        for (vector<pair<string, string> >::const_iterator i = p.begin();
                i != p.end(); ++i)
            eqs.push_back(i->first + "=" + i->second);
        ftk->exec("set " + join_vector(eqs, ", "));
    }
    wxConfig::Get()->Write(wxT("/loadDataDir"), dir_ld_tc->GetValue());
    wxConfig::Get()->Write(wxT("/execScriptDir"), dir_xs_tc->GetValue());
    wxConfig::Get()->Write(wxT("/exportDir"), dir_ex_tc->GetValue());
    close_it(this, wxID_OK);
}




syntax highlighted by Code2HTML, v. 0.9.1