// $Id: gc_migration_dialogs.cpp,v 1.5 2018/01/03 21:32:59 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#include <cassert>

#include "gc_datastore.h"
#include "gc_data.h"
#include "gc_dialog.h"
#include "gc_errhandling.h"
#include "gc_layout.h"
#include "gc_migration_dialogs.h"
#include "gc_strings.h"
#include "gc_structures_err.h"

#include "wx/checkbox.h"
#include "wx/log.h"
#include "wx/sizer.h"
#include "wx/statbox.h"
#include "wx/statline.h"
#include "wx/textctrl.h"

//------------------------------------------------------------------------------------

gcMigrationRate::gcMigrationRate(size_t migrationId)
    :
    m_migrationId(migrationId)
{
}

gcMigrationRate::~gcMigrationRate()
{
}

wxString
gcMigrationRate::FromDataStore(GCDataStore & dataStore)
{
    gcMigration & migrationRef = dataStore.GetStructures().GetMigration(m_migrationId);
    return migrationRef.GetStartValueString();
}

void
gcMigrationRate::ToDataStore(GCDataStore & dataStore, wxString newText)
{
    gcMigration & migrationRef = dataStore.GetStructures().GetMigration(m_migrationId);
    double val;
    if (newText.ToDouble(&val))
    {
        if (val < 0)
        {
            throw gc_rate_too_small_error();
        }
        else
        {
            migrationRef.SetStartValue(val);
        }
    }
}

//------------------------------------------------------------------------------------

gcMigrationMethodChoice::gcMigrationMethodChoice(size_t migrationId, migration_method  type)
    :
    m_migrationId(migrationId),
    m_type(type),
    m_box(NULL)
{
}

gcMigrationMethodChoice::~gcMigrationMethodChoice()
{
}

void
gcMigrationMethodChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    m_box->SetLabel(ToWxString(m_type));
    UpdateDisplayInterim(dataStore);
}

void
gcMigrationMethodChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    // grab the migration
    gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);

    // set selection
    bool isThisOne = (migRef.GetMethod() == m_type );
    m_box->SetValue( isThisOne ? 1 : 0 );

    m_box->Enable();

}

void
gcMigrationMethodChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);
        migRef.SetMethod(m_type);
    }
}

void
gcMigrationMethodChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    UpdateDataInterim(dataStore);
}

wxWindow *
gcMigrationMethodChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcMigrationMethodChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcMigrationMethodChoice::GetRelevantId()
{
    return m_migrationId;
}

//------------------------------------------------------------------------------------

gcMigrationProfileChoice::gcMigrationProfileChoice(size_t migrationId, migration_profile type)
    :
    m_migrationId(migrationId),
    m_type(type),
    m_box(NULL)
{
}

gcMigrationProfileChoice::~gcMigrationProfileChoice()
{
}

void
gcMigrationProfileChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    m_box->SetLabel(ToWxString(m_type));
    UpdateDisplayInterim(dataStore);
}

void
gcMigrationProfileChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    // grab the migration
    gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);

    // set selection
    bool isThisOne = (migRef.GetProfile() == m_type );
    m_box->SetValue( isThisOne ? 1 : 0 );

    m_box->Enable();

}

void
gcMigrationProfileChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);
        migRef.SetProfile(m_type);
    }
}

void
gcMigrationProfileChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    UpdateDataInterim(dataStore);
}

wxWindow *
gcMigrationProfileChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcMigrationProfileChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcMigrationProfileChoice::GetRelevantId()
{
    return m_migrationId;
}

//------------------------------------------------------------------------------------

gcMigrationConstraintChoice::gcMigrationConstraintChoice(size_t migrationId, migration_constraint type)
    :
    m_migrationId(migrationId),
    m_type(type),
    m_box(NULL)
{
}

gcMigrationConstraintChoice::~gcMigrationConstraintChoice()
{
}

void
gcMigrationConstraintChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    m_box->SetLabel(ToWxString(m_type));
    UpdateDisplayInterim(dataStore);
}

void
gcMigrationConstraintChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    // grab the migration
    gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);

    // set selection
    bool isThisOne = (migRef.GetConstraint() == m_type );
    m_box->SetValue( isThisOne ? 1 : 0 );
    m_box->Enable();

}

void
gcMigrationConstraintChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        gcMigration& migRef = dataStore.GetStructures().GetMigration(m_migrationId);
        migRef.SetConstraint(m_type);
        if (m_type == migconstraint_SYMMETRIC)
        {
            size_t toId = migRef.GetToId();
            size_t fromId = migRef.GetFromId();
            gcMigration& symMigRef = dataStore.GetStructures().GetMigration(toId, fromId);
            symMigRef.SetConstraint(m_type);
            symMigRef.SetStartValue(migRef.GetStartValue());
        }
        else
        {
            size_t toId = migRef.GetToId();
            size_t fromId = migRef.GetFromId();
            gcMigration& symMigRef = dataStore.GetStructures().GetMigration(toId, fromId);
            if (symMigRef.GetConstraint() == migconstraint_SYMMETRIC)
            {
                symMigRef.SetConstraint(migconstraint_UNCONSTRAINED);
            }
        }
    }
}

void
gcMigrationConstraintChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    UpdateDataInterim(dataStore);
}

wxWindow *
gcMigrationConstraintChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcMigrationConstraintChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcMigrationConstraintChoice::GetRelevantId()
{
    return m_migrationId;
}

//------------------------------------------------------------------------------------

