// -*- c-basic-offset: 4 -*-

/** @file CPDetectorDialog.cpp
 *
 *  @brief implementation of CPDetectorDialog class, 
 *         which allows changing options of CP detectors
 *
 *  @author Thomas Modes
 *
 */

/*  This is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this software. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#ifdef _WIN32
#include "wx/msw/wrapwin.h"
 // Mingw define still DIFFERENCE, which conflicts with vigra, so disable it
#undef DIFFERENCE
#endif
#include "hugin/CPDetectorDialog.h"
#include "hugin_config.h"
#include "base_wx/huginConfig.h"
#include "base_wx/wxutils.h"
#include "hugin/config_defaults.h"
#include "hugin/huginApp.h"

#if defined MAC_SELF_CONTAINED_BUNDLE 
  #include "base_wx/platform.h"
  #include <wx/dir.h>
  #include <CoreFoundation/CFBundle.h>
#endif

// dialog for showing settings of one autopano setting
CPDetectorDialog::CPDetectorDialog(wxWindow* parent)
{
    wxXmlResource::Get()->LoadDialog(this, parent, "cpdetector_dialog");

    //restore frame position and size
    hugin_utils::RestoreFramePosition(this,"CPDetectorDialog");

    m_edit_desc = XRCCTRL(*this, "prefs_cpdetector_desc", wxTextCtrl);
    m_edit_prog = XRCCTRL(*this, "prefs_cpdetector_program", wxTextCtrl);
    m_edit_args = XRCCTRL(*this, "prefs_cpdetector_args", wxTextCtrl);
    m_label_args_cleanup = XRCCTRL(*this, "prefs_cpdetector_args_label_cleanup", wxStaticText);
    m_edit_args_cleanup = XRCCTRL(*this, "prefs_cpdetector_args_cleanup", wxTextCtrl);
    m_edit_prog_descriptor = XRCCTRL(*this, "prefs_cpdetector_program_descriptor", wxTextCtrl);
    m_edit_args_descriptor = XRCCTRL(*this, "prefs_cpdetector_args_descriptor", wxTextCtrl);
    m_edit_prog_matcher = XRCCTRL(*this, "prefs_cpdetector_program_matcher", wxTextCtrl);
    m_edit_args_matcher = XRCCTRL(*this, "prefs_cpdetector_args_matcher", wxTextCtrl);
    m_edit_prog_stack = XRCCTRL(*this, "prefs_cpdetector_program_stack", wxTextCtrl);
    m_edit_args_stack = XRCCTRL(*this, "prefs_cpdetector_args_stack", wxTextCtrl);
    m_check_option = XRCCTRL(*this, "prefs_cpdetector_option", wxCheckBox);
    m_cpdetector_type = XRCCTRL(*this, "prefs_cpdetector_type", wxChoice);
    m_choice_step = XRCCTRL(*this, "choicebook_steps", wxChoicebook);
    // enable auto completion
    m_edit_prog->AutoCompleteFileNames();
    m_edit_prog_descriptor->AutoCompleteFileNames();
    m_edit_prog_matcher->AutoCompleteFileNames();
    m_edit_prog_stack->AutoCompleteFileNames();
    m_cpdetector_type->SetSelection(1);
    ChangeType();
    // bind events
    m_cpdetector_type->Bind(wxEVT_CHOICE, &CPDetectorDialog::OnTypeChange, this);
    m_choice_step->Bind(wxEVT_CHOICEBOOK_PAGE_CHANGING, &CPDetectorDialog::OnStepChanging, this);
    Bind(wxEVT_BUTTON, &CPDetectorDialog::OnSelectPath, this, XRCID("prefs_cpdetector_program_select"));
    Bind(wxEVT_BUTTON, &CPDetectorDialog::OnSelectPathDescriptor, this, XRCID("prefs_cpdetector_program_descriptor_select"));
    Bind(wxEVT_BUTTON, &CPDetectorDialog::OnSelectPathMatcher, this, XRCID("prefs_cpdetector_program_matcher_select"));
    Bind(wxEVT_BUTTON, &CPDetectorDialog::OnSelectPathStack, this, XRCID("prefs_cpdetector_program_stack_select"));
    Bind(wxEVT_BUTTON, &CPDetectorDialog::OnOk, this, wxID_OK);
};

CPDetectorDialog::~CPDetectorDialog()
{
    hugin_utils::StoreFramePosition(this,"CPDetectorDialog");
};

void CPDetectorDialog::OnOk(wxCommandEvent & e)
{
#ifdef __WXMAC__
    if(m_cpdetector_type->GetSelection()==0)
    {
        hugin_utils::HuginMessageBox(_("Autopano from http://autopano.kolor.com is not available for OS X"), 
                     _("Hugin"),wxOK|wxICON_EXCLAMATION, this); 
        m_cpdetector_type->SetSelection(1);
    };
#endif
    bool valid=true;
    valid=valid && (m_edit_desc->GetValue().Trim().Len()>0);
    if(m_choice_step->GetSelection()==0)
    {
        //detector with one step
        valid=valid && (m_edit_prog->GetValue().Trim().Len()>0);
        valid=valid && (m_edit_args->GetValue().Trim().Len()>0);
    }
    else
    {
        //detector with two steps
        valid=valid && (m_edit_prog_descriptor->GetValue().Trim().Len()>0);
        valid=valid && (m_edit_prog_matcher->GetValue().Trim().Len()>0);
        valid=valid && (m_edit_args_descriptor->GetValue().Trim().Len()>0);
        valid=valid && (m_edit_args_matcher->GetValue().Trim().Len()>0);
    };
    if(CPDetectorSetting::ContainsStacks((CPDetectorType)(m_cpdetector_type->GetSelection())))
        if(m_edit_prog_stack->GetValue().Trim().Len()>0)
            valid=valid && (m_edit_args_stack->GetValue().Trim().Len()>0);
    if (valid)
        this->EndModal(wxOK);
    else
        hugin_utils::HuginMessageBox(_("At least one input field is empty.\nPlease check your inputs."),
            _("Hugin"), wxOK | wxICON_ERROR, this);
};

void CPDetectorDialog::UpdateFields(CPDetectorConfig* cpdet_config,int index)
{
    m_edit_desc->SetValue(cpdet_config->settings[index].GetCPDetectorDesc());
    //program names and arguments
    if(cpdet_config->settings[index].IsTwoStepDetector())
    {
        m_choice_step->SetSelection(1);
        m_edit_prog_descriptor->SetValue(cpdet_config->settings[index].GetProg());
        m_edit_prog_matcher->SetValue(cpdet_config->settings[index].GetProgMatcher());
        m_edit_args_descriptor->SetValue(cpdet_config->settings[index].GetArgs());
        m_edit_args_matcher->SetValue(cpdet_config->settings[index].GetArgsMatcher());
    }
    else
    {
        m_choice_step->SetSelection(0);
        m_edit_prog->SetValue(cpdet_config->settings[index].GetProg());
        m_edit_args->SetValue(cpdet_config->settings[index].GetArgs());
        if(cpdet_config->settings[index].IsCleanupPossible())
        {
            m_edit_args_cleanup->SetValue(cpdet_config->settings[index].GetArgsCleanup());
        };
    };
    if(cpdet_config->settings[index].ContainsStacks())
    {
        m_edit_prog_stack->SetValue(cpdet_config->settings[index].GetProgStack());
        m_edit_args_stack->SetValue(cpdet_config->settings[index].GetArgsStack());
    };
    m_cpdetector_type->SetSelection(cpdet_config->settings[index].GetType());
    m_check_option->SetValue(cpdet_config->settings[index].GetOption());
    ChangeType();
};

void CPDetectorDialog::UpdateSettings(CPDetectorConfig* cpdet_config,int index)
{
    cpdet_config->settings[index].SetCPDetectorDesc(m_edit_desc->GetValue().Trim());
    cpdet_config->settings[index].SetType((CPDetectorType)m_cpdetector_type->GetSelection());
    if(m_choice_step->GetSelection()==0)
    {
        cpdet_config->settings[index].SetProg(m_edit_prog->GetValue().Trim());
        cpdet_config->settings[index].SetArgs(m_edit_args->GetValue().Trim());
        if(cpdet_config->settings[index].IsCleanupPossible())
        {
            cpdet_config->settings[index].SetArgsCleanup(m_edit_args_cleanup->GetValue().Trim());
        }
        else
        {
            cpdet_config->settings[index].SetArgsCleanup(wxEmptyString);
        };
    }
    else
    {
        cpdet_config->settings[index].SetProg(m_edit_prog_descriptor->GetValue().Trim());
        cpdet_config->settings[index].SetArgs(m_edit_args_descriptor->GetValue().Trim());
        cpdet_config->settings[index].SetProgMatcher(m_edit_prog_matcher->GetValue().Trim());
        cpdet_config->settings[index].SetArgsMatcher(m_edit_args_matcher->GetValue().Trim());
    };
    if(cpdet_config->settings[index].ContainsStacks())
    {
        cpdet_config->settings[index].SetProgStack(m_edit_prog_stack->GetValue().Trim());
        cpdet_config->settings[index].SetArgsStack(m_edit_args_stack->GetValue().Trim());
    }
    else
    {
        cpdet_config->settings[index].SetProgStack(wxEmptyString);
        cpdet_config->settings[index].SetArgsStack(wxEmptyString);
    }
    cpdet_config->settings[index].SetOption(m_check_option->IsChecked());
};

void CPDetectorDialog::OnTypeChange(wxCommandEvent &e)
{
    ChangeType();
};

void CPDetectorDialog::ChangeType()
{
    CPDetectorType type=(CPDetectorType)m_cpdetector_type->GetSelection();
    if(type==CPDetector_AutoPano)
    {
        m_choice_step->SetSelection(0);
        twoStepAllowed=false;
    }
    else
    {
        twoStepAllowed=true;
    }
    XRCCTRL(*this,"panel_stack",wxPanel)->Enable(CPDetectorSetting::ContainsStacks(type));
    switch(type)
    {
        case CPDetector_AutoPanoSiftMultiRow:
        case CPDetector_AutoPanoSiftMultiRowStack:
            m_check_option->SetLabel(_("Try to connect all overlapping images."));
            m_check_option->Enable(true);
            m_check_option->Show(true);
            XRCCTRL(*this, "prefs_cpdetector_no_option",wxStaticText)->Show(false);
            break;
        case CPDetector_AutoPanoSiftPreAlign:
            m_check_option->SetLabel(_("Only work on image pairs without control points."));
            m_check_option->Enable(true);
            m_check_option->Show(true);
            XRCCTRL(*this, "prefs_cpdetector_no_option",wxStaticText)->Show(false);
            break;
        default:
            XRCCTRL(*this, "prefs_cpdetector_no_option",wxStaticText)->Show(true);
            m_check_option->Enable(false);
            m_check_option->Show(false);
            break;
    };
    m_check_option->GetParent()->Layout();
    bool cleanup_possible=CPDetectorSetting::IsCleanupPossible(type);
    m_label_args_cleanup->Enable(cleanup_possible);
    m_label_args_cleanup->Show(cleanup_possible);
    m_edit_args_cleanup->Enable(cleanup_possible);
    m_edit_args_cleanup->Show(cleanup_possible);
    m_label_args_cleanup->GetParent()->Layout();
    Layout();
};


bool CPDetectorDialog::ShowFileDialog(wxString & prog)
{
    wxFileName executable(prog);
#ifdef MAC_SELF_CONTAINED_BUNDLE
    wxString autopanoPath = MacGetPathToUserAppSupportAutoPanoFolder();
#endif
    wxFileDialog dlg(this,_("Select control point detector program"), 
#ifdef MAC_SELF_CONTAINED_BUNDLE
            autopanoPath,
#else
            executable.GetPath(),
#endif
            executable.GetFullName(),
#ifdef __WXMSW__
            _("Executables (*.exe,*.vbs,*.cmd, *.bat)|*.exe;*.vbs;*.cmd;*.bat"),
#else
            wxEmptyString,
#endif
            wxFD_OPEN, wxDefaultPosition);
    if (dlg.ShowModal() == wxID_OK)
    {
        prog=dlg.GetPath();
        return true;
    }
    else
        return false;
};

void CPDetectorDialog::OnSelectPath(wxCommandEvent &e)
{
    wxString prog=m_edit_prog->GetValue();
    if (ShowFileDialog(prog))
        m_edit_prog->SetValue(prog);
};

void CPDetectorDialog::OnSelectPathDescriptor(wxCommandEvent &e)
{
    wxString prog=m_edit_prog_descriptor->GetValue();
    if (ShowFileDialog(prog))
        m_edit_prog_descriptor->SetValue(prog);
};

void CPDetectorDialog::OnSelectPathMatcher(wxCommandEvent &e)
{
    wxString prog=m_edit_prog_matcher->GetValue();
    if (ShowFileDialog(prog))
        m_edit_prog_matcher->SetValue(prog);
};

void CPDetectorDialog::OnSelectPathStack(wxCommandEvent &e)
{
    wxString prog=m_edit_prog_stack->GetValue();
    if (ShowFileDialog(prog))
        m_edit_prog_stack->SetValue(prog);
};

void CPDetectorDialog::OnStepChanging(wxChoicebookEvent &e)
{
    if(!twoStepAllowed && e.GetOldSelection()==0)
    {
        wxBell();
        e.Veto();
    };
};