gcMigrationEditDialog::gcMigrationEditDialog(   wxWindow *      parent,
                                                GCDataStore &   dataStore,
                                                size_t          migrationId,
                                                wxString        toName,
                                                wxString        fromName,
                                                bool            forJustCreatedObj)
    :
    gcUpdatingDialog(   parent,
                        dataStore,
                        wxString::Format(gcstr::editMigration, toName.c_str(), fromName.c_str()),
                        forJustCreatedObj),
    m_migrationId(migrationId)
{
}

gcMigrationEditDialog::~gcMigrationEditDialog()
{
}

//------------------------------------------------------------------------------------

bool DoDialogEditMigration( wxWindow *      parent,
                            GCDataStore &   dataStore,
                            size_t          migrationId,
                            bool            forJustCreatedObj)
{
    wxLogVerbose("DoDialogEditMigration: migrationID: %i pop? %i",(int)migrationId, dataStore.GetStructures().IsPop(migrationId));  // JMDBG

    wxString fromName;
    if (dataStore.GetStructures().IsPop(dataStore.GetStructures().GetMigration(migrationId).GetFromId()))
    {
        fromName = dataStore.GetStructures().GetPop(
            dataStore.GetStructures().GetMigration(migrationId).GetFromId()).GetName();
    }
    else
    {
        fromName = dataStore.GetStructures().GetParent(
            dataStore.GetStructures().GetMigration(migrationId).GetFromId()).GetName();
    }

    wxString toName;
    if (dataStore.GetStructures().IsPop(dataStore.GetStructures().GetMigration(migrationId).GetToId()))
    {
        toName = dataStore.GetStructures().GetPop(
            dataStore.GetStructures().GetMigration(migrationId).GetToId()).GetName();
    }
    else
    {
        toName = dataStore.GetStructures().GetParent(
            dataStore.GetStructures().GetMigration(migrationId).GetToId()).GetName();
    }

    gcMigrationEditDialog dialog(parent,dataStore,migrationId, toName, fromName, forJustCreatedObj);


    // migration rate
    gcTextHelper * migrationRate  = new gcMigrationRate(migrationId);
    gcUpdatingComponent * rate    = new gcUpdatingTextCtrl( &dialog,
                                                            gcstr::migLabelRate,
                                                            migrationRate);

    // method choices
    std::vector<gcChoiceObject*> methodChoicesDT;
    wxArrayString migMethods = gcdata::migrationMethods();

    for(size_t i=0; i < migMethods.Count(); i++)
    {
        bool usestr = true;
        if(dataStore.GetStructures().GetDivergenceState())
        {
            // shut off FST option which will break divergence
            if (migMethods[i].Contains("FST"))
            {
                usestr = false;
            }
        }
        if (usestr)
        {
            wxString dataTypeString = migMethods[i];
            migration_method type = ProduceMigMethodOrBarf(dataTypeString);
            methodChoicesDT.push_back(new gcMigrationMethodChoice(migrationId,type));
        }
    }
    gcUpdatingComponent * migMethod = new gcUpdatingChoose(&dialog,
                                                           gcstr::migLabelMethod,
                                                           methodChoicesDT);

    // migration profile
    std::vector<gcChoiceObject*> profileChoicesDT;
    wxArrayString migProfiles = gcdata::migrationProfiles();

    for(size_t i=0; i < migProfiles.Count(); i++)
    {
        wxString dataTypeString = migProfiles[i];
        migration_profile type = ProduceMigProfileOrBarf(dataTypeString);
        profileChoicesDT.push_back(new gcMigrationProfileChoice(migrationId,type));
    }
    gcUpdatingComponent * migProfile = new gcUpdatingChoose(&dialog,
                                                            gcstr::migLabelProfile,
                                                            profileChoicesDT);

    // migration constraint
    std::vector<gcChoiceObject*> constraintChoicesDT;
    wxArrayString migConstraints = gcdata::migrationConstraints();

    for(size_t i=0; i < migConstraints.Count(); i++)
    {
        wxString dataTypeString = migConstraints[i];
        migration_constraint type = ProduceMigConstraintOrBarf(dataTypeString);
        constraintChoicesDT.push_back(new gcMigrationConstraintChoice(migrationId,type));
    }
    gcUpdatingComponent * migConstraint = new gcUpdatingChoose(&dialog,
                                                               gcstr::migLabelConstraint,
                                                               constraintChoicesDT);


    // build the dialog
    gcDialogCreator creator;
    wxBoxSizer * contentSizer   = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer * leftSizer      = new wxBoxSizer(wxVERTICAL);

    // populate left sizer
    leftSizer->Add(rate,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(migConstraint,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);


    creator.AddComponent(dialog,rate);
    creator.AddComponent(dialog,migConstraint);
    contentSizer->Add(leftSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);


    //////////////////////////////////////////////////////
    contentSizer->Add(new wxStaticLine(&dialog,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    //////////////////////////////////////////////////////
    wxBoxSizer * rightSizer = new wxBoxSizer(wxVERTICAL);

    // populate right sizer
    rightSizer->Add(migMethod,
                    0,
                    wxALL | wxALIGN_CENTER | wxEXPAND,
                    gclayout::borderSizeSmall);
    rightSizer->Add(migProfile,
                    0,
                    wxALL | wxALIGN_CENTER | wxEXPAND,
                    gclayout::borderSizeSmall);


    creator.AddComponent(dialog,migMethod);
    creator.AddComponent(dialog,migProfile);

    contentSizer->Add(rightSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    creator.PlaceContent(dialog,contentSizer);
    return dialog.Go();
}
//------------------------------------------------------------------------------------

bool
gcActor_MigrationEdit::OperateOn(wxWindow * parent, GCDataStore & dataStore)
{
    wxLogVerbose("gcActor_MigrationEdit::OperateOn m_migrationId: %i",(int)m_migrationId);  // JMDBG
    return DoDialogEditMigration(parent,dataStore,m_migrationId,false);
}

//____________________________________________________________________________________
